Commit 4a81fa41 authored by fpizlo@apple.com's avatar fpizlo@apple.com

JSC should be able to report profiling data associated with the IR dumps and disassembly

https://bugs.webkit.org/show_bug.cgi?id=102999

Reviewed by Gavin Barraclough.

Source/JavaScriptCore: 

Added a new profiler to JSC. It's simply called "Profiler" in anticipation of it
ultimately replacing the previous profiling infrastructure. This profiler counts the
number of times that a bytecode executes in various engines, and will record both the
counts and all disassembly and bytecode dumps, into a database that can be at any
time turned into either a JS object using any global object or global data of your
choice, or can be turned into a JSON string, or saved to a file.
        
Currently the only use of this is the new '-p <file>' flag to the jsc command-line.
        
The profiler is always compiled in and normally incurs no execution time cost, but is
only activated when you create a Profiler::Database and install it in
JSGlobalData::m_perBytecodeProfiler. From that point on, all code blocks will be
compiled along with disassembly and bytecode dumps stored into the Profiler::Database,
and all code blocks will have execution counts, which are also stored in the database.
The database will continue to keep information about code blocks alive even after they
are otherwise GC'd.
        
This currently still has some glitches, like the fact that it only counts executions
in the JITs. Doing execution counting in the LLInt might require a bit of a rethink
about how the counting is expressed - currently it is implicit in bytecode, so there
is no easy way to "turn it on" in the LLInt. Also, right now there is no information
recorded about OSR exits or out-of-line stubs. But, even so, it's quite cool, and
gives you a peek into what JSC is doing that would otherwise not be possible.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::~CodeBlock):
* bytecode/CodeBlock.h:
(CodeBlock):
(JSC::CodeBlock::baselineVersion):
* bytecode/CodeOrigin.cpp:
(JSC::InlineCallFrame::baselineCodeBlock):
(JSC):
* bytecode/CodeOrigin.h:
(InlineCallFrame):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGDisassembler.cpp:
(JSC::DFG::Disassembler::dump):
(DFG):
(JSC::DFG::Disassembler::reportToProfiler):
(JSC::DFG::Disassembler::dumpHeader):
(JSC::DFG::Disassembler::append):
(JSC::DFG::Disassembler::createDumpList):
* dfg/DFGDisassembler.h:
(Disassembler):
(JSC::DFG::Disassembler::DumpedOp::DumpedOp):
(DumpedOp):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::Graph):
(JSC::DFG::Graph::dumpCodeOrigin):
(JSC::DFG::Graph::dump):
* dfg/DFGGraph.h:
(Graph):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::JITCompiler):
(JSC::DFG::JITCompiler::compile):
(JSC::DFG::JITCompiler::compileFunction):
* dfg/DFGNode.h:
(Node):
(JSC::DFG::Node::hasExecutionCounter):
(JSC::DFG::Node::executionCounter):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/JIT.cpp:
(JSC::JIT::JIT):
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompile):
* jit/JIT.h:
(JIT):
* jit/JITDisassembler.cpp:
(JSC::JITDisassembler::dump):
(JSC::JITDisassembler::reportToProfiler):
(JSC):
(JSC::JITDisassembler::dumpHeader):
(JSC::JITDisassembler::firstSlowLabel):
(JSC::JITDisassembler::dumpVectorForInstructions):
(JSC::JITDisassembler::dumpForInstructions):
(JSC::JITDisassembler::reportInstructions):
* jit/JITDisassembler.h:
(JITDisassembler):
(DumpedOp):
* jsc.cpp:
(CommandLine::CommandLine):
(CommandLine):
(printUsageStatement):
(CommandLine::parseArguments):
(jscmain):
* profiler/ProfilerBytecode.cpp: Added.
(Profiler):
(JSC::Profiler::Bytecode::toJS):
* profiler/ProfilerBytecode.h: Added.
(Profiler):
(Bytecode):
(JSC::Profiler::Bytecode::Bytecode):
(JSC::Profiler::Bytecode::bytecodeIndex):
(JSC::Profiler::Bytecode::description):
(JSC::Profiler::getBytecodeIndexForBytecode):
* profiler/ProfilerBytecodes.cpp: Added.
(Profiler):
(JSC::Profiler::Bytecodes::Bytecodes):
(JSC::Profiler::Bytecodes::~Bytecodes):
(JSC::Profiler::Bytecodes::indexForBytecodeIndex):
(JSC::Profiler::Bytecodes::forBytecodeIndex):
(JSC::Profiler::Bytecodes::dump):
(JSC::Profiler::Bytecodes::toJS):
* profiler/ProfilerBytecodes.h: Added.
(Profiler):
(Bytecodes):
(JSC::Profiler::Bytecodes::append):
(JSC::Profiler::Bytecodes::id):
(JSC::Profiler::Bytecodes::hash):
(JSC::Profiler::Bytecodes::size):
(JSC::Profiler::Bytecodes::at):
* profiler/ProfilerCompilation.cpp: Added.
(Profiler):
(JSC::Profiler::Compilation::Compilation):
(JSC::Profiler::Compilation::~Compilation):
(JSC::Profiler::Compilation::addDescription):
(JSC::Profiler::Compilation::executionCounterFor):
(JSC::Profiler::Compilation::toJS):
* profiler/ProfilerCompilation.h: Added.
(Profiler):
(Compilation):
(JSC::Profiler::Compilation::bytecodes):
(JSC::Profiler::Compilation::kind):
* profiler/ProfilerCompilationKind.cpp: Added.
(WTF):
(WTF::printInternal):
* profiler/ProfilerCompilationKind.h: Added.
(Profiler):
(WTF):
* profiler/ProfilerCompiledBytecode.cpp: Added.
(Profiler):
(JSC::Profiler::CompiledBytecode::CompiledBytecode):
(JSC::Profiler::CompiledBytecode::~CompiledBytecode):
(JSC::Profiler::CompiledBytecode::toJS):
* profiler/ProfilerCompiledBytecode.h: Added.
(Profiler):
(CompiledBytecode):
(JSC::Profiler::CompiledBytecode::originStack):
(JSC::Profiler::CompiledBytecode::description):
* profiler/ProfilerDatabase.cpp: Added.
(Profiler):
(JSC::Profiler::Database::Database):
(JSC::Profiler::Database::~Database):
(JSC::Profiler::Database::addBytecodes):
(JSC::Profiler::Database::ensureBytecodesFor):
(JSC::Profiler::Database::notifyDestruction):
(JSC::Profiler::Database::newCompilation):
(JSC::Profiler::Database::toJS):
(JSC::Profiler::Database::toJSON):
(JSC::Profiler::Database::save):
* profiler/ProfilerDatabase.h: Added.
(Profiler):
(Database):
* profiler/ProfilerExecutionCounter.h: Added.
(Profiler):
(ExecutionCounter):
(JSC::Profiler::ExecutionCounter::ExecutionCounter):
(JSC::Profiler::ExecutionCounter::address):
(JSC::Profiler::ExecutionCounter::count):
* profiler/ProfilerOrigin.cpp: Added.
(Profiler):
(JSC::Profiler::Origin::Origin):
(JSC::Profiler::Origin::dump):
(JSC::Profiler::Origin::toJS):
* profiler/ProfilerOrigin.h: Added.
(JSC):
(Profiler):
(Origin):
(JSC::Profiler::Origin::Origin):
(JSC::Profiler::Origin::operator!):
(JSC::Profiler::Origin::bytecodes):
(JSC::Profiler::Origin::bytecodeIndex):
(JSC::Profiler::Origin::operator!=):
(JSC::Profiler::Origin::operator==):
(JSC::Profiler::Origin::hash):
(JSC::Profiler::Origin::isHashTableDeletedValue):
(JSC::Profiler::OriginHash::hash):
(JSC::Profiler::OriginHash::equal):
(OriginHash):
(WTF):
* profiler/ProfilerOriginStack.cpp: Added.
(Profiler):
(JSC::Profiler::OriginStack::OriginStack):
(JSC::Profiler::OriginStack::~OriginStack):
(JSC::Profiler::OriginStack::append):
(JSC::Profiler::OriginStack::operator==):
(JSC::Profiler::OriginStack::hash):
(JSC::Profiler::OriginStack::dump):
(JSC::Profiler::OriginStack::toJS):
* profiler/ProfilerOriginStack.h: Added.
(JSC):
(Profiler):
(OriginStack):
(JSC::Profiler::OriginStack::OriginStack):
(JSC::Profiler::OriginStack::operator!):
(JSC::Profiler::OriginStack::size):
(JSC::Profiler::OriginStack::fromBottom):
(JSC::Profiler::OriginStack::fromTop):
(JSC::Profiler::OriginStack::isHashTableDeletedValue):
(JSC::Profiler::OriginStackHash::hash):
(JSC::Profiler::OriginStackHash::equal):
(OriginStackHash):
(WTF):
* runtime/CommonIdentifiers.h:
* runtime/ExecutionHarness.h:
(JSC::prepareForExecution):
(JSC::prepareFunctionForExecution):
* runtime/JSGlobalData.cpp:
(JSC::JSGlobalData::JSGlobalData):
(JSC::JSGlobalData::~JSGlobalData):
* runtime/JSGlobalData.h:
(JSGlobalData):
* runtime/Options.h:
(JSC):

Source/WTF: 

Made some minor changes to support the new profiler. FileOutputStream now has an
open() method, and DataLog uses it. StringPrintStream has a reset() method, which
allows you to reuse the same StringPrintStream for creating multiple strings.
SegmentedVector now has a const operator[]. And, WTFString now can do fromUTF8() on
a CString directly.

* wtf/DataLog.cpp:
(WTF::initializeLogFileOnce):
* wtf/FilePrintStream.cpp:
(WTF::FilePrintStream::open):
(WTF):
* wtf/FilePrintStream.h:
* wtf/SegmentedVector.h:
(WTF::SegmentedVector::at):
(SegmentedVector):
(WTF::SegmentedVector::operator[]):
* wtf/StringPrintStream.cpp:
(WTF::StringPrintStream::reset):
(WTF):
* wtf/StringPrintStream.h:
(StringPrintStream):
* wtf/text/WTFString.cpp:
(WTF::String::fromUTF8):
(WTF):
* wtf/text/WTFString.h:
(String):

Tools: 

Added a tool that allows you to grok the output from JSC's new profiler. Currently,
this still gets confused a bit about the execution counts of a method running
standalone versus a method running inlined, but other than that, it's pretty cool.
See the attached "sampling profiling session" attached to the bug to see it in
action.
        
Also had to feed EFL's build system.

* DumpRenderTree/efl/CMakeLists.txt:
* Scripts/display-profiler-output: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@136601 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent a2767ff3
......@@ -172,6 +172,23 @@ SET(JavaScriptCore_SOURCES
parser/ParserArena.cpp
parser/SourceProviderCache.cpp
profiler/ProfilerBytecode.cpp
profiler/ProfilerBytecode.h
profiler/ProfilerBytecodes.cpp
profiler/ProfilerBytecodes.h
profiler/ProfilerCompilation.cpp
profiler/ProfilerCompilation.h
profiler/ProfilerCompilationKind.cpp
profiler/ProfilerCompilationKind.h
profiler/ProfilerCompiledBytecode.cpp
profiler/ProfilerCompiledBytecode.h
profiler/ProfilerDatabase.cpp
profiler/ProfilerDatabase.h
profiler/ProfilerExecutionCounter.h
profiler/ProfilerOrigin.cpp
profiler/ProfilerOrigin.h
profiler/ProfilerOriginStack.cpp
profiler/ProfilerOriginStack.h
profiler/Profile.cpp
profiler/ProfileGenerator.cpp
profiler/ProfileNode.cpp
......
This diff is collapsed.
......@@ -471,6 +471,23 @@ javascriptcore_sources += \
Source/JavaScriptCore/parser/SourceProviderCacheItem.h \
Source/JavaScriptCore/parser/SyntaxChecker.h \
Source/JavaScriptCore/profiler/CallIdentifier.h \
Source/JavaScriptCore/profiler/ProfilerBytecode.cpp \
Source/JavaScriptCore/profiler/ProfilerBytecode.h \
Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp \
Source/JavaScriptCore/profiler/ProfilerBytecodes.h \
Source/JavaScriptCore/profiler/ProfilerCompilation.cpp \
Source/JavaScriptCore/profiler/ProfilerCompilation.h \
Source/JavaScriptCore/profiler/ProfilerCompilationKind.cpp \
Source/JavaScriptCore/profiler/ProfilerCompilationKind.h \
Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp \
Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.h \
Source/JavaScriptCore/profiler/ProfilerDatabase.cpp \
Source/JavaScriptCore/profiler/ProfilerDatabase.h \
Source/JavaScriptCore/profiler/ProfilerExecutionCounter.h \
Source/JavaScriptCore/profiler/ProfilerOrigin.cpp \
Source/JavaScriptCore/profiler/ProfilerOrigin.h \
Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp \
Source/JavaScriptCore/profiler/ProfilerOriginStack.h \
Source/JavaScriptCore/profiler/Profile.cpp \
Source/JavaScriptCore/profiler/ProfileGenerator.cpp \
Source/JavaScriptCore/profiler/ProfileGenerator.h \
......
......@@ -5,6 +5,7 @@ EXPORTS
??0Collator@WTF@@QAE@PBD@Z
??0CString@WTF@@QAE@PBD@Z
??0CString@WTF@@QAE@PBDI@Z
??0Database@Profiler@JSC@@QAE@AAVJSGlobalData@2@@Z
??0DateInstance@JSC@@IAE@PAVExecState@1@PAVStructure@1@@Z
??0DefaultGCActivityCallback@JSC@@QAE@PAVHeap@1@@Z
??0DropAllLocks@JSLock@JSC@@QAE@PAVExecState@2@@Z
......@@ -34,6 +35,7 @@ EXPORTS
??1ArrayBufferView@WTF@@UAE@XZ
??1ClientData@JSGlobalData@JSC@@UAE@XZ
??1Collator@WTF@@QAE@XZ
??1Database@Profiler@JSC@@QAE@XZ
??1Debugger@JSC@@UAE@XZ
??1DropAllLocks@JSLock@JSC@@QAE@XZ
??1ErrorHandlingMode@Interpreter@JSC@@QAE@XZ
......@@ -341,6 +343,7 @@ EXPORTS
?restoreAll@Profile@JSC@@QAEXXZ
?retrieveCallerFromVMCode@Interpreter@JSC@@QBE?AVJSValue@2@PAVExecState@2@PAVJSFunction@2@@Z
?retrieveLastCaller@Interpreter@JSC@@QBEXPAVExecState@2@AAH1AAVString@WTF@@AAVJSValue@2@@Z
?save@Database@Profiler@JSC@@QBE_NPBD@Z
?setConfigurable@PropertyDescriptor@JSC@@QAEX_N@Z
?setDescriptor@PropertyDescriptor@JSC@@QAEXVJSValue@2@I@Z
?setEnumerable@PropertyDescriptor@JSC@@QAEX_N@Z
......
......@@ -1525,6 +1525,74 @@
RelativePath="..\..\profiler\CallIdentifier.h"
>
</File>
<File
RelativePath="..\..\profiler\ProfilerBytecode.cpp"
>
</File>
<File
RelativePath="..\..\profiler\ProfilerBytecode.h"
>
</File>
<File
RelativePath="..\..\profiler\ProfilerBytecodes.cpp"
>
</File>
<File
RelativePath="..\..\profiler\ProfilerBytecodes.h"
>
</File>
<File
RelativePath="..\..\profiler\ProfilerCompilation.cpp"
>
</File>
<File
RelativePath="..\..\profiler\ProfilerCompilation.h"
>
</File>
<File
RelativePath="..\..\profiler\ProfilerCompilationKind.cpp"
>
</File>
<File
RelativePath="..\..\profiler\ProfilerCompilationKind.h"
>
</File>
<File
RelativePath="..\..\profiler\ProfilerCompiledBytecode.cpp"
>
</File>
<File
RelativePath="..\..\profiler\ProfilerCompiledBytecode.h"
>
</File>
<File
RelativePath="..\..\profiler\ProfilerDatabase.cpp"
>
</File>
<File
RelativePath="..\..\profiler\ProfilerDatabase.h"
>
</File>
<File
RelativePath="..\..\profiler\ProfilerExecutionCounter.h"
>
</File>
<File
RelativePath="..\..\profiler\ProfilerOrigin.cpp"
>
</File>
<File
RelativePath="..\..\profiler\ProfilerOrigin.h"
>
</File>
<File
RelativePath="..\..\profiler\ProfilerOriginStack.cpp"
>
</File>
<File
RelativePath="..\..\profiler\ProfilerOriginStack.h"
>
</File>
<File
RelativePath="..\..\profiler\Profile.cpp"
>
......
......@@ -182,6 +182,23 @@ SOURCES += \
parser/ParserArena.cpp \
parser/Parser.cpp \
parser/SourceProviderCache.cpp \
profiler/ProfilerBytecode.cpp \
profiler/ProfilerBytecode.h \
profiler/ProfilerBytecodes.cpp \
profiler/ProfilerBytecodes.h \
profiler/ProfilerCompilation.cpp \
profiler/ProfilerCompilation.h \
profiler/ProfilerCompilationKind.cpp \
profiler/ProfilerCompilationKind.h \
profiler/ProfilerCompiledBytecode.cpp \
profiler/ProfilerCompiledBytecode.h \
profiler/ProfilerDatabase.cpp \
profiler/ProfilerDatabase.h \
profiler/ProfilerExecutionCounter.h \
profiler/ProfilerOrigin.cpp \
profiler/ProfilerOrigin.h \
profiler/ProfilerOriginStack.cpp \
profiler/ProfilerOriginStack.h \
profiler/Profile.cpp \
profiler/ProfileGenerator.cpp \
profiler/ProfileNode.cpp \
......
......@@ -1918,6 +1918,9 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
CodeBlock::~CodeBlock()
{
if (m_globalData->m_perBytecodeProfiler)
m_globalData->m_perBytecodeProfiler->notifyDestruction(this);
#if ENABLE(DFG_JIT)
// Remove myself from the set of DFG code blocks. Note that I may not be in this set
// (because I'm not a DFG code block), in which case this is a no-op anyway.
......
......@@ -160,6 +160,11 @@ namespace JSC {
ASSERT(JITCode::isBaselineCode(result->getJITType()));
return result;
}
#else
CodeBlock* baselineVersion()
{
return this;
}
#endif
void visitAggregate(SlotVisitor&);
......
......@@ -26,6 +26,7 @@
#include "config.h"
#include "CodeOrigin.h"
#include "CodeBlock.h"
#include "Executable.h"
namespace JSC {
......@@ -73,6 +74,11 @@ CodeBlockHash InlineCallFrame::hash() const
return executable->hashFor(specializationKind());
}
CodeBlock* InlineCallFrame::baselineCodeBlock() const
{
return jsCast<FunctionExecutable*>(executable.get())->baselineCodeBlockFor(specializationKind());
}
void InlineCallFrame::dump(PrintStream& out) const
{
out.print("#", hash(), ":<", RawPointer(executable.get()), ", bc#", caller.bytecodeIndex, ", ", specializationKind(), ">");
......
......@@ -108,6 +108,8 @@ struct InlineCallFrame {
CodeBlockHash hash() const;
CodeBlock* baselineCodeBlock() const;
void dump(PrintStream&) const;
};
......
......@@ -1735,6 +1735,7 @@ bool AbstractState::execute(unsigned indexInBlock)
case Phantom:
case InlineStart:
case Nop:
case CountExecution:
node.setCanExit(false);
break;
......
......@@ -2114,6 +2114,12 @@ bool ByteCodeParser::parseBlock(unsigned limit)
Instruction* currentInstruction = instructionsBegin + m_currentIndex;
m_currentInstruction = currentInstruction; // Some methods want to use this, and we'd rather not thread it through calls.
OpcodeID opcodeID = interpreter->getOpcodeID(currentInstruction->u.opcode);
if (m_graph.m_compilation) {
addToGraph(CountExecution, OpInfo(m_graph.m_compilation->executionCounterFor(
Profiler::OriginStack(*m_globalData->m_perBytecodeProfiler, m_codeBlock, currentCodeOrigin()))));
}
switch (opcodeID) {
// === Function entry opcodes ===
......
......@@ -42,10 +42,53 @@ Disassembler::Disassembler(Graph& graph)
void Disassembler::dump(PrintStream& out, LinkBuffer& linkBuffer)
{
m_graph.m_dominators.computeIfNecessary(m_graph);
Vector<DumpedOp> ops = createDumpList(linkBuffer);
for (unsigned i = 0; i < ops.size(); ++i)
out.print(ops[i].text);
}
void Disassembler::dump(LinkBuffer& linkBuffer)
{
dump(WTF::dataFile(), linkBuffer);
}
void Disassembler::reportToProfiler(Profiler::Compilation* compilation, LinkBuffer& linkBuffer)
{
Vector<DumpedOp> ops = createDumpList(linkBuffer);
for (unsigned i = 0; i < ops.size(); ++i) {
Profiler::OriginStack stack;
if (ops[i].codeOrigin.isSet())
stack = Profiler::OriginStack(*m_graph.m_globalData.m_perBytecodeProfiler, m_graph.m_codeBlock, ops[i].codeOrigin);
compilation->addDescription(Profiler::CompiledBytecode(stack, ops[i].text));
}
}
void Disassembler::dumpHeader(PrintStream& out, LinkBuffer& linkBuffer)
{
out.print("Generated DFG JIT code for ", CodeBlockWithJITType(m_graph.m_codeBlock, JITCode::DFGJIT), ", instruction count = ", m_graph.m_codeBlock->instructionCount(), ":\n");
out.print(" Code at [", RawPointer(linkBuffer.debugAddress()), ", ", RawPointer(static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize()), "):\n");
}
void Disassembler::append(Vector<Disassembler::DumpedOp>& result, StringPrintStream& out, CodeOrigin& previousOrigin)
{
result.append(DumpedOp(previousOrigin, out.toCString()));
previousOrigin = CodeOrigin();
out.reset();
}
Vector<Disassembler::DumpedOp> Disassembler::createDumpList(LinkBuffer& linkBuffer)
{
StringPrintStream out;
Vector<DumpedOp> result;
CodeOrigin previousOrigin = CodeOrigin();
dumpHeader(out, linkBuffer);
append(result, out, previousOrigin);
m_graph.m_dominators.computeIfNecessary(m_graph);
const char* prefix = " ";
const char* disassemblyPrefix = " ";
......@@ -57,7 +100,9 @@ void Disassembler::dump(PrintStream& out, LinkBuffer& linkBuffer)
if (!block)
continue;
dumpDisassembly(out, disassemblyPrefix, linkBuffer, previousLabel, m_labelForBlockIndex[blockIndex], lastNodeIndex);
append(result, out, previousOrigin);
m_graph.dumpBlockHeader(out, prefix, blockIndex, Graph::DumpLivePhisOnly);
append(result, out, previousOrigin);
NodeIndex lastNodeIndexForDisassembly = block->at(0);
for (size_t i = 0; i < block->size(); ++i) {
if (!m_graph[block->at(i)].willHaveCodeGenOrOSR() && !Options::showAllDFGNodes())
......@@ -76,20 +121,25 @@ void Disassembler::dump(PrintStream& out, LinkBuffer& linkBuffer)
currentLabel = m_endOfMainPath;
}
dumpDisassembly(out, disassemblyPrefix, linkBuffer, previousLabel, currentLabel, lastNodeIndexForDisassembly);
m_graph.dumpCodeOrigin(out, prefix, lastNodeIndex, block->at(i));
append(result, out, previousOrigin);
previousOrigin = m_graph[block->at(i)].codeOrigin;
if (m_graph.dumpCodeOrigin(out, prefix, lastNodeIndex, block->at(i))) {
append(result, out, previousOrigin);
previousOrigin = m_graph[block->at(i)].codeOrigin;
}
m_graph.dump(out, prefix, block->at(i));
lastNodeIndex = block->at(i);
lastNodeIndexForDisassembly = block->at(i);
}
}
dumpDisassembly(out, disassemblyPrefix, linkBuffer, previousLabel, m_endOfMainPath, lastNodeIndex);
append(result, out, previousOrigin);
out.print(prefix, "(End Of Main Path)\n");
append(result, out, previousOrigin);
dumpDisassembly(out, disassemblyPrefix, linkBuffer, previousLabel, m_endOfCode, NoNode);
}
void Disassembler::dump(LinkBuffer& linkBuffer)
{
dump(WTF::dataFile(), linkBuffer);
append(result, out, previousOrigin);
return result;
}
void Disassembler::dumpDisassembly(PrintStream& out, const char* prefix, LinkBuffer& linkBuffer, MacroAssembler::Label& previousLabel, MacroAssembler::Label currentLabel, NodeIndex context)
......
......@@ -33,6 +33,7 @@
#include "DFGCommon.h"
#include "LinkBuffer.h"
#include "MacroAssembler.h"
#include <wtf/StringPrintStream.h>
#include <wtf/Vector.h>
namespace JSC { namespace DFG {
......@@ -64,8 +65,24 @@ public:
void dump(PrintStream&, LinkBuffer&);
void dump(LinkBuffer&);
void reportToProfiler(Profiler::Compilation*, LinkBuffer&);
private:
void dumpHeader(PrintStream&, LinkBuffer&);
struct DumpedOp {
DumpedOp(CodeOrigin codeOrigin, CString text)
: codeOrigin(codeOrigin)
, text(text)
{
}
CodeOrigin codeOrigin;
CString text;
};
void append(Vector<DumpedOp>&, StringPrintStream&, CodeOrigin&);
Vector<DumpedOp> createDumpList(LinkBuffer&);
void dumpDisassembly(PrintStream&, const char* prefix, LinkBuffer&, MacroAssembler::Label& previousLabel, MacroAssembler::Label currentLabel, NodeIndex context);
Graph& m_graph;
......
......@@ -43,6 +43,7 @@ static const char* dfgOpNames[] = {
Graph::Graph(JSGlobalData& globalData, CodeBlock* codeBlock, unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues)
: m_globalData(globalData)
, m_codeBlock(codeBlock)
, m_compilation(globalData.m_perBytecodeProfiler ? globalData.m_perBytecodeProfiler->newCompilation(codeBlock, Profiler::DFG) : 0)
, m_profiledBlock(codeBlock->alternative())
, m_hasArguments(false)
, m_osrEntryBytecodeIndex(osrEntryBytecodeIndex)
......@@ -63,15 +64,15 @@ static void printWhiteSpace(PrintStream& out, unsigned amount)
out.print(" ");
}
void Graph::dumpCodeOrigin(PrintStream& out, const char* prefix, NodeIndex prevNodeIndex, NodeIndex nodeIndex)
bool Graph::dumpCodeOrigin(PrintStream& out, const char* prefix, NodeIndex prevNodeIndex, NodeIndex nodeIndex)
{
if (prevNodeIndex == NoNode)
return;
return false;
Node& currentNode = at(nodeIndex);
Node& previousNode = at(prevNodeIndex);
if (previousNode.codeOrigin.inlineCallFrame == currentNode.codeOrigin.inlineCallFrame)
return;
return false;
Vector<CodeOrigin> previousInlineStack = previousNode.codeOrigin.inlineStack();
Vector<CodeOrigin> currentInlineStack = currentNode.codeOrigin.inlineStack();
......@@ -84,11 +85,14 @@ void Graph::dumpCodeOrigin(PrintStream& out, const char* prefix, NodeIndex prevN
}
}
bool hasPrinted = false;
// Print the pops.
for (unsigned i = previousInlineStack.size(); i-- > indexOfDivergence;) {
out.print(prefix);
printWhiteSpace(out, i * 2);
out.print("<-- ", *previousInlineStack[i].inlineCallFrame, "\n");
hasPrinted = true;
}
// Print the pushes.
......@@ -96,7 +100,10 @@ void Graph::dumpCodeOrigin(PrintStream& out, const char* prefix, NodeIndex prevN
out.print(prefix);
printWhiteSpace(out, i * 2);
out.print("--> ", *currentInlineStack[i].inlineCallFrame, "\n");
hasPrinted = true;
}
return hasPrinted;
}
int Graph::amountOfNodeWhiteSpace(Node& node)
......@@ -254,6 +261,13 @@ void Graph::dump(PrintStream& out, const char* prefix, NodeIndex nodeIndex)
if (hasPrinted)
out.print(", ");
out.print(indexingTypeToString(node.indexingType()));
hasPrinted = true;
}
if (node.hasExecutionCounter()) {
if (hasPrinted)
out.print(", ");
out.print(RawPointer(node.executionCounter()));
hasPrinted = true;
}
if (op == JSConstant) {
out.print(hasPrinted ? ", " : "", "$", node.constantNumber());
......
......@@ -199,8 +199,8 @@ public:
static void printNodeWhiteSpace(PrintStream&, Node&);
// Dump the code origin of the given node as a diff from the code origin of the
// preceding node.
void dumpCodeOrigin(PrintStream&, const char* prefix, NodeIndex, NodeIndex);
// preceding node. Returns true if anything was printed.
bool dumpCodeOrigin(PrintStream&, const char* prefix, NodeIndex, NodeIndex);
BlockIndex blockIndexForBytecodeOffset(Vector<BlockIndex>& blocks, unsigned bytecodeBegin);
......@@ -671,6 +671,7 @@ public:
JSGlobalData& m_globalData;
CodeBlock* m_codeBlock;
Profiler::Compilation* m_compilation;
CodeBlock* m_profiledBlock;
Vector< OwnPtr<BasicBlock> , 8> m_blocks;
......
......@@ -45,7 +45,7 @@ JITCompiler::JITCompiler(Graph& dfg)
, m_graph(dfg)
, m_currentCodeOriginIndex(0)
{
if (shouldShowDisassembly())
if (shouldShowDisassembly() || m_graph.m_globalData.m_perBytecodeProfiler)
m_disassembler = adoptPtr(new Disassembler(dfg));
}
......@@ -236,8 +236,10 @@ bool JITCompiler::compile(JITCode& entry)
link(linkBuffer);
speculative.linkOSREntries(linkBuffer);
if (m_disassembler)
if (shouldShowDisassembly())
m_disassembler->dump(linkBuffer);
if (m_graph.m_compilation)
m_disassembler->reportToProfiler(m_graph.m_compilation, linkBuffer);
entry = JITCode(
linkBuffer.finalizeCodeWithoutDisassembly(),
......@@ -327,8 +329,10 @@ bool JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWi
linkBuffer.link(callStackCheck, cti_stack_check);
linkBuffer.link(callArityCheck, m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck);
if (m_disassembler)
if (shouldShowDisassembly())
m_disassembler->dump(linkBuffer);
if (m_graph.m_compilation)
m_disassembler->reportToProfiler(m_graph.m_compilation, linkBuffer);
entryWithArityCheck = linkBuffer.locationOf(arityCheck);
entry = JITCode(
......
......@@ -859,6 +859,16 @@ struct Node {
ASSERT(hasArgumentPositionStart());
return m_opInfo;
}
bool hasExecutionCounter()
{
return op() == CountExecution;
}
Profiler::ExecutionCounter* executionCounter()
{
return bitwise_cast<Profiler::ExecutionCounter*>(m_opInfo);
}
bool shouldGenerate()
{
......
......@@ -245,6 +245,9 @@ namespace JSC { namespace DFG {
\
macro(GarbageValue, NodeResultJS | NodeClobbersWorld) \
\
/* Count execution. */\
macro(CountExecution, NodeMustGenerate) \
\
/* This is a pseudo-terminal. It means that execution should fall out of DFG at */\
/* this point, but execution does continue in the basic block - just in a */\
/* different compiler. */\
......
......@@ -771,6 +771,7 @@ private:
case Phantom:
case InlineStart:
case Nop:
case CountExecution:
break;
case LastNodeType:
......
......@@ -5044,6 +5044,10 @@ void SpeculativeJIT::compile(Node& node)
break;
}
case CountExecution:
m_jit.add64(TrustedImm32(1), MacroAssembler::AbsoluteAddress(node.executionCounter()->address()));
break;
case Phantom:
// This is a no-op.
noResult(m_compileIndex);
......
......@@ -4912,6 +4912,10 @@ void SpeculativeJIT::compile(Node& node)
case NewFunctionExpression:
compileNewFunctionExpression(node);
break;
case CountExecution:
m_jit.add64(TrustedImm32(1), MacroAssembler::AbsoluteAddress(node.executionCounter()->address()));
break;
case GarbageValue:
// We should never get to the point of code emission for a GarbageValue
......
......@@ -89,6 +89,7 @@ JIT::JIT(JSGlobalData* globalData, CodeBlock* codeBlock)
, m_lastResultBytecodeRegister(std::numeric_limits<int>::max())
, m_jumpTargetsPosition(0)
#endif
, m_compilation(0)
#if USE(OS_RANDOMNESS)
, m_randomGenerator(cryptographicallyRandomNumber())
#else
......@@ -232,6 +233,13 @@ void JIT::privateCompileMainPass()
#if ENABLE(JIT_VERBOSE)
dataLogF("Old JIT emitting code for bc#%u at offset 0x%lx.\n", m_bytecodeOffset, (long)debugOffset());
#endif
if (m_compilation) {
add64(
TrustedImm32(1),
AbsoluteAddress(m_compilation->executionCounterFor(Profiler::OriginStack(Profiler::Origin(
m_compilation->bytecodes(), m_bytecodeOffset)))->address()));
}
switch (m_interpreter->getOpcodeID(currentInstruction->u.opcode)) {
DEFINE_BINARY_OP(op_del_by_val)
......@@ -631,8 +639,10 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo
}
#endif
if (Options::showDisassembly())
if (Options::showDisassembly() || m_globalData->m_perBytecodeProfiler)
m_disassembler = adoptPtr(new JITDisassembler(m_codeBlock));
if (m_globalData->m_perBytecodeProfiler)
m_compilation = m_globalData->m_perBytecodeProfiler->newCompilation(m_codeBlock, Profiler::Baseline);
if (m_disassembler)
m_disassembler->setStartOfCode(label());
......@@ -823,8 +833,10 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo
if (m_codeBlock->codeType() == FunctionCode && functionEntryArityCheck)
*functionEntryArityCheck = patchBuffer.locationOf(arityCheck);
if (m_disassembler)
if (Options::showDisassembly())