<!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>[192125] 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/192125">192125</a></dd>
<dt>Author</dt> <dd>sbarati@apple.com</dd>
<dt>Date</dt> <dd>2015-11-06 19:18:32 -0800 (Fri, 06 Nov 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Control Flow Profiler should keep execution counts of basic blocks
https://bugs.webkit.org/show_bug.cgi?id=146099

Reviewed by Mark Lam.

This patch changes the control flow profiler to now
keep track of execution counts for each basic block
instead of a boolean indicating if the basic block has 
executed at all.  This has the consequence of us having to 
always compile all op_profile_control_flows in the baseline and DFG.

This patch adds a new &quot;executionCount&quot; field to the inspector protocol
corresponding to the execution of a basic block. This patch, for now,
still maintains the previous field of &quot;hasExecuted&quot; even though this is
redundant with &quot;executionCount&quot;.

* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* inspector/agents/InspectorRuntimeAgent.cpp:
(Inspector::InspectorRuntimeAgent::getBasicBlocks):
* inspector/protocol/Runtime.json:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_profile_control_flow):
(JSC::JIT::emit_op_create_direct_arguments):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionHasBasicBlockExecuted):
(functionBasicBlockExecutionCount):
(functionEnableExceptionFuzz):
(functionDrainMicrotasks):
(functionIs32BitPlatform):
(functionLoadWebAssembly):
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/BasicBlockLocation.cpp:
(JSC::BasicBlockLocation::BasicBlockLocation):
(JSC::BasicBlockLocation::dumpData):
(JSC::BasicBlockLocation::emitExecuteCode):
* runtime/BasicBlockLocation.h:
(JSC::BasicBlockLocation::endOffset):
(JSC::BasicBlockLocation::setStartOffset):
(JSC::BasicBlockLocation::setEndOffset):
(JSC::BasicBlockLocation::hasExecuted):
(JSC::BasicBlockLocation::executionCount):
* runtime/ControlFlowProfiler.cpp:
(JSC::ControlFlowProfiler::getBasicBlocksForSourceID):
(JSC::findBasicBlockAtTextOffset):
(JSC::ControlFlowProfiler::hasBasicBlockAtTextOffsetBeenExecuted):
(JSC::ControlFlowProfiler::basicBlockExecutionCountAtTextOffset):
* runtime/ControlFlowProfiler.h:
(JSC::ControlFlowProfiler::dummyBasicBlock):
* tests/controlFlowProfiler/execution-count.js: Added.
(noop):
(foo):
(a):
(b):
(baz):
(jaz):
(testWhile):
(is32BitPlatform.testMax):
(is32BitPlatform):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreinspectoragentsInspectorRuntimeAgentcpp">trunk/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreinspectorprotocolRuntimejson">trunk/Source/JavaScriptCore/inspector/protocol/Runtime.json</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOpcodescpp">trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejsccpp">trunk/Source/JavaScriptCore/jsc.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreterasm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreter32_64asm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreter64asm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeBasicBlockLocationcpp">trunk/Source/JavaScriptCore/runtime/BasicBlockLocation.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeBasicBlockLocationh">trunk/Source/JavaScriptCore/runtime/BasicBlockLocation.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeControlFlowProfilercpp">trunk/Source/JavaScriptCore/runtime/ControlFlowProfiler.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeControlFlowProfilerh">trunk/Source/JavaScriptCore/runtime/ControlFlowProfiler.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestscontrolFlowProfilerexecutioncountjs">trunk/Source/JavaScriptCore/tests/controlFlowProfiler/execution-count.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (192124 => 192125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-11-07 03:18:32 UTC (rev 192125)
</span><span class="lines">@@ -1,3 +1,70 @@
</span><ins>+2015-11-06  Saam barati  &lt;sbarati@apple.com&gt;
+
+        Control Flow Profiler should keep execution counts of basic blocks
+        https://bugs.webkit.org/show_bug.cgi?id=146099
+
+        Reviewed by Mark Lam.
+
+        This patch changes the control flow profiler to now
+        keep track of execution counts for each basic block
+        instead of a boolean indicating if the basic block has 
+        executed at all.  This has the consequence of us having to 
+        always compile all op_profile_control_flows in the baseline and DFG.
+
+        This patch adds a new &quot;executionCount&quot; field to the inspector protocol
+        corresponding to the execution of a basic block. This patch, for now,
+        still maintains the previous field of &quot;hasExecuted&quot; even though this is
+        redundant with &quot;executionCount&quot;.
+
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * inspector/agents/InspectorRuntimeAgent.cpp:
+        (Inspector::InspectorRuntimeAgent::getBasicBlocks):
+        * inspector/protocol/Runtime.json:
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_profile_control_flow):
+        (JSC::JIT::emit_op_create_direct_arguments):
+        * jsc.cpp:
+        (GlobalObject::finishCreation):
+        (functionHasBasicBlockExecuted):
+        (functionBasicBlockExecutionCount):
+        (functionEnableExceptionFuzz):
+        (functionDrainMicrotasks):
+        (functionIs32BitPlatform):
+        (functionLoadWebAssembly):
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * runtime/BasicBlockLocation.cpp:
+        (JSC::BasicBlockLocation::BasicBlockLocation):
+        (JSC::BasicBlockLocation::dumpData):
+        (JSC::BasicBlockLocation::emitExecuteCode):
+        * runtime/BasicBlockLocation.h:
+        (JSC::BasicBlockLocation::endOffset):
+        (JSC::BasicBlockLocation::setStartOffset):
+        (JSC::BasicBlockLocation::setEndOffset):
+        (JSC::BasicBlockLocation::hasExecuted):
+        (JSC::BasicBlockLocation::executionCount):
+        * runtime/ControlFlowProfiler.cpp:
+        (JSC::ControlFlowProfiler::getBasicBlocksForSourceID):
+        (JSC::findBasicBlockAtTextOffset):
+        (JSC::ControlFlowProfiler::hasBasicBlockAtTextOffsetBeenExecuted):
+        (JSC::ControlFlowProfiler::basicBlockExecutionCountAtTextOffset):
+        * runtime/ControlFlowProfiler.h:
+        (JSC::ControlFlowProfiler::dummyBasicBlock):
+        * tests/controlFlowProfiler/execution-count.js: Added.
+        (noop):
+        (foo):
+        (a):
+        (b):
+        (baz):
+        (jaz):
+        (testWhile):
+        (is32BitPlatform.testMax):
+        (is32BitPlatform):
+
</ins><span class="cx"> 2015-11-06  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         B3 and Air should simplify CFGs
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (192124 => 192125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2015-11-07 03:18:32 UTC (rev 192125)
</span><span class="lines">@@ -4782,11 +4782,9 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">     case ProfileControlFlow: {
</span><ins>+        GPRTemporary scratch1(this);
</ins><span class="cx">         BasicBlockLocation* basicBlockLocation = node-&gt;basicBlockLocation();
</span><del>-        if (!basicBlockLocation-&gt;hasExecuted()) {
-            GPRTemporary scratch1(this);
-            basicBlockLocation-&gt;emitExecuteCode(m_jit, scratch1.gpr());
-        }
</del><ins>+        basicBlockLocation-&gt;emitExecuteCode(m_jit, scratch1.gpr());
</ins><span class="cx">         noResult(node);
</span><span class="cx">         break;
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (192124 => 192125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-11-07 03:18:32 UTC (rev 192125)
</span><span class="lines">@@ -4813,10 +4813,7 @@
</span><span class="cx">     }
</span><span class="cx">     case ProfileControlFlow: {
</span><span class="cx">         BasicBlockLocation* basicBlockLocation = node-&gt;basicBlockLocation();
</span><del>-        if (!basicBlockLocation-&gt;hasExecuted()) {
-            GPRTemporary scratch1(this);
-            basicBlockLocation-&gt;emitExecuteCode(m_jit, scratch1.gpr());
-        }
</del><ins>+        basicBlockLocation-&gt;emitExecuteCode(m_jit);
</ins><span class="cx">         noResult(node);
</span><span class="cx">         break;
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinspectoragentsInspectorRuntimeAgentcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp (192124 => 192125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp        2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp        2015-11-07 03:18:32 UTC (rev 192125)
</span><span class="lines">@@ -356,6 +356,7 @@
</span><span class="cx">             .setStartOffset(block.m_startOffset)
</span><span class="cx">             .setEndOffset(block.m_endOffset)
</span><span class="cx">             .setHasExecuted(block.m_hasExecuted)
</span><ins>+            .setExecutionCount(block.m_executionCount)
</ins><span class="cx">             .release();
</span><span class="cx">         basicBlocks-&gt;addItem(WTF::move(location));
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinspectorprotocolRuntimejson"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/inspector/protocol/Runtime.json (192124 => 192125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/inspector/protocol/Runtime.json        2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/JavaScriptCore/inspector/protocol/Runtime.json        2015-11-07 03:18:32 UTC (rev 192125)
</span><span class="lines">@@ -188,7 +188,8 @@
</span><span class="cx">             &quot;properties&quot;: [
</span><span class="cx">                 { &quot;name&quot;: &quot;startOffset&quot;, &quot;type&quot;: &quot;integer&quot;, &quot;description&quot;: &quot;Start offset of the basic block.&quot; },
</span><span class="cx">                 { &quot;name&quot;: &quot;endOffset&quot;, &quot;type&quot;: &quot;integer&quot;, &quot;description&quot;: &quot;End offset of the basic block.&quot; },
</span><del>-                { &quot;name&quot;: &quot;hasExecuted&quot;, &quot;type&quot;: &quot;boolean&quot;, &quot;description&quot;: &quot;Indicates if the basic block has executed before.&quot; }
</del><ins>+                { &quot;name&quot;: &quot;hasExecuted&quot;, &quot;type&quot;: &quot;boolean&quot;, &quot;description&quot;: &quot;Indicates if the basic block has executed before.&quot; },
+                { &quot;name&quot;: &quot;executionCount&quot;, &quot;type&quot;: &quot;integer&quot;, &quot;description&quot;: &quot;Indicates how many times the basic block has executed.&quot; }
</ins><span class="cx">             ]
</span><span class="cx">         }
</span><span class="cx">     ],
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOpcodescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp (192124 => 192125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp        2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp        2015-11-07 03:18:32 UTC (rev 192125)
</span><span class="lines">@@ -1368,8 +1368,11 @@
</span><span class="cx"> void JIT::emit_op_profile_control_flow(Instruction* currentInstruction)
</span><span class="cx"> {
</span><span class="cx">     BasicBlockLocation* basicBlockLocation = currentInstruction[1].u.basicBlockLocation;
</span><del>-    if (!basicBlockLocation-&gt;hasExecuted())
-        basicBlockLocation-&gt;emitExecuteCode(*this, regT1);
</del><ins>+#if USE(JSVALUE64)
+    basicBlockLocation-&gt;emitExecuteCode(*this);
+#else
+    basicBlockLocation-&gt;emitExecuteCode(*this, regT0);
+#endif
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void JIT::emit_op_create_direct_arguments(Instruction* currentInstruction)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejsccpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jsc.cpp (192124 => 192125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jsc.cpp        2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/JavaScriptCore/jsc.cpp        2015-11-07 03:18:32 UTC (rev 192125)
</span><span class="lines">@@ -544,8 +544,10 @@
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState*);
</span><ins>+static EncodedJSValue JSC_HOST_CALL functionBasicBlockExecutionCount(ExecState*);
</ins><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionDrainMicrotasks(ExecState*);
</span><ins>+static EncodedJSValue JSC_HOST_CALL functionIs32BitPlatform(ExecState*);
</ins><span class="cx"> #if ENABLE(WEBASSEMBLY)
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionLoadWebAssembly(ExecState*);
</span><span class="cx"> #endif
</span><span class="lines">@@ -724,11 +726,14 @@
</span><span class="cx"> 
</span><span class="cx">         addFunction(vm, &quot;dumpBasicBlockExecutionRanges&quot;, functionDumpBasicBlockExecutionRanges , 0);
</span><span class="cx">         addFunction(vm, &quot;hasBasicBlockExecuted&quot;, functionHasBasicBlockExecuted, 2);
</span><ins>+        addFunction(vm, &quot;basicBlockExecutionCount&quot;, functionBasicBlockExecutionCount, 2);
</ins><span class="cx"> 
</span><span class="cx">         addFunction(vm, &quot;enableExceptionFuzz&quot;, functionEnableExceptionFuzz, 0);
</span><span class="cx"> 
</span><span class="cx">         addFunction(vm, &quot;drainMicrotasks&quot;, functionDrainMicrotasks, 0);
</span><span class="cx"> 
</span><ins>+        addFunction(vm, &quot;is32BitPlatform&quot;, functionIs32BitPlatform, 0);
+
</ins><span class="cx"> #if ENABLE(WEBASSEMBLY)
</span><span class="cx">         addFunction(vm, &quot;loadWebAssembly&quot;, functionLoadWebAssembly, 3);
</span><span class="cx"> #endif
</span><span class="lines">@@ -1505,6 +1510,24 @@
</span><span class="cx">     return JSValue::encode(jsBoolean(hasExecuted));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+EncodedJSValue JSC_HOST_CALL functionBasicBlockExecutionCount(ExecState* exec)
+{
+    RELEASE_ASSERT(exec-&gt;vm().controlFlowProfiler());
+
+    JSValue functionValue = exec-&gt;argument(0);
+    RELEASE_ASSERT(functionValue.isFunction());
+    FunctionExecutable* executable = (jsDynamicCast&lt;JSFunction*&gt;(functionValue.asCell()-&gt;getObject()))-&gt;jsExecutable();
+
+    RELEASE_ASSERT(exec-&gt;argument(1).isString());
+    String substring = exec-&gt;argument(1).getString(exec);
+    String sourceCodeText = executable-&gt;source().toString();
+    RELEASE_ASSERT(sourceCodeText.contains(substring));
+    int offset = sourceCodeText.find(substring) + executable-&gt;source().startOffset();
+    
+    size_t executionCount = exec-&gt;vm().controlFlowProfiler()-&gt;basicBlockExecutionCountAtTextOffset(offset, executable-&gt;sourceID(), exec-&gt;vm());
+    return JSValue::encode(JSValue(executionCount));
+}
+
</ins><span class="cx"> EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*)
</span><span class="cx"> {
</span><span class="cx">     Options::useExceptionFuzz() = true;
</span><span class="lines">@@ -1517,6 +1540,15 @@
</span><span class="cx">     return JSValue::encode(jsUndefined());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+EncodedJSValue JSC_HOST_CALL functionIs32BitPlatform(ExecState*)
+{
+#if USE(JSVALUE64)
+    return JSValue::encode(JSValue(JSC::JSValue::JSFalse));
+#else
+    return JSValue::encode(JSValue(JSC::JSValue::JSTrue));
+#endif
+}
+
</ins><span class="cx"> #if ENABLE(WEBASSEMBLY)
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL functionLoadWebAssembly(ExecState* exec)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreterasm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm (192124 => 192125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm        2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm        2015-11-07 03:18:32 UTC (rev 192125)
</span><span class="lines">@@ -1669,12 +1669,6 @@
</span><span class="cx">     callSlowPath(_slow_path_to_index_string)
</span><span class="cx">     dispatch(3)
</span><span class="cx"> 
</span><del>-_llint_op_profile_control_flow:
-    traceExecution()
-    loadpFromInstruction(1, t0)
-    storeb 1, BasicBlockLocation::m_hasExecuted[t0]
-    dispatch(2)
-
</del><span class="cx"> # Lastly, make sure that we can link even though we don't support all opcodes.
</span><span class="cx"> # These opcodes should never arise when using LLInt or either JIT. We assert
</span><span class="cx"> # as much.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreter32_64asm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm (192124 => 192125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm        2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm        2015-11-07 03:18:32 UTC (rev 192125)
</span><span class="lines">@@ -2410,6 +2410,18 @@
</span><span class="cx"> .opProfileTypeDone:
</span><span class="cx">     dispatch(6)
</span><span class="cx"> 
</span><ins>+
+_llint_op_profile_control_flow:
+    traceExecution()
+    loadpFromInstruction(1, t0)
+    loadi BasicBlockLocation::m_executionCount[t0], t1
+    addi 1, t1
+    bieq t1, 0, .done # We overflowed.
+    storei t1, BasicBlockLocation::m_executionCount[t0]
+.done:
+    dispatch(2)
+
+
</ins><span class="cx"> _llint_op_load_arrowfunction_this:
</span><span class="cx">     traceExecution()
</span><span class="cx">     loadi Callee + PayloadOffset[cfr], t0
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreter64asm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (192124 => 192125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2015-11-07 03:18:32 UTC (rev 192125)
</span><span class="lines">@@ -2284,6 +2284,13 @@
</span><span class="cx"> .opProfileTypeDone:
</span><span class="cx">     dispatch(6)
</span><span class="cx"> 
</span><ins>+_llint_op_profile_control_flow:
+    traceExecution()
+    loadpFromInstruction(1, t0)
+    addq 1, BasicBlockLocation::m_executionCount[t0]
+    dispatch(2)
+
+
</ins><span class="cx"> _llint_op_load_arrowfunction_this:
</span><span class="cx">     traceExecution()
</span><span class="cx">     loadp Callee[cfr], t0
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeBasicBlockLocationcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/BasicBlockLocation.cpp (192124 => 192125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/BasicBlockLocation.cpp        2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/JavaScriptCore/runtime/BasicBlockLocation.cpp        2015-11-07 03:18:32 UTC (rev 192125)
</span><span class="lines">@@ -36,7 +36,7 @@
</span><span class="cx"> BasicBlockLocation::BasicBlockLocation(int startOffset, int endOffset)
</span><span class="cx">     : m_startOffset(startOffset)
</span><span class="cx">     , m_endOffset(endOffset)
</span><del>-    , m_hasExecuted(false)
</del><ins>+    , m_executionCount(0)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -75,15 +75,26 @@
</span><span class="cx"> {
</span><span class="cx">     Vector&lt;Gap&gt; executedRanges = getExecutedRanges();
</span><span class="cx">     for (Gap gap : executedRanges)
</span><del>-        dataLogF(&quot;\tBasicBlock: [%d, %d] hasExecuted: %s\n&quot;, gap.first, gap.second, hasExecuted() ? &quot;true&quot; : &quot;false&quot;);
</del><ins>+        dataLogF(&quot;\tBasicBlock: [%d, %d] hasExecuted: %s, executionCount:%zu\n&quot;, gap.first, gap.second, hasExecuted() ? &quot;true&quot; : &quot;false&quot;, m_executionCount);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(JIT)
</span><del>-void BasicBlockLocation::emitExecuteCode(CCallHelpers&amp; jit, MacroAssembler::RegisterID ptrReg) const
</del><ins>+#if USE(JSVALUE64)
+void BasicBlockLocation::emitExecuteCode(CCallHelpers&amp; jit) const
</ins><span class="cx"> {
</span><del>-    jit.move(CCallHelpers::TrustedImmPtr(&amp;m_hasExecuted), ptrReg);
-    jit.store8(CCallHelpers::TrustedImm32(true), CCallHelpers::Address(ptrReg, 0));
</del><ins>+    static_assert(sizeof(size_t) == 8, &quot;Assuming size_t is 64 bits on 64 bit platforms.&quot;);
+    jit.add64(CCallHelpers::TrustedImm32(1), CCallHelpers::AbsoluteAddress(&amp;m_executionCount));
</ins><span class="cx"> }
</span><ins>+#else
+void BasicBlockLocation::emitExecuteCode(CCallHelpers&amp; jit, MacroAssembler::RegisterID scratch) const
+{
+    static_assert(sizeof(size_t) == 4, &quot;Assuming size_t is 32 bits on 32 bit platforms.&quot;);
+    jit.load32(&amp;m_executionCount, scratch);
+    CCallHelpers::Jump done = jit.branchAdd32(CCallHelpers::Zero, scratch, CCallHelpers::TrustedImm32(1), scratch);
+    jit.store32(scratch, bitwise_cast&lt;void*&gt;(&amp;m_executionCount));
+    done.link(&amp;jit);
+}
+#endif // USE(JSVALUE64)
</ins><span class="cx"> #endif // ENABLE(JIT)
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeBasicBlockLocationh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/BasicBlockLocation.h (192124 => 192125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/BasicBlockLocation.h        2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/JavaScriptCore/runtime/BasicBlockLocation.h        2015-11-07 03:18:32 UTC (rev 192125)
</span><span class="lines">@@ -47,20 +47,25 @@
</span><span class="cx">     int endOffset() const { return m_endOffset; }
</span><span class="cx">     void setStartOffset(int startOffset) { m_startOffset = startOffset; }
</span><span class="cx">     void setEndOffset(int endOffset) { m_endOffset = endOffset; }
</span><del>-    bool hasExecuted() const { return m_hasExecuted; }
</del><ins>+    bool hasExecuted() const { return m_executionCount &gt; 0; }
+    size_t executionCount() const { return m_executionCount; }
</ins><span class="cx">     void insertGap(int, int);
</span><span class="cx">     Vector&lt;Gap&gt; getExecutedRanges() const;
</span><span class="cx">     JS_EXPORT_PRIVATE void dumpData() const;
</span><span class="cx"> #if ENABLE(JIT)
</span><del>-    void emitExecuteCode(CCallHelpers&amp;, MacroAssembler::RegisterID) const;
</del><ins>+#if USE(JSVALUE64)
+    void emitExecuteCode(CCallHelpers&amp;) const;
+#else
+    void emitExecuteCode(CCallHelpers&amp;, MacroAssembler::RegisterID scratch) const;
</ins><span class="cx"> #endif
</span><ins>+#endif
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     friend class LLIntOffsetsExtractor;
</span><span class="cx"> 
</span><span class="cx">     int m_startOffset;
</span><span class="cx">     int m_endOffset;
</span><del>-    bool m_hasExecuted;
</del><ins>+    size_t m_executionCount;
</ins><span class="cx">     Vector&lt;Gap&gt; m_gaps;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeControlFlowProfilercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ControlFlowProfiler.cpp (192124 => 192125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ControlFlowProfiler.cpp        2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/JavaScriptCore/runtime/ControlFlowProfiler.cpp        2015-11-07 03:18:32 UTC (rev 192125)
</span><span class="lines">@@ -76,31 +76,33 @@
</span><span class="cx">     const BlockLocationCache&amp; cache = bucketFindResult-&gt;value;
</span><span class="cx">     for (const BasicBlockLocation* block : cache.values()) {
</span><span class="cx">         bool hasExecuted = block-&gt;hasExecuted();
</span><ins>+        size_t executionCount = block-&gt;executionCount();
</ins><span class="cx">         const Vector&lt;BasicBlockLocation::Gap&gt;&amp; blockRanges = block-&gt;getExecutedRanges();
</span><span class="cx">         for (BasicBlockLocation::Gap gap : blockRanges) {
</span><span class="cx">             BasicBlockRange range;
</span><span class="cx">             range.m_hasExecuted = hasExecuted;
</span><ins>+            range.m_executionCount = executionCount;
</ins><span class="cx">             range.m_startOffset = gap.first;
</span><span class="cx">             range.m_endOffset = gap.second;
</span><span class="cx">             result.append(range);
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    const Vector&lt;std::tuple&lt;bool, unsigned, unsigned&gt;&gt;&amp; unexecutedFunctionRanges = vm.functionHasExecutedCache()-&gt;getFunctionRanges(sourceID);
-    for (const auto&amp; functionRange : unexecutedFunctionRanges) {
</del><ins>+    const Vector&lt;std::tuple&lt;bool, unsigned, unsigned&gt;&gt;&amp; functionRanges = vm.functionHasExecutedCache()-&gt;getFunctionRanges(sourceID);
+    for (const auto&amp; functionRange : functionRanges) {
</ins><span class="cx">         BasicBlockRange range;
</span><span class="cx">         range.m_hasExecuted = std::get&lt;0&gt;(functionRange);
</span><span class="cx">         range.m_startOffset = static_cast&lt;int&gt;(std::get&lt;1&gt;(functionRange));
</span><span class="cx">         range.m_endOffset = static_cast&lt;int&gt;(std::get&lt;2&gt;(functionRange));
</span><ins>+        range.m_executionCount = range.m_hasExecuted ? 1 : 0; // This is a hack. We don't actually count this.
</ins><span class="cx">         result.append(range);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool ControlFlowProfiler::hasBasicBlockAtTextOffsetBeenExecuted(int offset, intptr_t sourceID, VM&amp; vm)
</del><ins>+static BasicBlockRange findBasicBlockAtTextOffset(int offset, const Vector&lt;BasicBlockRange&gt;&amp; blocks)
</ins><span class="cx"> {
</span><del>-    const Vector&lt;BasicBlockRange&gt;&amp; blocks = getBasicBlocksForSourceID(sourceID, vm);
</del><span class="cx">     int bestDistance = INT_MAX;
</span><span class="cx">     BasicBlockRange bestRange;
</span><span class="cx">     bestRange.m_startOffset = bestRange.m_endOffset = -1;
</span><span class="lines">@@ -115,7 +117,21 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     RELEASE_ASSERT(bestRange.m_startOffset != -1 &amp;&amp; bestRange.m_endOffset != -1);
</span><del>-    return bestRange.m_hasExecuted;
</del><ins>+    return bestRange;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool ControlFlowProfiler::hasBasicBlockAtTextOffsetBeenExecuted(int offset, intptr_t sourceID, VM&amp; vm)
+{
+    const Vector&lt;BasicBlockRange&gt;&amp; blocks = getBasicBlocksForSourceID(sourceID, vm);
+    BasicBlockRange range = findBasicBlockAtTextOffset(offset, blocks);
+    return range.m_hasExecuted;
+}
+
+size_t ControlFlowProfiler::basicBlockExecutionCountAtTextOffset(int offset, intptr_t sourceID, VM&amp; vm)
+{
+    const Vector&lt;BasicBlockRange&gt;&amp; blocks = getBasicBlocksForSourceID(sourceID, vm);
+    BasicBlockRange range = findBasicBlockAtTextOffset(offset, blocks);
+    return range.m_executionCount;
+}
+
</ins><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeControlFlowProfilerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ControlFlowProfiler.h (192124 => 192125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ControlFlowProfiler.h        2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/JavaScriptCore/runtime/ControlFlowProfiler.h        2015-11-07 03:18:32 UTC (rev 192125)
</span><span class="lines">@@ -87,6 +87,7 @@
</span><span class="cx">     int m_startOffset;
</span><span class="cx">     int m_endOffset;
</span><span class="cx">     bool m_hasExecuted;
</span><ins>+    size_t m_executionCount;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> class ControlFlowProfiler {
</span><span class="lines">@@ -98,7 +99,8 @@
</span><span class="cx">     JS_EXPORT_PRIVATE void dumpData() const;
</span><span class="cx">     Vector&lt;BasicBlockRange&gt; getBasicBlocksForSourceID(intptr_t sourceID, VM&amp;) const;
</span><span class="cx">     BasicBlockLocation* dummyBasicBlock() { return &amp;m_dummyBasicBlock; }
</span><del>-    JS_EXPORT_PRIVATE bool hasBasicBlockAtTextOffsetBeenExecuted(int, intptr_t, VM&amp;); // This function exists for testing.
</del><ins>+    JS_EXPORT_PRIVATE bool hasBasicBlockAtTextOffsetBeenExecuted(int, intptr_t, VM&amp;);  // This function exists for testing.
+    JS_EXPORT_PRIVATE size_t basicBlockExecutionCountAtTextOffset(int, intptr_t, VM&amp;); // This function exists for testing.
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     typedef HashMap&lt;BasicBlockKey, BasicBlockLocation*&gt; BlockLocationCache;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestscontrolFlowProfilerexecutioncountjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/controlFlowProfiler/execution-count.js (0 => 192125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/controlFlowProfiler/execution-count.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/controlFlowProfiler/execution-count.js        2015-11-07 03:18:32 UTC (rev 192125)
</span><span class="lines">@@ -0,0 +1,70 @@
</span><ins>+load(&quot;./driver/driver.js&quot;);
+
+function noop() { ; }
+function foo(num) {
+    for (let i = 0; i &lt; num; i++) {
+        noop(); 
+    }
+}
+
+function a() { ; }
+function b() { ; }
+
+function baz(num) {
+    for (let i = 0; i &lt; num; i++) {
+        i % 2 ? a() : b();
+    }
+}
+
+function jaz(num) {
+    for (let i = 0; i &lt; num; i++) {
+        if (i % 2)
+            a();
+        else
+            b();
+    }
+}
+
+function testWhile(num) {
+    let i = num;
+    while (i--) {
+        noop();
+        if (i % 2)
+            a();
+        else
+            b();
+    }
+}
+
+foo(120);
+assert(basicBlockExecutionCount(foo, &quot;noop()&quot;) === 120);
+noop();
+assert(basicBlockExecutionCount(noop, &quot;;&quot;) === 121);
+
+baz(140);
+assert(basicBlockExecutionCount(baz, &quot;a()&quot;) === 140/2);
+assert(basicBlockExecutionCount(baz, &quot;b()&quot;) === 140/2);
+assert(basicBlockExecutionCount(a, &quot;;&quot;) === 140/2);
+assert(basicBlockExecutionCount(b, &quot;;&quot;) === 140/2);
+
+jaz(140);
+assert(basicBlockExecutionCount(jaz, &quot;a()&quot;) === 140/2);
+assert(basicBlockExecutionCount(jaz, &quot;b()&quot;) === 140/2);
+
+testWhile(140);
+assert(basicBlockExecutionCount(testWhile, &quot;noop()&quot;) === 140);
+assert(basicBlockExecutionCount(testWhile, &quot;a()&quot;) === 140/2);
+assert(basicBlockExecutionCount(testWhile, &quot;b()&quot;) === 140/2);
+
+if (is32BitPlatform()) {
+    function testMax() {
+        let j = 0;
+        let numIters = Math.pow(2, 32) + 10;
+        for (let i = 0; i &lt; numIters; i++) {
+            j++;
+        }
+    }
+
+    testMax();
+    assert(basicBlockExecutionCount(testMax, &quot;j++&quot;) === Math.pow(2, 32) - 1);
+}
</ins></span></pre>
</div>
</div>

</body>
</html>