JavaScript Control Flow Profiler
https://bugs.webkit.org/show_bug.cgi?id=137785

Reviewed by Filip Pizlo.

This patch introduces a mechanism for JavaScriptCore to profile
which basic blocks have executed. This mechanism will then be
used by the Web Inspector to indicate which basic blocks
have and have not executed.
        
The profiling works by compiling in an op_profile_control_flow
at the start of every basic block. Then, whenever this op code 
executes, we know that a particular basic block has executed.
        
When we tier up a CodeBlock that contains an op_profile_control_flow
that corresponds to an already executed basic block, we don't
have to emit code for that particular op_profile_control_flow
because the internal data structures used to keep track of 
basic block locations has already recorded that the corresponding
op_profile_control_flow has executed.

* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
* bytecode/Instruction.h:
* bytecode/UnlinkedCodeBlock.cpp:
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::addOpProfileControlFlowBytecodeOffset):
(JSC::UnlinkedCodeBlock::opProfileControlFlowBytecodeOffsets):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitProfileControlFlow):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::ConditionalNode::emitBytecode):
(JSC::IfElseNode::emitBytecode):
(JSC::WhileNode::emitBytecode):
(JSC::ForNode::emitBytecode):
(JSC::ContinueNode::emitBytecode):
(JSC::BreakNode::emitBytecode):
(JSC::ReturnNode::emitBytecode):
(JSC::CaseClauseNode::emitBytecode):
(JSC::SwitchNode::emitBytecode):
(JSC::ThrowNode::emitBytecode):
(JSC::TryNode::emitBytecode):
(JSC::ProgramNode::emitBytecode):
(JSC::FunctionNode::emitBytecode):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::basicBlockLocation):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* inspector/agents/InspectorRuntimeAgent.cpp:
(Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_profile_control_flow):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_profile_control_flow):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionFindTypeForExpression):
(functionReturnTypeFor):
(functionDumpBasicBlockExecutionRanges):
* llint/LowLevelInterpreter.asm:
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createFunctionExpr):
(JSC::ASTBuilder::createGetterOrSetterProperty):
(JSC::ASTBuilder::createFuncDeclStatement):
(JSC::ASTBuilder::endOffset):
(JSC::ASTBuilder::setStartOffset):
* parser/NodeConstructors.h:
(JSC::Node::Node):
* parser/Nodes.h:
(JSC::CaseClauseNode::setStartOffset):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseSwitchClauses):
(JSC::Parser<LexerType>::parseSwitchDefaultClause):
(JSC::Parser<LexerType>::parseBlockStatement):
(JSC::Parser<LexerType>::parseStatement):
(JSC::Parser<LexerType>::parseFunctionDeclaration):
(JSC::Parser<LexerType>::parseIfStatement):
(JSC::Parser<LexerType>::parseExpression):
(JSC::Parser<LexerType>::parseConditionalExpression):
(JSC::Parser<LexerType>::parseProperty):
(JSC::Parser<LexerType>::parseMemberExpression):
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createFunctionExpr):
(JSC::SyntaxChecker::createFuncDeclStatement):
(JSC::SyntaxChecker::createGetterOrSetterProperty):
(JSC::SyntaxChecker::operatorStackPop):
* runtime/BasicBlockLocation.cpp: Added.
(JSC::BasicBlockLocation::BasicBlockLocation):
(JSC::BasicBlockLocation::insertGap):
(JSC::BasicBlockLocation::getExecutedRanges):
(JSC::BasicBlockLocation::dumpData):
(JSC::BasicBlockLocation::emitExecuteCode):
* runtime/BasicBlockLocation.h: Added.
(JSC::BasicBlockLocation::startOffset):
(JSC::BasicBlockLocation::endOffset):
(JSC::BasicBlockLocation::setStartOffset):
(JSC::BasicBlockLocation::setEndOffset):
(JSC::BasicBlockLocation::hasExecuted):
* runtime/CodeCache.cpp:
(JSC::CodeCache::getGlobalCodeBlock):
* runtime/ControlFlowProfiler.cpp: Added.
(JSC::ControlFlowProfiler::~ControlFlowProfiler):
(JSC::ControlFlowProfiler::getBasicBlockLocation):
(JSC::ControlFlowProfiler::dumpData):
(JSC::ControlFlowProfiler::getBasicBlocksForSourceID):
* runtime/ControlFlowProfiler.h: Added. This class is in 
charge of generating BasicBlockLocations and also
providing an interface that the Web Inspector can use to ping
which basic blocks have executed based on the source id of a script.

(JSC::BasicBlockKey::BasicBlockKey):
(JSC::BasicBlockKey::isHashTableDeletedValue):
(JSC::BasicBlockKey::operator==):
(JSC::BasicBlockKey::hash):
(JSC::BasicBlockKeyHash::hash):
(JSC::BasicBlockKeyHash::equal):
* runtime/Executable.cpp:
(JSC::ProgramExecutable::ProgramExecutable):
(JSC::ProgramExecutable::initializeGlobalProperties):
* runtime/FunctionHasExecutedCache.cpp:
(JSC::FunctionHasExecutedCache::getUnexecutedFunctionRanges):
* runtime/FunctionHasExecutedCache.h:
* runtime/Options.h:
* runtime/TypeProfiler.cpp:
(JSC::TypeProfiler::logTypesForTypeLocation):
(JSC::TypeProfiler::typeInformationForExpressionAtOffset):
(JSC::TypeProfiler::findLocation):
(JSC::TypeProfiler::dumpTypeProfilerData):
* runtime/TypeProfiler.h:
(JSC::TypeProfiler::functionHasExecutedCache): Deleted.
* runtime/VM.cpp:
(JSC::VM::VM):
(JSC::enableProfilerWithRespectToCount):
(JSC::disableProfilerWithRespectToCount):
(JSC::VM::enableTypeProfiler):
(JSC::VM::disableTypeProfiler):
(JSC::VM::enableControlFlowProfiler):
(JSC::VM::disableControlFlowProfiler):
(JSC::VM::dumpTypeProfilerData):
* runtime/VM.h:
(JSC::VM::functionHasExecutedCache):
(JSC::VM::controlFlowProfiler):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@176836 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index 73dc71b..55a4c04 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -1991,6 +1991,7 @@
     case ProfileWillCall:
     case ProfileDidCall:
     case ProfileType:
+    case ProfileControlFlow:
     case Phantom:
     case HardPhantom:
     case CountExecution:
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 7c075df..b91ff50 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -29,6 +29,7 @@
 #if ENABLE(DFG_JIT)
 
 #include "ArrayConstructor.h"
+#include "BasicBlockLocation.h"
 #include "CallLinkStatus.h"
 #include "CodeBlock.h"
 #include "CodeBlockWithJITType.h"
@@ -2884,6 +2885,12 @@
             NEXT_OPCODE(op_profile_type);
         }
 
+        case op_profile_control_flow: {
+            BasicBlockLocation* basicBlockLocation = currentInstruction[1].u.basicBlockLocation;
+            addToGraph(ProfileControlFlow, OpInfo(basicBlockLocation));
+            NEXT_OPCODE(op_profile_control_flow);
+        }
+
         // === Block terminators. ===
 
         case op_jmp: {
diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
index 3d9fd3a..37b38e2 100644
--- a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
@@ -121,6 +121,7 @@
     case op_profile_will_call:
     case op_profile_did_call:
     case op_profile_type:
+    case op_profile_control_flow:
     case op_mov:
     case op_check_has_instance:
     case op_instanceof:
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index b5d35b4..6c6927b 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -274,6 +274,7 @@
     case ProfileWillCall:
     case ProfileDidCall:
     case ProfileType:
+    case ProfileControlFlow:
     case StoreBarrier:
     case StoreBarrierWithNullCheck:
     case PutByOffsetHint:
diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
index 5033ba4..d635775 100644
--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
@@ -124,6 +124,7 @@
     case ProfileWillCall:
     case ProfileDidCall:
     case ProfileType:
+    case ProfileControlFlow:
     case CheckHasInstance:
     case InstanceOf:
     case IsUndefined:
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 18aae11..0e6e19d 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -1202,6 +1202,7 @@
         case Construct:
         case ProfiledCall:
         case ProfiledConstruct:
+        case ProfileControlFlow:
         case NativeCall:
         case NativeConstruct:
         case NewObject:
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 87182aa..04eee50 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -28,6 +28,7 @@
 
 #if ENABLE(DFG_JIT)
 
+#include "BasicBlockLocation.h"
 #include "CodeBlock.h"
 #include "DFGAbstractValue.h"
 #include "DFGAdjacencyList.h"
@@ -1788,6 +1789,11 @@
     {
         return reinterpret_cast<TypeLocation*>(m_opInfo);
     }
+
+    BasicBlockLocation* basicBlockLocation()
+    {
+        return reinterpret_cast<BasicBlockLocation*>(m_opInfo);
+    }
     
     void dumpChildren(PrintStream& out)
     {
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 9b1a4dd..8e79564 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -257,6 +257,7 @@
     macro(MakeRope, NodeResultJS) \
     macro(In, NodeResultBoolean | NodeMustGenerate | NodeClobbersWorld) \
     macro(ProfileType, NodeMustGenerate) \
+    macro(ProfileControlFlow, NodeMustGenerate) \
     \
     /* Nodes used for activations. Activation support works by having it anchored at */\
     /* epilgoues via TearOffActivation, and all CreateActivation nodes kept alive by */\
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index 0151daa..9d52d4f 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -647,6 +647,7 @@
         case ProfileWillCall:
         case ProfileDidCall:
         case ProfileType:
+        case ProfileControlFlow:
         case CheckHasInstance:
         case ThrowReferenceError:
         case ForceOSRExit:
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index 90eda2f..32c3a2b 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -200,6 +200,7 @@
     case ProfileWillCall:
     case ProfileDidCall:
     case ProfileType:
+    case ProfileControlFlow:
     case CheckHasInstance:
     case InstanceOf:
     case IsUndefined:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 6798a5f..e19d80d 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -4863,6 +4863,15 @@
         noResult(node);
         break;
     }
+    case ProfileControlFlow: {
+        BasicBlockLocation* basicBlockLocation = node->basicBlockLocation();
+        if (!basicBlockLocation->hasExecuted()) {
+            GPRTemporary scratch1(this);
+            basicBlockLocation->emitExecuteCode(m_jit, scratch1.gpr());
+        }
+        noResult(node);
+        break;
+    }
 
     case ForceOSRExit: {
         terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index c89f40e..62c5d71 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -4935,6 +4935,15 @@
         noResult(node);
         break;
     }
+    case ProfileControlFlow: {
+        BasicBlockLocation* basicBlockLocation = node->basicBlockLocation();
+        if (!basicBlockLocation->hasExecuted()) {
+            GPRTemporary scratch1(this);
+            basicBlockLocation->emitExecuteCode(m_jit, scratch1.gpr());
+        }
+        noResult(node);
+        break;
+    }
 
 #if ENABLE(FTL_JIT)        
     case CheckTierUpInLoop: {