<!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>[211316] trunk/Source/JavaScriptCore</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/211316">211316</a></dd>
<dt>Author</dt> <dd>sbarati@apple.com</dd>
<dt>Date</dt> <dd>2017-01-27 17:04:06 -0800 (Fri, 27 Jan 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Make the CLI for the sampling profiler better for inlined call site indices
https://bugs.webkit.org/show_bug.cgi?id=167482

Reviewed by Mark Lam.

This patches changes the command line interface for the sampling
profiler to also dump the machine frame that the semantic code
origin is in if the semantic code origin is inlined. This helps
when doing performance work because it's helpful to know the
context that an inlined frame is in. Before, we used to just
say it was in the baseline JIT if it didn't have its own optimized
compile. Now, we can tell that its inlined into a DFG or FTL frame.

* inspector/agents/InspectorScriptProfilerAgent.cpp:
(Inspector::buildSamples):
* runtime/Options.h:
* runtime/SamplingProfiler.cpp:
(JSC::SamplingProfiler::processUnverifiedStackTraces):
(JSC::SamplingProfiler::reportTopFunctions):
(JSC::SamplingProfiler::reportTopBytecodes):
* runtime/SamplingProfiler.h:
(JSC::SamplingProfiler::StackFrame::CodeLocation::hasCodeBlockHash):
(JSC::SamplingProfiler::StackFrame::CodeLocation::hasBytecodeIndex):
(JSC::SamplingProfiler::StackFrame::CodeLocation::hasExpressionInfo):
(JSC::SamplingProfiler::StackFrame::hasExpressionInfo):
(JSC::SamplingProfiler::StackFrame::lineNumber):
(JSC::SamplingProfiler::StackFrame::columnNumber):
(JSC::SamplingProfiler::StackFrame::hasBytecodeIndex): Deleted.
(JSC::SamplingProfiler::StackFrame::hasCodeBlockHash): Deleted.</pre>

<h3>Modified Paths</h3>
<ul>
<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="#trunkSourceJavaScriptCoreruntimeOptionsh">trunk/Source/JavaScriptCore/runtime/Options.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeSamplingProfilercpp">trunk/Source/JavaScriptCore/runtime/SamplingProfiler.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeSamplingProfilerh">trunk/Source/JavaScriptCore/runtime/SamplingProfiler.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (211315 => 211316)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2017-01-28 00:55:39 UTC (rev 211315)
+++ trunk/Source/JavaScriptCore/ChangeLog        2017-01-28 01:04:06 UTC (rev 211316)
</span><span class="lines">@@ -1,3 +1,35 @@
</span><ins>+2017-01-27  Saam Barati  &lt;sbarati@apple.com&gt;
+
+        Make the CLI for the sampling profiler better for inlined call site indices
+        https://bugs.webkit.org/show_bug.cgi?id=167482
+
+        Reviewed by Mark Lam.
+
+        This patches changes the command line interface for the sampling
+        profiler to also dump the machine frame that the semantic code
+        origin is in if the semantic code origin is inlined. This helps
+        when doing performance work because it's helpful to know the
+        context that an inlined frame is in. Before, we used to just
+        say it was in the baseline JIT if it didn't have its own optimized
+        compile. Now, we can tell that its inlined into a DFG or FTL frame.
+
+        * inspector/agents/InspectorScriptProfilerAgent.cpp:
+        (Inspector::buildSamples):
+        * runtime/Options.h:
+        * runtime/SamplingProfiler.cpp:
+        (JSC::SamplingProfiler::processUnverifiedStackTraces):
+        (JSC::SamplingProfiler::reportTopFunctions):
+        (JSC::SamplingProfiler::reportTopBytecodes):
+        * runtime/SamplingProfiler.h:
+        (JSC::SamplingProfiler::StackFrame::CodeLocation::hasCodeBlockHash):
+        (JSC::SamplingProfiler::StackFrame::CodeLocation::hasBytecodeIndex):
+        (JSC::SamplingProfiler::StackFrame::CodeLocation::hasExpressionInfo):
+        (JSC::SamplingProfiler::StackFrame::hasExpressionInfo):
+        (JSC::SamplingProfiler::StackFrame::lineNumber):
+        (JSC::SamplingProfiler::StackFrame::columnNumber):
+        (JSC::SamplingProfiler::StackFrame::hasBytecodeIndex): Deleted.
+        (JSC::SamplingProfiler::StackFrame::hasCodeBlockHash): Deleted.
+
</ins><span class="cx"> 2017-01-27  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Extend create_hash_table to specify Intrinsic
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinspectoragentsInspectorScriptProfilerAgentcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.cpp (211315 => 211316)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.cpp        2017-01-28 00:55:39 UTC (rev 211315)
+++ trunk/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.cpp        2017-01-28 01:04:06 UTC (rev 211316)
</span><span class="lines">@@ -180,8 +180,8 @@
</span><span class="cx"> 
</span><span class="cx">             if (stackFrame.hasExpressionInfo()) {
</span><span class="cx">                 Ref&lt;Protocol::ScriptProfiler::ExpressionLocation&gt; expressionLocation = Protocol::ScriptProfiler::ExpressionLocation::create()
</span><del>-                    .setLine(stackFrame.lineNumber)
-                    .setColumn(stackFrame.columnNumber)
</del><ins>+                    .setLine(stackFrame.lineNumber())
+                    .setColumn(stackFrame.columnNumber())
</ins><span class="cx">                     .release();
</span><span class="cx">                 frame-&gt;setExpressionLocation(WTFMove(expressionLocation));
</span><span class="cx">             }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeOptionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Options.h (211315 => 211316)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Options.h        2017-01-28 00:55:39 UTC (rev 211315)
+++ trunk/Source/JavaScriptCore/runtime/Options.h        2017-01-28 01:04:06 UTC (rev 211316)
</span><span class="lines">@@ -361,6 +361,8 @@
</span><span class="cx">     v(bool, useSamplingProfiler, false, Normal, nullptr) \
</span><span class="cx">     v(unsigned, sampleInterval, 1000, Normal, &quot;Time between stack traces in microseconds.&quot;) \
</span><span class="cx">     v(bool, collectSamplingProfilerDataForJSCShell, false, Normal, &quot;This corresponds to the JSC shell's --sample option.&quot;) \
</span><ins>+    v(unsigned, samplingProfilerTopFunctionsCount, 12, Normal, &quot;Number of top functions to report when using the command line interface.&quot;) \
+    v(unsigned, samplingProfilerTopBytecodesCount, 40, Normal, &quot;Number of top bytecodes to report when using the command line interface.&quot;) \
</ins><span class="cx">     v(optionString, samplingProfilerPath, nullptr, Normal, &quot;The path to the directory to write sampiling profiler output to. This probably will not work with WK2 unless the path is in the whitelist.&quot;) \
</span><span class="cx">     \
</span><span class="cx">     v(bool, alwaysGeneratePCToCodeOriginMap, false, Normal, &quot;This will make sure we always generate a PCToCodeOriginMap for JITed code.&quot;) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeSamplingProfilercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/SamplingProfiler.cpp (211315 => 211316)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/SamplingProfiler.cpp        2017-01-28 00:55:39 UTC (rev 211315)
+++ trunk/Source/JavaScriptCore/runtime/SamplingProfiler.cpp        2017-01-28 01:04:06 UTC (rev 211316)
</span><span class="lines">@@ -44,6 +44,7 @@
</span><span class="cx"> #include &quot;NativeExecutable.h&quot;
</span><span class="cx"> #include &quot;PCToCodeOriginMap.h&quot;
</span><span class="cx"> #include &quot;SlotVisitor.h&quot;
</span><ins>+#include &quot;StrongInlines.h&quot;
</ins><span class="cx"> #include &quot;VM.h&quot;
</span><span class="cx"> #include &lt;wtf/HashSet.h&gt;
</span><span class="cx"> #include &lt;wtf/RandomNumber.h&gt;
</span><span class="lines">@@ -363,29 +364,32 @@
</span><span class="cx">         StackTrace&amp; stackTrace = m_stackTraces.last();
</span><span class="cx">         stackTrace.timestamp = unprocessedStackTrace.timestamp;
</span><span class="cx"> 
</span><del>-        auto appendCodeBlock = [&amp;] (CodeBlock* codeBlock, unsigned bytecodeIndex) {
-            stackTrace.frames.append(StackFrame(codeBlock-&gt;ownerExecutable()));
-            m_liveCellPointers.add(codeBlock-&gt;ownerExecutable());
-
</del><ins>+        auto populateCodeLocation = [] (CodeBlock* codeBlock, unsigned bytecodeIndex, StackFrame::CodeLocation&amp; location) {
</ins><span class="cx">             if (bytecodeIndex &lt; codeBlock-&gt;instructionCount()) {
</span><span class="cx">                 int divot;
</span><span class="cx">                 int startOffset;
</span><span class="cx">                 int endOffset;
</span><span class="cx">                 codeBlock-&gt;expressionRangeForBytecodeOffset(bytecodeIndex, divot, startOffset, endOffset,
</span><del>-                    stackTrace.frames.last().lineNumber, stackTrace.frames.last().columnNumber);
-                stackTrace.frames.last().bytecodeIndex = bytecodeIndex;
</del><ins>+                    location.lineNumber, location.columnNumber);
+                location.bytecodeIndex = bytecodeIndex;
</ins><span class="cx">             }
</span><span class="cx">             if (Options::collectSamplingProfilerDataForJSCShell()) {
</span><del>-                stackTrace.frames.last().codeBlockHash = codeBlock-&gt;hash();
-                stackTrace.frames.last().jitType = codeBlock-&gt;jitType();
</del><ins>+                location.codeBlockHash = codeBlock-&gt;hash();
+                location.jitType = codeBlock-&gt;jitType();
</ins><span class="cx">             }
</span><span class="cx">         };
</span><span class="cx"> 
</span><ins>+        auto appendCodeBlock = [&amp;] (CodeBlock* codeBlock, unsigned bytecodeIndex) {
+            stackTrace.frames.append(StackFrame(codeBlock-&gt;ownerExecutable()));
+            m_liveCellPointers.add(codeBlock-&gt;ownerExecutable());
+            populateCodeLocation(codeBlock, bytecodeIndex, stackTrace.frames.last().semanticLocation);
+        };
+
</ins><span class="cx">         auto appendEmptyFrame = [&amp;] {
</span><span class="cx">             stackTrace.frames.append(StackFrame());
</span><span class="cx">         };
</span><span class="cx"> 
</span><del>-        auto storeCalleeIntoTopFrame = [&amp;] (EncodedJSValue encodedCallee) {
</del><ins>+        auto storeCalleeIntoLastFrame = [&amp;] (EncodedJSValue encodedCallee) {
</ins><span class="cx">             // Set the callee if it's a valid GC object.
</span><span class="cx">             JSValue callee = JSValue::decode(encodedCallee);
</span><span class="cx">             StackFrame&amp; stackFrame = stackTrace.frames.last();
</span><span class="lines">@@ -441,7 +445,31 @@
</span><span class="cx">             m_liveCellPointers.add(executable);
</span><span class="cx">         };
</span><span class="cx"> 
</span><ins>+        auto appendCodeOrigin = [&amp;] (CodeBlock* machineCodeBlock, CodeOrigin origin) {
+            size_t startIndex = stackTrace.frames.size(); // We want to change stack traces that we're about to append.
</ins><span class="cx"> 
</span><ins>+            CodeOrigin machineOrigin;
+            origin.walkUpInlineStack([&amp;] (const CodeOrigin&amp; codeOrigin) {
+                machineOrigin = codeOrigin;
+                appendCodeBlock(codeOrigin.inlineCallFrame ? codeOrigin.inlineCallFrame-&gt;baselineCodeBlock.get() : machineCodeBlock, codeOrigin.bytecodeIndex);
+            });
+
+            if (Options::collectSamplingProfilerDataForJSCShell()) {
+                RELEASE_ASSERT(machineOrigin.isSet());
+                RELEASE_ASSERT(!machineOrigin.inlineCallFrame);
+
+                StackFrame::CodeLocation machineLocation = stackTrace.frames.last().semanticLocation;
+
+                // We want to tell each inlined frame about the machine frame
+                // they were inlined into. Currently, we only use this for dumping
+                // output on the command line, but we could extend it to the web
+                // inspector in the future if we find a need for it there.
+                RELEASE_ASSERT(stackTrace.frames.size());
+                for (size_t i = startIndex; i &lt; stackTrace.frames.size() - 1; i++)
+                    stackTrace.frames[i].machineLocation = std::make_pair(machineLocation, Strong&lt;CodeBlock&gt;(m_vm, machineCodeBlock));
+            }
+        };
+
</ins><span class="cx">         // Prepend the top-most inlined frame if needed and gather
</span><span class="cx">         // location information about where the top frame is executing.
</span><span class="cx">         size_t startIndex = 0;
</span><span class="lines">@@ -468,14 +496,12 @@
</span><span class="cx">                     UNUSED_PARAM(isValidPC); // FIXME: do something with this info for the web inspector: https://bugs.webkit.org/show_bug.cgi?id=153455
</span><span class="cx"> 
</span><span class="cx">                     appendCodeBlock(topCodeBlock, bytecodeIndex);
</span><del>-                    storeCalleeIntoTopFrame(unprocessedStackTrace.frames[0].unverifiedCallee);
</del><ins>+                    storeCalleeIntoLastFrame(unprocessedStackTrace.frames[0].unverifiedCallee);
</ins><span class="cx">                     startIndex = 1;
</span><span class="cx">                 }
</span><span class="cx">             } else if (std::optional&lt;CodeOrigin&gt; codeOrigin = topCodeBlock-&gt;findPC(unprocessedStackTrace.topPC)) {
</span><del>-                codeOrigin-&gt;walkUpInlineStack([&amp;] (const CodeOrigin&amp; codeOrigin) {
-                    appendCodeBlock(codeOrigin.inlineCallFrame ? codeOrigin.inlineCallFrame-&gt;baselineCodeBlock.get() : topCodeBlock, codeOrigin.bytecodeIndex);
-                });
-                storeCalleeIntoTopFrame(unprocessedStackTrace.frames[0].unverifiedCallee);
</del><ins>+                appendCodeOrigin(topCodeBlock, *codeOrigin);
+                storeCalleeIntoLastFrame(unprocessedStackTrace.frames[0].unverifiedCallee);
</ins><span class="cx">                 startIndex = 1;
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="lines">@@ -492,11 +518,9 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx">                 if (codeBlock-&gt;hasCodeOrigins()) {
</span><del>-                    if (codeBlock-&gt;canGetCodeOrigin(callSiteIndex)) {
-                        codeBlock-&gt;codeOrigin(callSiteIndex).walkUpInlineStack([&amp;] (const CodeOrigin&amp; codeOrigin) {
-                            appendCodeBlock(codeOrigin.inlineCallFrame ? codeOrigin.inlineCallFrame-&gt;baselineCodeBlock.get() : codeBlock, codeOrigin.bytecodeIndex);
-                        });
-                    } else
</del><ins>+                    if (codeBlock-&gt;canGetCodeOrigin(callSiteIndex))
+                        appendCodeOrigin(codeBlock, codeBlock-&gt;codeOrigin(callSiteIndex));
+                    else
</ins><span class="cx">                         appendCodeBlock(codeBlock, std::numeric_limits&lt;unsigned&gt;::max());
</span><span class="cx">                 } else
</span><span class="cx">                     appendCodeBlockNoInlining();
</span><span class="lines">@@ -508,7 +532,7 @@
</span><span class="cx"> 
</span><span class="cx">             // Note that this is okay to do if we walked the inline stack because
</span><span class="cx">             // the machine frame will be at the top of the processed stack trace.
</span><del>-            storeCalleeIntoTopFrame(unprocessedStackFrame.unverifiedCallee);
</del><ins>+            storeCalleeIntoLastFrame(unprocessedStackFrame.unverifiedCallee);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -843,14 +867,16 @@
</span><span class="cx">         return std::make_pair(maxFrameDescription, maxFrameCount);
</span><span class="cx">     };
</span><span class="cx"> 
</span><del>-    out.print(&quot;\n\nSampling rate: &quot;, m_timingInterval.count(), &quot; microseconds\n&quot;);
-    out.print(&quot;Hottest functions as &lt;numSamples  'functionName:sourceID'&gt;\n&quot;);
-    for (size_t i = 0; i &lt; 40; i++) {
-        auto pair = takeMax();
-        if (pair.first.isEmpty())
-            break;
-        out.printf(&quot;%6zu &quot;, pair.second);
-        out.print(&quot;   '&quot;, pair.first, &quot;'\n&quot;);
</del><ins>+    if (Options::samplingProfilerTopFunctionsCount()) {
+        out.print(&quot;\n\nSampling rate: &quot;, m_timingInterval.count(), &quot; microseconds\n&quot;);
+        out.print(&quot;Top functions as &lt;numSamples  'functionName:sourceID'&gt;\n&quot;);
+        for (size_t i = 0; i &lt; Options::samplingProfilerTopFunctionsCount(); i++) {
+            auto pair = takeMax();
+            if (pair.first.isEmpty())
+                break;
+            out.printf(&quot;%6zu &quot;, pair.second);
+            out.print(&quot;   '&quot;, pair.first, &quot;'\n&quot;);
+        }
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -873,22 +899,30 @@
</span><span class="cx">         if (!stackTrace.frames.size())
</span><span class="cx">             continue;
</span><span class="cx"> 
</span><del>-        StackFrame&amp; frame = stackTrace.frames.first();
-        String bytecodeIndex;
-        String codeBlockHash;
-        if (frame.hasBytecodeIndex())
-            bytecodeIndex = String::number(frame.bytecodeIndex);
-        else
-            bytecodeIndex = &quot;&lt;nil&gt;&quot;;
</del><ins>+        auto descriptionForLocation = [&amp;] (StackFrame::CodeLocation location) -&gt; String {
+            String bytecodeIndex;
+            String codeBlockHash;
+            if (location.hasBytecodeIndex())
+                bytecodeIndex = String::number(location.bytecodeIndex);
+            else
+                bytecodeIndex = &quot;&lt;nil&gt;&quot;;
</ins><span class="cx"> 
</span><del>-        if (frame.hasCodeBlockHash()) {
-            StringPrintStream stream;
-            frame.codeBlockHash.dump(stream);
-            codeBlockHash = stream.toString();
-        } else
-            codeBlockHash = &quot;&lt;nil&gt;&quot;;
</del><ins>+            if (location.hasCodeBlockHash()) {
+                StringPrintStream stream;
+                location.codeBlockHash.dump(stream);
+                codeBlockHash = stream.toString();
+            } else
+                codeBlockHash = &quot;&lt;nil&gt;&quot;;
</ins><span class="cx"> 
</span><del>-        String frameDescription = makeString(frame.displayName(m_vm), &quot;#&quot;, codeBlockHash, &quot;:&quot;, JITCode::typeName(frame.jitType), &quot;:&quot;, bytecodeIndex);
</del><ins>+            return makeString(&quot;#&quot;, codeBlockHash, &quot;:&quot;, JITCode::typeName(location.jitType), &quot;:&quot;, bytecodeIndex);
+        };
+
+        StackFrame&amp; frame = stackTrace.frames.first();
+        String frameDescription = makeString(frame.displayName(m_vm), descriptionForLocation(frame.semanticLocation));
+        if (std::optional&lt;std::pair&lt;StackFrame::CodeLocation, Strong&lt;CodeBlock&gt;&gt;&gt; machineLocation = frame.machineLocation) {
+            frameDescription = makeString(frameDescription, &quot; &lt;-- &quot;,
+                machineLocation-&gt;second-&gt;inferredName().data(), descriptionForLocation(machineLocation-&gt;first));
+        }
</ins><span class="cx">         bytecodeCounts.add(frameDescription, 0).iterator-&gt;value++;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -906,14 +940,16 @@
</span><span class="cx">         return std::make_pair(maxFrameDescription, maxFrameCount);
</span><span class="cx">     };
</span><span class="cx"> 
</span><del>-    out.print(&quot;\n\nSampling rate: &quot;, m_timingInterval.count(), &quot; microseconds\n&quot;);
-    out.print(&quot;Hottest bytecodes as &lt;numSamples   'functionName#hash:JITType:bytecodeIndex'&gt;\n&quot;);
-    for (size_t i = 0; i &lt; 80; i++) {
-        auto pair = takeMax();
-        if (pair.first.isEmpty())
-            break;
-        out.printf(&quot;%6zu &quot;, pair.second);
-        out.print(&quot;   '&quot;, pair.first, &quot;'\n&quot;);
</del><ins>+    if (Options::samplingProfilerTopBytecodesCount()) {
+        out.print(&quot;\n\nSampling rate: &quot;, m_timingInterval.count(), &quot; microseconds\n&quot;);
+        out.print(&quot;Hottest bytecodes as &lt;numSamples   'functionName#hash:JITType:bytecodeIndex'&gt;\n&quot;);
+        for (size_t i = 0; i &lt; Options::samplingProfilerTopBytecodesCount(); i++) {
+            auto pair = takeMax();
+            if (pair.first.isEmpty())
+                break;
+            out.printf(&quot;%6zu &quot;, pair.second);
+            out.print(&quot;   '&quot;, pair.first, &quot;'\n&quot;);
+        }
</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 (211315 => 211316)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/SamplingProfiler.h        2017-01-28 00:55:39 UTC (rev 211315)
+++ trunk/Source/JavaScriptCore/runtime/SamplingProfiler.h        2017-01-28 01:04:06 UTC (rev 211316)
</span><span class="lines">@@ -80,27 +80,45 @@
</span><span class="cx">         FrameType frameType { FrameType::Unknown };
</span><span class="cx">         ExecutableBase* executable { nullptr };
</span><span class="cx">         JSObject* callee { nullptr };
</span><del>-        // These attempt to be expression-level line and column number.
-        unsigned lineNumber { std::numeric_limits&lt;unsigned&gt;::max() };
-        unsigned columnNumber { std::numeric_limits&lt;unsigned&gt;::max() };
-        unsigned bytecodeIndex { std::numeric_limits&lt;unsigned&gt;::max() };
-        CodeBlockHash codeBlockHash;
-        JITCode::JITType jitType { JITCode::None };
</del><span class="cx"> 
</span><del>-        bool hasExpressionInfo() const
-        {
-            return lineNumber != std::numeric_limits&lt;unsigned&gt;::max()
-                &amp;&amp; columnNumber != std::numeric_limits&lt;unsigned&gt;::max();
-        }
</del><ins>+        struct CodeLocation {
+            bool hasCodeBlockHash() const
+            {
+                return codeBlockHash.isSet();
+            }
</ins><span class="cx"> 
</span><del>-        bool hasBytecodeIndex() const
</del><ins>+            bool hasBytecodeIndex() const
+            {
+                return bytecodeIndex != std::numeric_limits&lt;unsigned&gt;::max();
+            }
+
+            bool hasExpressionInfo() const
+            {
+                return lineNumber != std::numeric_limits&lt;unsigned&gt;::max()
+                    &amp;&amp; columnNumber != std::numeric_limits&lt;unsigned&gt;::max();
+            }
+
+            // These attempt to be expression-level line and column number.
+            unsigned lineNumber { std::numeric_limits&lt;unsigned&gt;::max() };
+            unsigned columnNumber { std::numeric_limits&lt;unsigned&gt;::max() };
+            unsigned bytecodeIndex { std::numeric_limits&lt;unsigned&gt;::max() };
+            CodeBlockHash codeBlockHash;
+            JITCode::JITType jitType { JITCode::None };
+        };
+
+        CodeLocation semanticLocation;
+        std::optional&lt;std::pair&lt;CodeLocation, Strong&lt;CodeBlock&gt;&gt;&gt; machineLocation; // This is non-null if we were inlined. It represents the machine frame we were inlined into.
+
+        bool hasExpressionInfo() const { return semanticLocation.hasExpressionInfo(); }
+        unsigned lineNumber() const
</ins><span class="cx">         {
</span><del>-            return bytecodeIndex != std::numeric_limits&lt;unsigned&gt;::max();
</del><ins>+            ASSERT(hasExpressionInfo());
+            return semanticLocation.lineNumber;
</ins><span class="cx">         }
</span><del>-
-        bool hasCodeBlockHash() const
</del><ins>+        unsigned columnNumber() const
</ins><span class="cx">         {
</span><del>-            return codeBlockHash.isSet();
</del><ins>+            ASSERT(hasExpressionInfo());
+            return semanticLocation.columnNumber;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // These are function-level data.
</span></span></pre>
</div>
</div>

</body>
</html>