<!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 "executionCount" field to the inspector protocol
corresponding to the execution of a basic block. This patch, for now,
still maintains the previous field of "hasExecuted" even though this is
redundant with "executionCount".
* 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 <sbarati@apple.com>
+
+ 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 "executionCount" field to the inspector protocol
+ corresponding to the execution of a basic block. This patch, for now,
+ still maintains the previous field of "hasExecuted" even though this is
+ redundant with "executionCount".
+
+ * 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 <fpizlo@apple.com>
</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->basicBlockLocation();
</span><del>- if (!basicBlockLocation->hasExecuted()) {
- GPRTemporary scratch1(this);
- basicBlockLocation->emitExecuteCode(m_jit, scratch1.gpr());
- }
</del><ins>+ basicBlockLocation->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->basicBlockLocation();
</span><del>- if (!basicBlockLocation->hasExecuted()) {
- GPRTemporary scratch1(this);
- basicBlockLocation->emitExecuteCode(m_jit, scratch1.gpr());
- }
</del><ins>+ basicBlockLocation->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->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"> "properties": [
</span><span class="cx"> { "name": "startOffset", "type": "integer", "description": "Start offset of the basic block." },
</span><span class="cx"> { "name": "endOffset", "type": "integer", "description": "End offset of the basic block." },
</span><del>- { "name": "hasExecuted", "type": "boolean", "description": "Indicates if the basic block has executed before." }
</del><ins>+ { "name": "hasExecuted", "type": "boolean", "description": "Indicates if the basic block has executed before." },
+ { "name": "executionCount", "type": "integer", "description": "Indicates how many times the basic block has executed." }
</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->hasExecuted())
- basicBlockLocation->emitExecuteCode(*this, regT1);
</del><ins>+#if USE(JSVALUE64)
+ basicBlockLocation->emitExecuteCode(*this);
+#else
+ basicBlockLocation->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, "dumpBasicBlockExecutionRanges", functionDumpBasicBlockExecutionRanges , 0);
</span><span class="cx"> addFunction(vm, "hasBasicBlockExecuted", functionHasBasicBlockExecuted, 2);
</span><ins>+ addFunction(vm, "basicBlockExecutionCount", functionBasicBlockExecutionCount, 2);
</ins><span class="cx">
</span><span class="cx"> addFunction(vm, "enableExceptionFuzz", functionEnableExceptionFuzz, 0);
</span><span class="cx">
</span><span class="cx"> addFunction(vm, "drainMicrotasks", functionDrainMicrotasks, 0);
</span><span class="cx">
</span><ins>+ addFunction(vm, "is32BitPlatform", functionIs32BitPlatform, 0);
+
</ins><span class="cx"> #if ENABLE(WEBASSEMBLY)
</span><span class="cx"> addFunction(vm, "loadWebAssembly", 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->vm().controlFlowProfiler());
+
+ JSValue functionValue = exec->argument(0);
+ RELEASE_ASSERT(functionValue.isFunction());
+ FunctionExecutable* executable = (jsDynamicCast<JSFunction*>(functionValue.asCell()->getObject()))->jsExecutable();
+
+ RELEASE_ASSERT(exec->argument(1).isString());
+ String substring = exec->argument(1).getString(exec);
+ String sourceCodeText = executable->source().toString();
+ RELEASE_ASSERT(sourceCodeText.contains(substring));
+ int offset = sourceCodeText.find(substring) + executable->source().startOffset();
+
+ size_t executionCount = exec->vm().controlFlowProfiler()->basicBlockExecutionCountAtTextOffset(offset, executable->sourceID(), exec->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<Gap> executedRanges = getExecutedRanges();
</span><span class="cx"> for (Gap gap : executedRanges)
</span><del>- dataLogF("\tBasicBlock: [%d, %d] hasExecuted: %s\n", gap.first, gap.second, hasExecuted() ? "true" : "false");
</del><ins>+ dataLogF("\tBasicBlock: [%d, %d] hasExecuted: %s, executionCount:%zu\n", gap.first, gap.second, hasExecuted() ? "true" : "false", m_executionCount);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> #if ENABLE(JIT)
</span><del>-void BasicBlockLocation::emitExecuteCode(CCallHelpers& jit, MacroAssembler::RegisterID ptrReg) const
</del><ins>+#if USE(JSVALUE64)
+void BasicBlockLocation::emitExecuteCode(CCallHelpers& jit) const
</ins><span class="cx"> {
</span><del>- jit.move(CCallHelpers::TrustedImmPtr(&m_hasExecuted), ptrReg);
- jit.store8(CCallHelpers::TrustedImm32(true), CCallHelpers::Address(ptrReg, 0));
</del><ins>+ static_assert(sizeof(size_t) == 8, "Assuming size_t is 64 bits on 64 bit platforms.");
+ jit.add64(CCallHelpers::TrustedImm32(1), CCallHelpers::AbsoluteAddress(&m_executionCount));
</ins><span class="cx"> }
</span><ins>+#else
+void BasicBlockLocation::emitExecuteCode(CCallHelpers& jit, MacroAssembler::RegisterID scratch) const
+{
+ static_assert(sizeof(size_t) == 4, "Assuming size_t is 32 bits on 32 bit platforms.");
+ jit.load32(&m_executionCount, scratch);
+ CCallHelpers::Jump done = jit.branchAdd32(CCallHelpers::Zero, scratch, CCallHelpers::TrustedImm32(1), scratch);
+ jit.store32(scratch, bitwise_cast<void*>(&m_executionCount));
+ done.link(&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 > 0; }
+ size_t executionCount() const { return m_executionCount; }
</ins><span class="cx"> void insertGap(int, int);
</span><span class="cx"> Vector<Gap> getExecutedRanges() const;
</span><span class="cx"> JS_EXPORT_PRIVATE void dumpData() const;
</span><span class="cx"> #if ENABLE(JIT)
</span><del>- void emitExecuteCode(CCallHelpers&, MacroAssembler::RegisterID) const;
</del><ins>+#if USE(JSVALUE64)
+ void emitExecuteCode(CCallHelpers&) const;
+#else
+ void emitExecuteCode(CCallHelpers&, 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<Gap> 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& cache = bucketFindResult->value;
</span><span class="cx"> for (const BasicBlockLocation* block : cache.values()) {
</span><span class="cx"> bool hasExecuted = block->hasExecuted();
</span><ins>+ size_t executionCount = block->executionCount();
</ins><span class="cx"> const Vector<BasicBlockLocation::Gap>& blockRanges = block->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<std::tuple<bool, unsigned, unsigned>>& unexecutedFunctionRanges = vm.functionHasExecutedCache()->getFunctionRanges(sourceID);
- for (const auto& functionRange : unexecutedFunctionRanges) {
</del><ins>+ const Vector<std::tuple<bool, unsigned, unsigned>>& functionRanges = vm.functionHasExecutedCache()->getFunctionRanges(sourceID);
+ for (const auto& functionRange : functionRanges) {
</ins><span class="cx"> BasicBlockRange range;
</span><span class="cx"> range.m_hasExecuted = std::get<0>(functionRange);
</span><span class="cx"> range.m_startOffset = static_cast<int>(std::get<1>(functionRange));
</span><span class="cx"> range.m_endOffset = static_cast<int>(std::get<2>(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& vm)
</del><ins>+static BasicBlockRange findBasicBlockAtTextOffset(int offset, const Vector<BasicBlockRange>& blocks)
</ins><span class="cx"> {
</span><del>- const Vector<BasicBlockRange>& 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 && 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& vm)
+{
+ const Vector<BasicBlockRange>& blocks = getBasicBlocksForSourceID(sourceID, vm);
+ BasicBlockRange range = findBasicBlockAtTextOffset(offset, blocks);
+ return range.m_hasExecuted;
+}
+
+size_t ControlFlowProfiler::basicBlockExecutionCountAtTextOffset(int offset, intptr_t sourceID, VM& vm)
+{
+ const Vector<BasicBlockRange>& 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<BasicBlockRange> getBasicBlocksForSourceID(intptr_t sourceID, VM&) const;
</span><span class="cx"> BasicBlockLocation* dummyBasicBlock() { return &m_dummyBasicBlock; }
</span><del>- JS_EXPORT_PRIVATE bool hasBasicBlockAtTextOffsetBeenExecuted(int, intptr_t, VM&); // This function exists for testing.
</del><ins>+ JS_EXPORT_PRIVATE bool hasBasicBlockAtTextOffsetBeenExecuted(int, intptr_t, VM&); // This function exists for testing.
+ JS_EXPORT_PRIVATE size_t basicBlockExecutionCountAtTextOffset(int, intptr_t, VM&); // This function exists for testing.
</ins><span class="cx">
</span><span class="cx"> private:
</span><span class="cx"> typedef HashMap<BasicBlockKey, BasicBlockLocation*> 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("./driver/driver.js");
+
+function noop() { ; }
+function foo(num) {
+ for (let i = 0; i < num; i++) {
+ noop();
+ }
+}
+
+function a() { ; }
+function b() { ; }
+
+function baz(num) {
+ for (let i = 0; i < num; i++) {
+ i % 2 ? a() : b();
+ }
+}
+
+function jaz(num) {
+ for (let i = 0; i < 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, "noop()") === 120);
+noop();
+assert(basicBlockExecutionCount(noop, ";") === 121);
+
+baz(140);
+assert(basicBlockExecutionCount(baz, "a()") === 140/2);
+assert(basicBlockExecutionCount(baz, "b()") === 140/2);
+assert(basicBlockExecutionCount(a, ";") === 140/2);
+assert(basicBlockExecutionCount(b, ";") === 140/2);
+
+jaz(140);
+assert(basicBlockExecutionCount(jaz, "a()") === 140/2);
+assert(basicBlockExecutionCount(jaz, "b()") === 140/2);
+
+testWhile(140);
+assert(basicBlockExecutionCount(testWhile, "noop()") === 140);
+assert(basicBlockExecutionCount(testWhile, "a()") === 140/2);
+assert(basicBlockExecutionCount(testWhile, "b()") === 140/2);
+
+if (is32BitPlatform()) {
+ function testMax() {
+ let j = 0;
+ let numIters = Math.pow(2, 32) + 10;
+ for (let i = 0; i < numIters; i++) {
+ j++;
+ }
+ }
+
+ testMax();
+ assert(basicBlockExecutionCount(testMax, "j++") === Math.pow(2, 32) - 1);
+}
</ins></span></pre>
</div>
</div>
</body>
</html>