Baseline JIT's disassembly should be just as pretty as the DFG's
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Nov 2012 00:46:57 +0000 (00:46 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Nov 2012 00:46:57 +0000 (00:46 +0000)
https://bugs.webkit.org/show_bug.cgi?id=102873

Reviewed by Sam Weinig.

Integrated the CodeBlock's bytecode dumper with the JIT's disassembler. Also fixed
some type goof-ups (instructions are not in a Vector<Instruction> so using a Vector
iterator makes no sense) and stream-lined some things (you don't actually need a
full-fledged ExecState* to dump bytecode).

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::printUnaryOp):
(JSC::CodeBlock::printBinaryOp):
(JSC::CodeBlock::printConditionalJump):
(JSC::CodeBlock::printGetByIdOp):
(JSC::CodeBlock::printCallOp):
(JSC::CodeBlock::printPutByIdOp):
(JSC::CodeBlock::dump):
(JSC):
(JSC::CodeBlock::CodeBlock):
* bytecode/CodeBlock.h:
(CodeBlock):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::dumpCallFrame):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
(JSC::JIT::privateCompile):
* jit/JIT.h:
(JIT):
* jit/JITDisassembler.cpp: Added.
(JSC):
(JSC::JITDisassembler::JITDisassembler):
(JSC::JITDisassembler::~JITDisassembler):
(JSC::JITDisassembler::dump):
(JSC::JITDisassembler::dumpForInstructions):
(JSC::JITDisassembler::dumpDisassembly):
* jit/JITDisassembler.h: Added.
(JSC):
(JITDisassembler):
(JSC::JITDisassembler::setStartOfCode):
(JSC::JITDisassembler::setForBytecodeMainPath):
(JSC::JITDisassembler::setForBytecodeSlowPath):
(JSC::JITDisassembler::setEndOfSlowPath):
(JSC::JITDisassembler::setEndOfCode):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@135457 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Target.pri
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITDisassembler.cpp [new file with mode: 0644]
Source/JavaScriptCore/jit/JITDisassembler.h [new file with mode: 0644]

index 70a7702..e0f905a 100644 (file)
@@ -148,6 +148,7 @@ SET(JavaScriptCore_SOURCES
     jit/JITCall32_64.cpp
     jit/JITCall.cpp
     jit/JIT.cpp
+    jit/JITDisassembler.cpp
     jit/JITExceptions.cpp
     jit/JITOpcodes32_64.cpp
     jit/JITOpcodes.cpp
index 69041dc..cac4b0d 100644 (file)
@@ -1,3 +1,56 @@
+2012-11-20  Filip Pizlo  <fpizlo@apple.com>
+
+        Baseline JIT's disassembly should be just as pretty as the DFG's
+        https://bugs.webkit.org/show_bug.cgi?id=102873
+
+        Reviewed by Sam Weinig.
+
+        Integrated the CodeBlock's bytecode dumper with the JIT's disassembler. Also fixed
+        some type goof-ups (instructions are not in a Vector<Instruction> so using a Vector
+        iterator makes no sense) and stream-lined some things (you don't actually need a
+        full-fledged ExecState* to dump bytecode).
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Target.pri:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::printUnaryOp):
+        (JSC::CodeBlock::printBinaryOp):
+        (JSC::CodeBlock::printConditionalJump):
+        (JSC::CodeBlock::printGetByIdOp):
+        (JSC::CodeBlock::printCallOp):
+        (JSC::CodeBlock::printPutByIdOp):
+        (JSC::CodeBlock::dump):
+        (JSC):
+        (JSC::CodeBlock::CodeBlock):
+        * bytecode/CodeBlock.h:
+        (CodeBlock):
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::dumpCallFrame):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        (JSC::JIT::privateCompileSlowCases):
+        (JSC::JIT::privateCompile):
+        * jit/JIT.h:
+        (JIT):
+        * jit/JITDisassembler.cpp: Added.
+        (JSC):
+        (JSC::JITDisassembler::JITDisassembler):
+        (JSC::JITDisassembler::~JITDisassembler):
+        (JSC::JITDisassembler::dump):
+        (JSC::JITDisassembler::dumpForInstructions):
+        (JSC::JITDisassembler::dumpDisassembly):
+        * jit/JITDisassembler.h: Added.
+        (JSC):
+        (JITDisassembler):
+        (JSC::JITDisassembler::setStartOfCode):
+        (JSC::JITDisassembler::setForBytecodeMainPath):
+        (JSC::JITDisassembler::setForBytecodeSlowPath):
+        (JSC::JITDisassembler::setEndOfSlowPath):
+        (JSC::JITDisassembler::setEndOfCode):
+
 2012-11-21  Daniel Bates  <dbates@webkit.org>
 
         JavaScript fails to concatenate large strings
index fece9e6..7851e83 100644 (file)
@@ -398,6 +398,8 @@ javascriptcore_sources += \
        Source/JavaScriptCore/jit/JITCall.cpp \
        Source/JavaScriptCore/jit/JITCode.h \
        Source/JavaScriptCore/jit/JITCompilationEffort.h \
+       Source/JavaScriptCore/jit/JITDisassembler.cpp \
+       Source/JavaScriptCore/jit/JITDisassembler.h \
        Source/JavaScriptCore/jit/JITDriver.h \
        Source/JavaScriptCore/jit/JIT.cpp \
        Source/JavaScriptCore/jit/JIT.h \
index f3fe110..2ed724c 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\jit\JITDisassembler.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\jit\JITDisassembler.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\jit\JITExceptions.cpp"
                                >
                        </File>
index 2a8b726..9937518 100644 (file)
                0FA581BA150E952C00B9A2D9 /* DFGNodeFlags.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FA581B7150E952A00B9A2D9 /* DFGNodeFlags.cpp */; };
                0FA581BB150E953000B9A2D9 /* DFGNodeFlags.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FA581B8150E952A00B9A2D9 /* DFGNodeFlags.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FA581BC150E953000B9A2D9 /* DFGNodeType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FA581B9150E952A00B9A2D9 /* DFGNodeType.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FAF7EFD165BA91B000C8455 /* JITDisassembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FAF7EFA165BA919000C8455 /* JITDisassembler.cpp */; };
+               0FAF7EFE165BA91F000C8455 /* JITDisassembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FAF7EFB165BA919000C8455 /* JITDisassembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FB5467714F59B5C002C2989 /* LazyOperandValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB5467614F59AD1002C2989 /* LazyOperandValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FB5467914F5C46B002C2989 /* LazyOperandValueProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB5467814F5C468002C2989 /* LazyOperandValueProfile.cpp */; };
                0FB5467B14F5C7E1002C2989 /* MethodOfGettingAValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB5467A14F5C7D4002C2989 /* MethodOfGettingAValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FA581B7150E952A00B9A2D9 /* DFGNodeFlags.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGNodeFlags.cpp; path = dfg/DFGNodeFlags.cpp; sourceTree = "<group>"; };
                0FA581B8150E952A00B9A2D9 /* DFGNodeFlags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGNodeFlags.h; path = dfg/DFGNodeFlags.h; sourceTree = "<group>"; };
                0FA581B9150E952A00B9A2D9 /* DFGNodeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGNodeType.h; path = dfg/DFGNodeType.h; sourceTree = "<group>"; };
+               0FAF7EFA165BA919000C8455 /* JITDisassembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITDisassembler.cpp; sourceTree = "<group>"; };
+               0FAF7EFB165BA919000C8455 /* JITDisassembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITDisassembler.h; sourceTree = "<group>"; };
                0FB5467614F59AD1002C2989 /* LazyOperandValueProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LazyOperandValueProfile.h; sourceTree = "<group>"; };
                0FB5467814F5C468002C2989 /* LazyOperandValueProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LazyOperandValueProfile.cpp; sourceTree = "<group>"; };
                0FB5467A14F5C7D4002C2989 /* MethodOfGettingAValueProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MethodOfGettingAValueProfile.h; sourceTree = "<group>"; };
                                146FE51111A710430087AE66 /* JITCall32_64.cpp */,
                                86CCEFDD0F413F8900FD7F9E /* JITCode.h */,
                                0F0776BD14FF002800102332 /* JITCompilationEffort.h */,
+                               0FAF7EFA165BA919000C8455 /* JITDisassembler.cpp */,
+                               0FAF7EFB165BA919000C8455 /* JITDisassembler.h */,
                                0F21C26614BE5F5E00ADC64B /* JITDriver.h */,
                                0F46807F14BA572700BFE272 /* JITExceptions.cpp */,
                                0F46808014BA572700BFE272 /* JITExceptions.h */,
                                A7B601821639FD2A00372BA3 /* UnlinkedCodeBlock.h in Headers */,
                                A77F1822164088B200640A47 /* CodeCache.h in Headers */,
                                A77F1825164192C700640A47 /* ParserModes.h in Headers */,
+                               0FAF7EFE165BA91F000C8455 /* JITDisassembler.h in Headers */,
                                0F73D7AF165A143000ACAB71 /* ClosureCallStubRoutine.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                                0F8335B71639C1E6001443B5 /* ArrayAllocationProfile.cpp in Sources */,
                                A76F279415F13C9600517D67 /* UnlinkedCodeBlock.cpp in Sources */,
                                A77F1821164088B200640A47 /* CodeCache.cpp in Sources */,
+                               0FAF7EFD165BA91B000C8455 /* JITDisassembler.cpp in Sources */,
                                0F73D7AE165A142D00ACAB71 /* ClosureCallStubRoutine.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
index fb34a5e..43184c1 100644 (file)
@@ -154,6 +154,7 @@ SOURCES += \
     jit/JITCall.cpp \
     jit/JITCall32_64.cpp \
     jit/JIT.cpp \
+    jit/JITDisassembler.cpp \
     jit/JITExceptions.cpp \
     jit/JITOpcodes.cpp \
     jit/JITOpcodes32_64.cpp \
index 9ce6139..161996a 100644 (file)
@@ -164,7 +164,7 @@ NEVER_INLINE static const char* debugHookName(int debugHookID)
     return "";
 }
 
-void CodeBlock::printUnaryOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op)
+void CodeBlock::printUnaryOp(ExecState* exec, int location, const Instruction*& it, const char* op)
 {
     int r0 = (++it)->u.operand;
     int r1 = (++it)->u.operand;
@@ -173,7 +173,7 @@ void CodeBlock::printUnaryOp(ExecState* exec, int location, Vector<Instruction>:
     dumpBytecodeCommentAndNewLine(location);
 }
 
-void CodeBlock::printBinaryOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op)
+void CodeBlock::printBinaryOp(ExecState* exec, int location, const Instruction*& it, const char* op)
 {
     int r0 = (++it)->u.operand;
     int r1 = (++it)->u.operand;
@@ -182,7 +182,7 @@ void CodeBlock::printBinaryOp(ExecState* exec, int location, Vector<Instruction>
     dumpBytecodeCommentAndNewLine(location);
 }
 
-void CodeBlock::printConditionalJump(ExecState* exec, const Vector<Instruction>::const_iterator&, Vector<Instruction>::const_iterator& it, int location, const char* op)
+void CodeBlock::printConditionalJump(ExecState* exec, const Instruction*, const Instruction*& it, int location, const char* op)
 {
     int r0 = (++it)->u.operand;
     int offset = (++it)->u.operand;
@@ -190,7 +190,7 @@ void CodeBlock::printConditionalJump(ExecState* exec, const Vector<Instruction>:
     dumpBytecodeCommentAndNewLine(location);
 }
 
-void CodeBlock::printGetByIdOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it)
+void CodeBlock::printGetByIdOp(ExecState* exec, int location, const Instruction*& it)
 {
     const char* op;
     switch (exec->interpreter()->getOpcodeID(it->u.opcode)) {
@@ -396,7 +396,7 @@ void CodeBlock::printGetByIdCacheStatus(ExecState* exec, int location)
 #endif
 }
 
-void CodeBlock::printCallOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op, CacheDumpMode cacheDumpMode)
+void CodeBlock::printCallOp(ExecState* exec, int location, const Instruction*& it, const char* op, CacheDumpMode cacheDumpMode)
 {
     int func = (++it)->u.operand;
     int argCount = (++it)->u.operand;
@@ -426,7 +426,7 @@ void CodeBlock::printCallOp(ExecState* exec, int location, Vector<Instruction>::
     it += 2;
 }
 
-void CodeBlock::printPutByIdOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op)
+void CodeBlock::printPutByIdOp(ExecState* exec, int location, const Instruction*& it, const char* op)
 {
     int r0 = (++it)->u.operand;
     int id0 = (++it)->u.operand;
@@ -480,8 +480,12 @@ void CodeBlock::printStructures(const Instruction* vPC)
     ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_call) || vPC[0].u.opcode == interpreter->getOpcode(op_call_eval) || vPC[0].u.opcode == interpreter->getOpcode(op_construct));
 }
 
-void CodeBlock::dump(ExecState* exec)
+void CodeBlock::dump()
 {
+    // We only use the ExecState* for things that don't actually lead to JS execution,
+    // like converting a JSString to a String. Hence the globalExec is appropriate.
+    ExecState* exec = m_globalObject->globalExec();
+    
     size_t instructionCount = 0;
 
     for (size_t i = 0; i < instructions().size(); i += opcodeLengths[exec->interpreter()->getOpcodeID(instructions()[i].u.opcode)])
@@ -505,9 +509,9 @@ void CodeBlock::dump(ExecState* exec)
         dataLog("; activation in r%d", activationRegister());
     dataLog("\n\n");
 
-    Vector<Instruction>::const_iterator begin = instructions().begin();
-    Vector<Instruction>::const_iterator end = instructions().end();
-    for (Vector<Instruction>::const_iterator it = begin; it != end; ++it)
+    const Instruction* begin = instructions().begin();
+    const Instruction* end = instructions().end();
+    for (const Instruction* it = begin; it != end; ++it)
         dump(exec, begin, it);
 
     if (!m_identifiers.isEmpty()) {
@@ -603,7 +607,7 @@ void CodeBlock::dump(ExecState* exec)
     dataLog("\n");
 }
 
-void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it)
+void CodeBlock::dump(ExecState* exec, const Instruction* begin, const Instruction*& it)
 {
     int location = it - begin;
     switch (exec->interpreter()->getOpcodeID(it->u.opcode)) {
@@ -1454,6 +1458,13 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
     }
 }
 
+void CodeBlock::dump(unsigned bytecodeOffset)
+{
+    ExecState* exec = m_globalObject->globalExec();
+    const Instruction* it = instructions().begin() + bytecodeOffset;
+    dump(exec, instructions().begin(), it);
+}
+
 #if DUMP_CODE_BLOCK_STATISTICS
 static HashSet<CodeBlock*> liveCodeBlockSet;
 #endif
@@ -1881,7 +1892,7 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
     m_instructions = WTF::RefCountedArray<Instruction>(instructions);
 
     if (BytecodeGenerator::dumpsGeneratedCode())
-        dump(m_globalObject->globalExec());
+        dump();
     m_globalData->finishedCompiling(this);
 }
 
index 183ea1e..63a0363 100644 (file)
@@ -163,7 +163,8 @@ namespace JSC {
 
         static void dumpStatistics();
 
-        void dump(ExecState*);
+        void dump();
+        void dump(unsigned bytecodeOffset);
         void printStructures(const Instruction*);
         void printStructure(const char* name, const Instruction*, int operand);
 
@@ -1211,17 +1212,17 @@ namespace JSC {
                 m_constantRegisters[i].set(*m_globalData, ownerExecutable(), constants[i].get());
         }
 
-        void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&);
+        void dump(ExecState*, const Instruction* begin, const Instruction*&);
 
         CString registerName(ExecState*, int r) const;
-        void printUnaryOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op);
-        void printBinaryOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op);
-        void printConditionalJump(ExecState*, const Vector<Instruction>::const_iterator&, Vector<Instruction>::const_iterator&, int location, const char* op);
-        void printGetByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&);
+        void printUnaryOp(ExecState*, int location, const Instruction*&, const char* op);
+        void printBinaryOp(ExecState*, int location, const Instruction*&, const char* op);
+        void printConditionalJump(ExecState*, const Instruction*, const Instruction*&, int location, const char* op);
+        void printGetByIdOp(ExecState*, int location, const Instruction*&);
         void printGetByIdCacheStatus(ExecState*, int location);
         enum CacheDumpMode { DumpCaches, DontDumpCaches };
-        void printCallOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op, CacheDumpMode);
-        void printPutByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op);
+        void printCallOp(ExecState*, int location, const Instruction*&, const char* op, CacheDumpMode);
+        void printPutByIdOp(ExecState*, int location, const Instruction*&, const char* op);
         void visitStructures(SlotVisitor&, Instruction* vPC);
         
 #if ENABLE(DFG_JIT)
index 397ac84..8228139 100644 (file)
@@ -380,7 +380,7 @@ void Interpreter::dumpCallFrame(CallFrame*)
 
 void Interpreter::dumpCallFrame(CallFrame* callFrame)
 {
-    callFrame->codeBlock()->dump(callFrame);
+    callFrame->codeBlock()->dump();
     dumpRegisters(callFrame);
 }
 
index a73be38..8930a0f 100644 (file)
@@ -212,6 +212,8 @@ void JIT::privateCompileMainPass()
     m_callLinkInfoIndex = 0;
 
     for (m_bytecodeOffset = 0; m_bytecodeOffset < instructionCount; ) {
+        if (m_disassembler)
+            m_disassembler->setForBytecodeMainPath(m_bytecodeOffset, label());
         Instruction* currentInstruction = instructionsBegin + m_bytecodeOffset;
         ASSERT_WITH_MESSAGE(m_interpreter->isOpcode(currentInstruction->u.opcode), "privateCompileMainPass gone bad @ %d", m_bytecodeOffset);
 
@@ -451,6 +453,9 @@ void JIT::privateCompileSlowCases()
 #if ENABLE(JIT_VERBOSE)
         dataLog("Old JIT emitting slow code for bc#%u at offset 0x%lx.\n", m_bytecodeOffset, (long)debugOffset());
 #endif
+        
+        if (m_disassembler)
+            m_disassembler->setForBytecodeSlowPath(m_bytecodeOffset, label());
 
         switch (m_interpreter->getOpcodeID(currentInstruction->u.opcode)) {
         DEFINE_SLOWCASE_OP(op_add)
@@ -625,6 +630,12 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo
         break;
     }
 #endif
+    
+    if (Options::showDisassembly())
+        m_disassembler = adoptPtr(new JITDisassembler(m_codeBlock));
+    
+    if (m_disassembler)
+        m_disassembler->setStartOfCode(label());
 
     // Just add a little bit of randomness to the codegen
     if (m_randomGenerator.getUint32() & 1)
@@ -684,6 +695,9 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo
     privateCompileMainPass();
     privateCompileLinkPass();
     privateCompileSlowCases();
+    
+    if (m_disassembler)
+        m_disassembler->setEndOfSlowPath(label());
 
     Label arityCheck;
     if (m_codeBlock->codeType() == FunctionCode) {
@@ -713,6 +727,9 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo
     }
 
     ASSERT(m_jmpTable.isEmpty());
+    
+    if (m_disassembler)
+        m_disassembler->setEndOfCode(label());
 
     LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock, effort);
     if (patchBuffer.didFailToAllocate())
@@ -805,11 +822,11 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo
 
     if (m_codeBlock->codeType() == FunctionCode && functionEntryArityCheck)
         *functionEntryArityCheck = patchBuffer.locationOf(arityCheck);
+
+    if (m_disassembler)
+        m_disassembler->dump(patchBuffer);
     
-    CodeRef result = FINALIZE_CODE(
-        patchBuffer,
-        ("Baseline JIT code for CodeBlock %p, instruction count = %u",
-         m_codeBlock, m_codeBlock->instructionCount()));
+    CodeRef result = patchBuffer.finalizeCodeWithoutDisassembly();
     
     m_globalData->machineCodeBytesPerBytecodeWordForBaselineJIT.add(
         static_cast<double>(result.size()) /
index 01cb476..c0d60ad 100644 (file)
@@ -46,6 +46,7 @@
 #include "CodeBlock.h"
 #include "CompactJITCodeMap.h"
 #include "Interpreter.h"
+#include "JITDisassembler.h"
 #include "JSInterfaceJIT.h"
 #include "Opcode.h"
 #include "Profiler.h"
@@ -945,6 +946,7 @@ namespace JSC {
         int m_uninterruptedConstantSequenceBegin;
 #endif
 #endif
+        OwnPtr<JITDisassembler> m_disassembler;
         WeakRandom m_randomGenerator;
         static CodeRef stringGetByValStubGenerator(JSGlobalData*);
 
diff --git a/Source/JavaScriptCore/jit/JITDisassembler.cpp b/Source/JavaScriptCore/jit/JITDisassembler.cpp
new file mode 100644 (file)
index 0000000..ad5abf8
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "JITDisassembler.h"
+
+#if ENABLE(JIT)
+
+#include "CodeBlock.h"
+#include "JIT.h"
+
+namespace JSC {
+
+JITDisassembler::JITDisassembler(CodeBlock *codeBlock)
+    : m_codeBlock(codeBlock)
+    , m_labelForBytecodeIndexInMainPath(codeBlock->instructionCount())
+    , m_labelForBytecodeIndexInSlowPath(codeBlock->instructionCount())
+{
+}
+
+JITDisassembler::~JITDisassembler()
+{
+}
+
+void JITDisassembler::dump(LinkBuffer& linkBuffer)
+{
+    dataLog("Baseline JIT code for CodeBlock %p, instruction count = %u:\n", m_codeBlock, m_codeBlock->instructionCount());
+    dataLog("    Code at [%p, %p):\n", linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize());
+    dumpDisassembly(linkBuffer, m_startOfCode, m_labelForBytecodeIndexInMainPath[0]);
+    
+    MacroAssembler::Label firstSlowLabel;
+    for (unsigned i = 0; i < m_labelForBytecodeIndexInSlowPath.size(); ++i) {
+        if (m_labelForBytecodeIndexInSlowPath[i].isSet()) {
+            firstSlowLabel = m_labelForBytecodeIndexInSlowPath[i];
+            break;
+        }
+    }
+    dumpForInstructions(linkBuffer, "    ", m_labelForBytecodeIndexInMainPath, firstSlowLabel.isSet() ? firstSlowLabel : m_endOfSlowPath);
+    dataLog("    (End Of Main Path)\n");
+    dumpForInstructions(linkBuffer, "    (S) ", m_labelForBytecodeIndexInSlowPath, m_endOfSlowPath);
+    dataLog("    (End Of Slow Path)\n");
+
+    dumpDisassembly(linkBuffer, m_endOfSlowPath, m_endOfCode);
+}
+
+void JITDisassembler::dumpForInstructions(LinkBuffer& linkBuffer, const char* prefix, Vector<MacroAssembler::Label>& labels, MacroAssembler::Label endLabel)
+{
+    for (unsigned i = 0 ; i < labels.size();) {
+        if (!labels[i].isSet()) {
+            i++;
+            continue;
+        }
+        dataLog("%s", prefix);
+        m_codeBlock->dump(i);
+        for (unsigned nextIndex = i + 1; ; nextIndex++) {
+            if (nextIndex >= labels.size()) {
+                dumpDisassembly(linkBuffer, labels[i], endLabel);
+                return;
+            }
+            if (labels[nextIndex].isSet()) {
+                dumpDisassembly(linkBuffer, labels[i], labels[nextIndex]);
+                i = nextIndex;
+                break;
+            }
+        }
+    }
+}
+
+void JITDisassembler::dumpDisassembly(LinkBuffer& linkBuffer, MacroAssembler::Label from, MacroAssembler::Label to)
+{
+    CodeLocationLabel fromLocation = linkBuffer.locationOf(from);
+    CodeLocationLabel toLocation = linkBuffer.locationOf(to);
+    if (tryToDisassemble(fromLocation, bitwise_cast<uintptr_t>(toLocation.executableAddress()) - bitwise_cast<uintptr_t>(fromLocation.executableAddress()), "        ", WTF::dataFile()))
+        return;
+    
+    dataLog("        disassembly not available for range %p...%p\n", fromLocation.executableAddress(), toLocation.executableAddress());
+}
+
+} // namespace JSC
+
+#endif // ENABLE(JIT)
+
diff --git a/Source/JavaScriptCore/jit/JITDisassembler.h b/Source/JavaScriptCore/jit/JITDisassembler.h
new file mode 100644 (file)
index 0000000..f8e917d
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef JITDisassembler_h
+#define JITDisassembler_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(JIT)
+
+#include "LinkBuffer.h"
+#include "MacroAssembler.h"
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+class CodeBlock;
+
+class JITDisassembler {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    JITDisassembler(CodeBlock*);
+    ~JITDisassembler();
+    
+    void setStartOfCode(MacroAssembler::Label label) { m_startOfCode = label; }
+    void setForBytecodeMainPath(unsigned bytecodeIndex, MacroAssembler::Label label)
+    {
+        m_labelForBytecodeIndexInMainPath[bytecodeIndex] = label;
+    }
+    void setForBytecodeSlowPath(unsigned bytecodeIndex, MacroAssembler::Label label)
+    {
+        m_labelForBytecodeIndexInSlowPath[bytecodeIndex] = label;
+    }
+    void setEndOfSlowPath(MacroAssembler::Label label) { m_endOfSlowPath = label; }
+    void setEndOfCode(MacroAssembler::Label label) { m_endOfCode = label; }
+    
+    void dump(LinkBuffer&);
+
+private:
+    void dumpForInstructions(LinkBuffer&, const char* prefix, Vector<MacroAssembler::Label>& labels, MacroAssembler::Label endLabel);
+    void dumpDisassembly(LinkBuffer&, MacroAssembler::Label from, MacroAssembler::Label to);
+    
+    CodeBlock* m_codeBlock;
+    MacroAssembler::Label m_startOfCode;
+    Vector<MacroAssembler::Label> m_labelForBytecodeIndexInMainPath;
+    Vector<MacroAssembler::Label> m_labelForBytecodeIndexInSlowPath;
+    MacroAssembler::Label m_endOfSlowPath;
+    MacroAssembler::Label m_endOfCode;
+};
+
+} // namespace JSC
+
+#endif // ENABLE(JIT)
+
+#endif // JITDisassembler_h
+