Title: [192125] trunk/Source/_javascript_Core
Revision
192125
Author
sbar...@apple.com
Date
2015-11-06 19:18:32 -0800 (Fri, 06 Nov 2015)

Log Message

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):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (192124 => 192125)


--- trunk/Source/_javascript_Core/ChangeLog	2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-11-07 03:18:32 UTC (rev 192125)
@@ -1,3 +1,70 @@
+2015-11-06  Saam barati  <sbar...@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):
+
 2015-11-06  Filip Pizlo  <fpi...@apple.com>
 
         B3 and Air should simplify CFGs

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (192124 => 192125)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2015-11-07 03:18:32 UTC (rev 192125)
@@ -4782,11 +4782,9 @@
         break;
     }
     case ProfileControlFlow: {
+        GPRTemporary scratch1(this);
         BasicBlockLocation* basicBlockLocation = node->basicBlockLocation();
-        if (!basicBlockLocation->hasExecuted()) {
-            GPRTemporary scratch1(this);
-            basicBlockLocation->emitExecuteCode(m_jit, scratch1.gpr());
-        }
+        basicBlockLocation->emitExecuteCode(m_jit, scratch1.gpr());
         noResult(node);
         break;
     }

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (192124 => 192125)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2015-11-07 03:18:32 UTC (rev 192125)
@@ -4813,10 +4813,7 @@
     }
     case ProfileControlFlow: {
         BasicBlockLocation* basicBlockLocation = node->basicBlockLocation();
-        if (!basicBlockLocation->hasExecuted()) {
-            GPRTemporary scratch1(this);
-            basicBlockLocation->emitExecuteCode(m_jit, scratch1.gpr());
-        }
+        basicBlockLocation->emitExecuteCode(m_jit);
         noResult(node);
         break;
     }

Modified: trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.cpp (192124 => 192125)


--- trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.cpp	2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.cpp	2015-11-07 03:18:32 UTC (rev 192125)
@@ -356,6 +356,7 @@
             .setStartOffset(block.m_startOffset)
             .setEndOffset(block.m_endOffset)
             .setHasExecuted(block.m_hasExecuted)
+            .setExecutionCount(block.m_executionCount)
             .release();
         basicBlocks->addItem(WTF::move(location));
     }

Modified: trunk/Source/_javascript_Core/inspector/protocol/Runtime.json (192124 => 192125)


--- trunk/Source/_javascript_Core/inspector/protocol/Runtime.json	2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/_javascript_Core/inspector/protocol/Runtime.json	2015-11-07 03:18:32 UTC (rev 192125)
@@ -188,7 +188,8 @@
             "properties": [
                 { "name": "startOffset", "type": "integer", "description": "Start offset of the basic block." },
                 { "name": "endOffset", "type": "integer", "description": "End offset of the basic block." },
-                { "name": "hasExecuted", "type": "boolean", "description": "Indicates if the basic block has executed before." }
+                { "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." }
             ]
         }
     ],

Modified: trunk/Source/_javascript_Core/jit/JITOpcodes.cpp (192124 => 192125)


--- trunk/Source/_javascript_Core/jit/JITOpcodes.cpp	2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes.cpp	2015-11-07 03:18:32 UTC (rev 192125)
@@ -1368,8 +1368,11 @@
 void JIT::emit_op_profile_control_flow(Instruction* currentInstruction)
 {
     BasicBlockLocation* basicBlockLocation = currentInstruction[1].u.basicBlockLocation;
-    if (!basicBlockLocation->hasExecuted())
-        basicBlockLocation->emitExecuteCode(*this, regT1);
+#if USE(JSVALUE64)
+    basicBlockLocation->emitExecuteCode(*this);
+#else
+    basicBlockLocation->emitExecuteCode(*this, regT0);
+#endif
 }
 
 void JIT::emit_op_create_direct_arguments(Instruction* currentInstruction)

Modified: trunk/Source/_javascript_Core/jsc.cpp (192124 => 192125)


--- trunk/Source/_javascript_Core/jsc.cpp	2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/_javascript_Core/jsc.cpp	2015-11-07 03:18:32 UTC (rev 192125)
@@ -544,8 +544,10 @@
 static EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionBasicBlockExecutionCount(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionDrainMicrotasks(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionIs32BitPlatform(ExecState*);
 #if ENABLE(WEBASSEMBLY)
 static EncodedJSValue JSC_HOST_CALL functionLoadWebAssembly(ExecState*);
 #endif
@@ -724,11 +726,14 @@
 
         addFunction(vm, "dumpBasicBlockExecutionRanges", functionDumpBasicBlockExecutionRanges , 0);
         addFunction(vm, "hasBasicBlockExecuted", functionHasBasicBlockExecuted, 2);
+        addFunction(vm, "basicBlockExecutionCount", functionBasicBlockExecutionCount, 2);
 
         addFunction(vm, "enableExceptionFuzz", functionEnableExceptionFuzz, 0);
 
         addFunction(vm, "drainMicrotasks", functionDrainMicrotasks, 0);
 
+        addFunction(vm, "is32BitPlatform", functionIs32BitPlatform, 0);
+
 #if ENABLE(WEBASSEMBLY)
         addFunction(vm, "loadWebAssembly", functionLoadWebAssembly, 3);
 #endif
@@ -1505,6 +1510,24 @@
     return JSValue::encode(jsBoolean(hasExecuted));
 }
 
+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));
+}
+
 EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*)
 {
     Options::useExceptionFuzz() = true;
@@ -1517,6 +1540,15 @@
     return JSValue::encode(jsUndefined());
 }
 
+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
+}
+
 #if ENABLE(WEBASSEMBLY)
 EncodedJSValue JSC_HOST_CALL functionLoadWebAssembly(ExecState* exec)
 {

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm (192124 => 192125)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2015-11-07 03:18:32 UTC (rev 192125)
@@ -1669,12 +1669,6 @@
     callSlowPath(_slow_path_to_index_string)
     dispatch(3)
 
-_llint_op_profile_control_flow:
-    traceExecution()
-    loadpFromInstruction(1, t0)
-    storeb 1, BasicBlockLocation::m_hasExecuted[t0]
-    dispatch(2)
-
 # Lastly, make sure that we can link even though we don't support all opcodes.
 # These opcodes should never arise when using LLInt or either JIT. We assert
 # as much.

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm (192124 => 192125)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm	2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm	2015-11-07 03:18:32 UTC (rev 192125)
@@ -2410,6 +2410,18 @@
 .opProfileTypeDone:
     dispatch(6)
 
+
+_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)
+
+
 _llint_op_load_arrowfunction_this:
     traceExecution()
     loadi Callee + PayloadOffset[cfr], t0

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (192124 => 192125)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2015-11-07 03:18:32 UTC (rev 192125)
@@ -2284,6 +2284,13 @@
 .opProfileTypeDone:
     dispatch(6)
 
+_llint_op_profile_control_flow:
+    traceExecution()
+    loadpFromInstruction(1, t0)
+    addq 1, BasicBlockLocation::m_executionCount[t0]
+    dispatch(2)
+
+
 _llint_op_load_arrowfunction_this:
     traceExecution()
     loadp Callee[cfr], t0

Modified: trunk/Source/_javascript_Core/runtime/BasicBlockLocation.cpp (192124 => 192125)


--- trunk/Source/_javascript_Core/runtime/BasicBlockLocation.cpp	2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/_javascript_Core/runtime/BasicBlockLocation.cpp	2015-11-07 03:18:32 UTC (rev 192125)
@@ -36,7 +36,7 @@
 BasicBlockLocation::BasicBlockLocation(int startOffset, int endOffset)
     : m_startOffset(startOffset)
     , m_endOffset(endOffset)
-    , m_hasExecuted(false)
+    , m_executionCount(0)
 {
 }
 
@@ -75,15 +75,26 @@
 {
     Vector<Gap> executedRanges = getExecutedRanges();
     for (Gap gap : executedRanges)
-        dataLogF("\tBasicBlock: [%d, %d] hasExecuted: %s\n", gap.first, gap.second, hasExecuted() ? "true" : "false");
+        dataLogF("\tBasicBlock: [%d, %d] hasExecuted: %s, executionCount:%zu\n", gap.first, gap.second, hasExecuted() ? "true" : "false", m_executionCount);
 }
 
 #if ENABLE(JIT)
-void BasicBlockLocation::emitExecuteCode(CCallHelpers& jit, MacroAssembler::RegisterID ptrReg) const
+#if USE(JSVALUE64)
+void BasicBlockLocation::emitExecuteCode(CCallHelpers& jit) const
 {
-    jit.move(CCallHelpers::TrustedImmPtr(&m_hasExecuted), ptrReg);
-    jit.store8(CCallHelpers::TrustedImm32(true), CCallHelpers::Address(ptrReg, 0));
+    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));
 }
+#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)
 #endif // ENABLE(JIT)
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/BasicBlockLocation.h (192124 => 192125)


--- trunk/Source/_javascript_Core/runtime/BasicBlockLocation.h	2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/_javascript_Core/runtime/BasicBlockLocation.h	2015-11-07 03:18:32 UTC (rev 192125)
@@ -47,20 +47,25 @@
     int endOffset() const { return m_endOffset; }
     void setStartOffset(int startOffset) { m_startOffset = startOffset; }
     void setEndOffset(int endOffset) { m_endOffset = endOffset; }
-    bool hasExecuted() const { return m_hasExecuted; }
+    bool hasExecuted() const { return m_executionCount > 0; }
+    size_t executionCount() const { return m_executionCount; }
     void insertGap(int, int);
     Vector<Gap> getExecutedRanges() const;
     JS_EXPORT_PRIVATE void dumpData() const;
 #if ENABLE(JIT)
-    void emitExecuteCode(CCallHelpers&, MacroAssembler::RegisterID) const;
+#if USE(JSVALUE64)
+    void emitExecuteCode(CCallHelpers&) const;
+#else
+    void emitExecuteCode(CCallHelpers&, MacroAssembler::RegisterID scratch) const;
 #endif
+#endif
 
 private:
     friend class LLIntOffsetsExtractor;
 
     int m_startOffset;
     int m_endOffset;
-    bool m_hasExecuted;
+    size_t m_executionCount;
     Vector<Gap> m_gaps;
 };
 

Modified: trunk/Source/_javascript_Core/runtime/ControlFlowProfiler.cpp (192124 => 192125)


--- trunk/Source/_javascript_Core/runtime/ControlFlowProfiler.cpp	2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/_javascript_Core/runtime/ControlFlowProfiler.cpp	2015-11-07 03:18:32 UTC (rev 192125)
@@ -76,31 +76,33 @@
     const BlockLocationCache& cache = bucketFindResult->value;
     for (const BasicBlockLocation* block : cache.values()) {
         bool hasExecuted = block->hasExecuted();
+        size_t executionCount = block->executionCount();
         const Vector<BasicBlockLocation::Gap>& blockRanges = block->getExecutedRanges();
         for (BasicBlockLocation::Gap gap : blockRanges) {
             BasicBlockRange range;
             range.m_hasExecuted = hasExecuted;
+            range.m_executionCount = executionCount;
             range.m_startOffset = gap.first;
             range.m_endOffset = gap.second;
             result.append(range);
         }
     }
 
-    const Vector<std::tuple<bool, unsigned, unsigned>>& unexecutedFunctionRanges = vm.functionHasExecutedCache()->getFunctionRanges(sourceID);
-    for (const auto& functionRange : unexecutedFunctionRanges) {
+    const Vector<std::tuple<bool, unsigned, unsigned>>& functionRanges = vm.functionHasExecutedCache()->getFunctionRanges(sourceID);
+    for (const auto& functionRange : functionRanges) {
         BasicBlockRange range;
         range.m_hasExecuted = std::get<0>(functionRange);
         range.m_startOffset = static_cast<int>(std::get<1>(functionRange));
         range.m_endOffset = static_cast<int>(std::get<2>(functionRange));
+        range.m_executionCount = range.m_hasExecuted ? 1 : 0; // This is a hack. We don't actually count this.
         result.append(range);
     }
 
     return result;
 }
 
-bool ControlFlowProfiler::hasBasicBlockAtTextOffsetBeenExecuted(int offset, intptr_t sourceID, VM& vm)
+static BasicBlockRange findBasicBlockAtTextOffset(int offset, const Vector<BasicBlockRange>& blocks)
 {
-    const Vector<BasicBlockRange>& blocks = getBasicBlocksForSourceID(sourceID, vm);
     int bestDistance = INT_MAX;
     BasicBlockRange bestRange;
     bestRange.m_startOffset = bestRange.m_endOffset = -1;
@@ -115,7 +117,21 @@
     }
 
     RELEASE_ASSERT(bestRange.m_startOffset != -1 && bestRange.m_endOffset != -1);
-    return bestRange.m_hasExecuted;
+    return bestRange;
 }
 
+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;
+}
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/ControlFlowProfiler.h (192124 => 192125)


--- trunk/Source/_javascript_Core/runtime/ControlFlowProfiler.h	2015-11-07 02:32:13 UTC (rev 192124)
+++ trunk/Source/_javascript_Core/runtime/ControlFlowProfiler.h	2015-11-07 03:18:32 UTC (rev 192125)
@@ -87,6 +87,7 @@
     int m_startOffset;
     int m_endOffset;
     bool m_hasExecuted;
+    size_t m_executionCount;
 };
 
 class ControlFlowProfiler {
@@ -98,7 +99,8 @@
     JS_EXPORT_PRIVATE void dumpData() const;
     Vector<BasicBlockRange> getBasicBlocksForSourceID(intptr_t sourceID, VM&) const;
     BasicBlockLocation* dummyBasicBlock() { return &m_dummyBasicBlock; }
-    JS_EXPORT_PRIVATE bool hasBasicBlockAtTextOffsetBeenExecuted(int, intptr_t, VM&); // This function exists for testing.
+    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.
 
 private:
     typedef HashMap<BasicBlockKey, BasicBlockLocation*> BlockLocationCache;

Added: trunk/Source/_javascript_Core/tests/controlFlowProfiler/execution-count.js (0 => 192125)


--- trunk/Source/_javascript_Core/tests/controlFlowProfiler/execution-count.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/controlFlowProfiler/execution-count.js	2015-11-07 03:18:32 UTC (rev 192125)
@@ -0,0 +1,70 @@
+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);
+}
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to