Profiler should show bytecode dumps as they would have been visible to the JITs,...
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Dec 2012 00:21:43 +0000 (00:21 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Dec 2012 00:21:43 +0000 (00:21 +0000)
https://bugs.webkit.org/show_bug.cgi?id=104647

Reviewed by Oliver Hunt.

Source/JavaScriptCore:

Adds more profiling data to bytecode dumps, and adds the ability to do a secondary
bytecode dump for each JIT compilation of a code block. This is relevant because both
the bytecodes, and the profiling data, may change after some number of executions.

Also fixes some random dumping code to use PrintStream& rather than
static const char[thingy].

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* bytecode/ArrayProfile.cpp:
(JSC::dumpArrayModes):
(JSC::ArrayProfile::briefDescription):
* bytecode/ArrayProfile.h:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::printGetByIdOp):
(JSC::CodeBlock::printGetByIdCacheStatus):
(JSC::CodeBlock::printCallOp):
(JSC::CodeBlock::dumpValueProfiling):
(JSC::CodeBlock::dumpArrayProfiling):
(JSC::CodeBlock::dumpBytecode):
* bytecode/CodeBlock.h:
* bytecode/ValueProfile.h:
(JSC::ValueProfileBase::briefDescription):
* dfg/DFGAbstractValue.h:
(JSC::DFG::AbstractValue::dump):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseCodeBlock):
* jit/JIT.cpp:
(JSC::JIT::privateCompile):
* profiler/ProfilerBytecodeSequence.cpp: Added.
(JSC::Profiler::BytecodeSequence::BytecodeSequence):
(JSC::Profiler::BytecodeSequence::~BytecodeSequence):
(JSC::Profiler::BytecodeSequence::indexForBytecodeIndex):
(JSC::Profiler::BytecodeSequence::forBytecodeIndex):
(JSC::Profiler::BytecodeSequence::addSequenceProperties):
* profiler/ProfilerBytecodeSequence.h: Added.
(JSC::Profiler::BytecodeSequence::size):
(JSC::Profiler::BytecodeSequence::at):
* profiler/ProfilerBytecodes.cpp:
(JSC::Profiler::Bytecodes::Bytecodes):
(JSC::Profiler::Bytecodes::toJS):
* profiler/ProfilerBytecodes.h:
(JSC::Profiler::Bytecodes::instructionCount):
* profiler/ProfilerCompilation.cpp:
(JSC::Profiler::Compilation::addProfiledBytecodes):
(JSC::Profiler::Compilation::toJS):
* profiler/ProfilerCompilation.h:
(JSC::Profiler::Compilation::profiledBytecodesSize):
(JSC::Profiler::Compilation::profiledBytecodesAt):
* profiler/ProfilerDatabase.cpp:
(JSC::Profiler::Database::ensureBytecodesFor):
* profiler/ProfilerDatabase.h:
* profiler/ProfilerProfiledBytecodes.cpp: Added.
(JSC::Profiler::ProfiledBytecodes::ProfiledBytecodes):
(JSC::Profiler::ProfiledBytecodes::~ProfiledBytecodes):
(JSC::Profiler::ProfiledBytecodes::toJS):
* profiler/ProfilerProfiledBytecodes.h: Added.
(JSC::Profiler::ProfiledBytecodes::bytecodes):
* runtime/CommonIdentifiers.h:

Tools:

Added a "profiling" (or "p") command to show the profiling data that the JITs saw
for each JIT compilation of a code block.

Also added instruction counts in the "full" display and made the "full" display the
default thing you see.

* Scripts/display-profiler-output:

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

27 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/ArrayProfile.cpp
Source/JavaScriptCore/bytecode/ArrayProfile.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecode/ValueProfile.h
Source/JavaScriptCore/dfg/DFGAbstractValue.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp [new file with mode: 0644]
Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.h [new file with mode: 0644]
Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp
Source/JavaScriptCore/profiler/ProfilerBytecodes.h
Source/JavaScriptCore/profiler/ProfilerCompilation.cpp
Source/JavaScriptCore/profiler/ProfilerCompilation.h
Source/JavaScriptCore/profiler/ProfilerDatabase.cpp
Source/JavaScriptCore/profiler/ProfilerDatabase.h
Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp [new file with mode: 0644]
Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/CommonIdentifiers.h
Tools/ChangeLog
Tools/Scripts/display-profiler-output

index 1aeaebf..d0b2f19 100644 (file)
@@ -176,6 +176,7 @@ set(JavaScriptCore_SOURCES
 
     profiler/ProfilerBytecode.cpp
     profiler/ProfilerBytecode.h
+    profiler/ProfilerBytecodeSequence.cpp
     profiler/ProfilerBytecodes.cpp
     profiler/ProfilerBytecodes.h
     profiler/ProfilerCompilation.cpp
@@ -193,6 +194,7 @@ set(JavaScriptCore_SOURCES
     profiler/ProfilerOriginStack.h
     profiler/ProfilerOSRExit.cpp
     profiler/ProfilerOSRExitSite.cpp
+    profiler/ProfilerProfiledBytecodes.cpp
     profiler/Profile.cpp
     profiler/ProfileGenerator.cpp
     profiler/ProfileNode.cpp
index 8a114c1..56b2bef 100644 (file)
@@ -1,3 +1,73 @@
+2012-12-11  Filip Pizlo  <fpizlo@apple.com>
+
+        Profiler should show bytecode dumps as they would have been visible to the JITs, including the profiling data that the JITs would see
+        https://bugs.webkit.org/show_bug.cgi?id=104647
+
+        Reviewed by Oliver Hunt.
+
+        Adds more profiling data to bytecode dumps, and adds the ability to do a secondary
+        bytecode dump for each JIT compilation of a code block. This is relevant because both
+        the bytecodes, and the profiling data, may change after some number of executions.
+        
+        Also fixes some random dumping code to use PrintStream& rather than
+        static const char[thingy].
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Target.pri:
+        * bytecode/ArrayProfile.cpp:
+        (JSC::dumpArrayModes):
+        (JSC::ArrayProfile::briefDescription):
+        * bytecode/ArrayProfile.h:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::printGetByIdOp):
+        (JSC::CodeBlock::printGetByIdCacheStatus):
+        (JSC::CodeBlock::printCallOp):
+        (JSC::CodeBlock::dumpValueProfiling):
+        (JSC::CodeBlock::dumpArrayProfiling):
+        (JSC::CodeBlock::dumpBytecode):
+        * bytecode/CodeBlock.h:
+        * bytecode/ValueProfile.h:
+        (JSC::ValueProfileBase::briefDescription):
+        * dfg/DFGAbstractValue.h:
+        (JSC::DFG::AbstractValue::dump):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseCodeBlock):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompile):
+        * profiler/ProfilerBytecodeSequence.cpp: Added.
+        (JSC::Profiler::BytecodeSequence::BytecodeSequence):
+        (JSC::Profiler::BytecodeSequence::~BytecodeSequence):
+        (JSC::Profiler::BytecodeSequence::indexForBytecodeIndex):
+        (JSC::Profiler::BytecodeSequence::forBytecodeIndex):
+        (JSC::Profiler::BytecodeSequence::addSequenceProperties):
+        * profiler/ProfilerBytecodeSequence.h: Added.
+        (JSC::Profiler::BytecodeSequence::size):
+        (JSC::Profiler::BytecodeSequence::at):
+        * profiler/ProfilerBytecodes.cpp:
+        (JSC::Profiler::Bytecodes::Bytecodes):
+        (JSC::Profiler::Bytecodes::toJS):
+        * profiler/ProfilerBytecodes.h:
+        (JSC::Profiler::Bytecodes::instructionCount):
+        * profiler/ProfilerCompilation.cpp:
+        (JSC::Profiler::Compilation::addProfiledBytecodes):
+        (JSC::Profiler::Compilation::toJS):
+        * profiler/ProfilerCompilation.h:
+        (JSC::Profiler::Compilation::profiledBytecodesSize):
+        (JSC::Profiler::Compilation::profiledBytecodesAt):
+        * profiler/ProfilerDatabase.cpp:
+        (JSC::Profiler::Database::ensureBytecodesFor):
+        * profiler/ProfilerDatabase.h:
+        * profiler/ProfilerProfiledBytecodes.cpp: Added.
+        (JSC::Profiler::ProfiledBytecodes::ProfiledBytecodes):
+        (JSC::Profiler::ProfiledBytecodes::~ProfiledBytecodes):
+        (JSC::Profiler::ProfiledBytecodes::toJS):
+        * profiler/ProfilerProfiledBytecodes.h: Added.
+        (JSC::Profiler::ProfiledBytecodes::bytecodes):
+        * runtime/CommonIdentifiers.h:
+
 2012-12-11  Oswald Buddenhagen  <oswald.buddenhagen@digia.com>
 
         [Qt] delete dead include paths
index f4d20e1..4dec66a 100644 (file)
@@ -479,6 +479,8 @@ javascriptcore_sources += \
        Source/JavaScriptCore/profiler/CallIdentifier.h \
        Source/JavaScriptCore/profiler/ProfilerBytecode.cpp \
        Source/JavaScriptCore/profiler/ProfilerBytecode.h \
+       Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp \
+       Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.h \
        Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp \
        Source/JavaScriptCore/profiler/ProfilerBytecodes.h \
        Source/JavaScriptCore/profiler/ProfilerCompilation.cpp \
@@ -498,6 +500,8 @@ javascriptcore_sources += \
        Source/JavaScriptCore/profiler/ProfilerOSRExit.h \
        Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp \
        Source/JavaScriptCore/profiler/ProfilerOSRExitSite.h \
+       Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp \
+       Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.h \
        Source/JavaScriptCore/profiler/Profile.cpp \
        Source/JavaScriptCore/profiler/ProfileGenerator.cpp \
        Source/JavaScriptCore/profiler/ProfileGenerator.h \
index ddc84ee..3b466f0 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\profiler\ProfilerBytecodeSequence.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\profiler\ProfilerBytecodeSequence.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\profiler\ProfilerBytecodes.cpp"
                                >
                        </File>
                                >
                        </File>
                        <File
+                               RelativePath="..\..\profiler\ProfilerProfiledBytecodes.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\profiler\ProfilerProfiledBytecodes.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\profiler\Profile.cpp"
                                >
                        </File>
index eda1440..fc9c855 100644 (file)
                0F0CD4C215F1A6070032F1C0 /* PutDirectIndexMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0CD4C015F1A6040032F1C0 /* PutDirectIndexMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F0CD4C415F6B6BB0032F1C0 /* SparseArrayValueMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F0CD4C315F6B6B50032F1C0 /* SparseArrayValueMap.cpp */; };
                0F0FC45A14BD15F500B81154 /* LLIntCallLinkInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0FC45814BD15F100B81154 /* LLIntCallLinkInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0F13912916771C33009CCB07 /* ProfilerBytecodeSequence.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F13912416771C30009CCB07 /* ProfilerBytecodeSequence.cpp */; };
+               0F13912A16771C36009CCB07 /* ProfilerBytecodeSequence.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F13912516771C30009CCB07 /* ProfilerBytecodeSequence.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0F13912B16771C3A009CCB07 /* ProfilerProfiledBytecodes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F13912616771C30009CCB07 /* ProfilerProfiledBytecodes.cpp */; };
+               0F13912C16771C3D009CCB07 /* ProfilerProfiledBytecodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F13912716771C30009CCB07 /* ProfilerProfiledBytecodes.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F13E04E16164A1F00DC8DE7 /* IndexingType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F13E04C16164A1B00DC8DE7 /* IndexingType.cpp */; };
                0F15F15F14B7A73E005DE37D /* CommonSlowPaths.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F15F15D14B7A73A005DE37D /* CommonSlowPaths.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F16015D156198C900C2587C /* DFGArgumentsSimplificationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F16015A156198BF00C2587C /* DFGArgumentsSimplificationPhase.cpp */; };
                0F0CD4C015F1A6040032F1C0 /* PutDirectIndexMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutDirectIndexMode.h; sourceTree = "<group>"; };
                0F0CD4C315F6B6B50032F1C0 /* SparseArrayValueMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SparseArrayValueMap.cpp; sourceTree = "<group>"; };
                0F0FC45814BD15F100B81154 /* LLIntCallLinkInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLIntCallLinkInfo.h; sourceTree = "<group>"; };
+               0F13912416771C30009CCB07 /* ProfilerBytecodeSequence.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProfilerBytecodeSequence.cpp; path = profiler/ProfilerBytecodeSequence.cpp; sourceTree = "<group>"; };
+               0F13912516771C30009CCB07 /* ProfilerBytecodeSequence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProfilerBytecodeSequence.h; path = profiler/ProfilerBytecodeSequence.h; sourceTree = "<group>"; };
+               0F13912616771C30009CCB07 /* ProfilerProfiledBytecodes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProfilerProfiledBytecodes.cpp; path = profiler/ProfilerProfiledBytecodes.cpp; sourceTree = "<group>"; };
+               0F13912716771C30009CCB07 /* ProfilerProfiledBytecodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProfilerProfiledBytecodes.h; path = profiler/ProfilerProfiledBytecodes.h; sourceTree = "<group>"; };
                0F13E04C16164A1B00DC8DE7 /* IndexingType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IndexingType.cpp; sourceTree = "<group>"; };
                0F15F15D14B7A73A005DE37D /* CommonSlowPaths.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommonSlowPaths.h; sourceTree = "<group>"; };
                0F16015A156198BF00C2587C /* DFGArgumentsSimplificationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGArgumentsSimplificationPhase.cpp; path = dfg/DFGArgumentsSimplificationPhase.cpp; sourceTree = "<group>"; };
                                0FF72993166AD347000F5BA3 /* ProfilerBytecode.h */,
                                0FF72994166AD347000F5BA3 /* ProfilerBytecodes.cpp */,
                                0FF72995166AD347000F5BA3 /* ProfilerBytecodes.h */,
+                               0F13912416771C30009CCB07 /* ProfilerBytecodeSequence.cpp */,
+                               0F13912516771C30009CCB07 /* ProfilerBytecodeSequence.h */,
                                0FF72996166AD347000F5BA3 /* ProfilerCompilation.cpp */,
                                0FF72997166AD347000F5BA3 /* ProfilerCompilation.h */,
                                0FF72998166AD347000F5BA3 /* ProfilerCompilationKind.cpp */,
                                0FB105881675482E00F8AB6E /* ProfilerOSRExit.h */,
                                0FB105891675482E00F8AB6E /* ProfilerOSRExitSite.cpp */,
                                0FB1058A1675482E00F8AB6E /* ProfilerOSRExitSite.h */,
+                               0F13912616771C30009CCB07 /* ProfilerProfiledBytecodes.cpp */,
+                               0F13912716771C30009CCB07 /* ProfilerProfiledBytecodes.h */,
                        );
                        name = profiler;
                        sourceTree = "<group>";
                                0FB1058C1675483300F8AB6E /* ProfilerOSRExit.h in Headers */,
                                0FB1058E1675483A00F8AB6E /* ProfilerOSRExitSite.h in Headers */,
                                0FF60AC216740F8300029779 /* ReduceWhitespace.h in Headers */,
+                               0F13912A16771C36009CCB07 /* ProfilerBytecodeSequence.h in Headers */,
+                               0F13912C16771C3D009CCB07 /* ProfilerProfiledBytecodes.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                0FB1058B1675483100F8AB6E /* ProfilerOSRExit.cpp in Sources */,
                                0FB1058D1675483700F8AB6E /* ProfilerOSRExitSite.cpp in Sources */,
                                0FF60AC316740F8800029779 /* ReduceWhitespace.cpp in Sources */,
+                               0F13912916771C33009CCB07 /* ProfilerBytecodeSequence.cpp in Sources */,
+                               0F13912B16771C3A009CCB07 /* ProfilerProfiledBytecodes.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 03f85e7..e0c671f 100644 (file)
@@ -186,6 +186,7 @@ SOURCES += \
     parser/SourceProviderCache.cpp \
     profiler/ProfilerBytecode.cpp \
     profiler/ProfilerBytecode.h \
+    profiler/ProfilerBytecodeSequence.cpp \
     profiler/ProfilerBytecodes.cpp \
     profiler/ProfilerBytecodes.h \
     profiler/ProfilerCompilation.cpp \
@@ -203,6 +204,7 @@ SOURCES += \
     profiler/ProfilerOriginStack.h \
     profiler/ProfilerOSRExit.cpp \
     profiler/ProfilerOSRExitSite.cpp \
+    profiler/ProfilerProfiledBytecodes.cpp \
     profiler/Profile.cpp \
     profiler/ProfileGenerator.cpp \
     profiler/ProfileNode.cpp \
index 51baf33..4fa3096 100644 (file)
 
 #include "CodeBlock.h"
 #include <wtf/StringExtras.h>
+#include <wtf/StringPrintStream.h>
 
 namespace JSC {
 
-const char* arrayModesToString(ArrayModes arrayModes)
+void dumpArrayModes(PrintStream& out, ArrayModes arrayModes)
 {
-    if (!arrayModes)
-        return "0:<empty>";
+    if (!arrayModes) {
+        out.print("0:<empty>");
+        return;
+    }
     
-    if (arrayModes == ALL_ARRAY_MODES)
-        return "TOP";
-
-    bool isNonArray = !!(arrayModes & asArrayModes(NonArray));
-    bool isNonArrayWithContiguous = !!(arrayModes & asArrayModes(NonArrayWithContiguous));
-    bool isNonArrayWithArrayStorage = !!(arrayModes & asArrayModes(NonArrayWithArrayStorage));
-    bool isNonArrayWithSlowPutArrayStorage = !!(arrayModes & asArrayModes(NonArrayWithSlowPutArrayStorage));
-    bool isArray = !!(arrayModes & asArrayModes(ArrayClass));
-    bool isArrayWithContiguous = !!(arrayModes & asArrayModes(ArrayWithContiguous));
-    bool isArrayWithArrayStorage = !!(arrayModes & asArrayModes(ArrayWithArrayStorage));
-    bool isArrayWithSlowPutArrayStorage = !!(arrayModes & asArrayModes(ArrayWithSlowPutArrayStorage));
+    if (arrayModes == ALL_ARRAY_MODES) {
+        out.print("TOP");
+        return;
+    }
     
-    static char result[256];
-    snprintf(
-        result, sizeof(result),
-        "%u:%s%s%s%s%s%s%s%s",
-        arrayModes,
-        isNonArray ? "NonArray" : "",
-        isNonArrayWithContiguous ? "NonArrayWithContiguous" : "",
-        isNonArrayWithArrayStorage ? " NonArrayWithArrayStorage" : "",
-        isNonArrayWithSlowPutArrayStorage ? "NonArrayWithSlowPutArrayStorage" : "",
-        isArray ? "ArrayClass" : "",
-        isArrayWithContiguous ? "ArrayWithContiguous" : "",
-        isArrayWithArrayStorage ? " ArrayWithArrayStorage" : "",
-        isArrayWithSlowPutArrayStorage ? "ArrayWithSlowPutArrayStorage" : "");
+    out.print(arrayModes, ":");
     
-    return result;
+    if (arrayModes & asArrayModes(NonArray))
+        out.print("NonArray");
+    if (arrayModes & asArrayModes(NonArrayWithInt32))
+        out.print("NonArrayWithInt32");
+    if (arrayModes & asArrayModes(NonArrayWithDouble))
+        out.print("NonArrayWithDouble");
+    if (arrayModes & asArrayModes(NonArrayWithContiguous))
+        out.print("NonArrayWithContiguous");
+    if (arrayModes & asArrayModes(NonArrayWithArrayStorage))
+        out.print("NonArrayWithArrayStorage");
+    if (arrayModes & asArrayModes(NonArrayWithSlowPutArrayStorage))
+        out.print("NonArrayWithSlowPutArrayStorage");
+    if (arrayModes & asArrayModes(ArrayClass))
+        out.print("ArrayClass");
+    if (arrayModes & asArrayModes(ArrayWithUndecided))
+        out.print("ArrayWithUndecided");
+    if (arrayModes & asArrayModes(ArrayWithInt32))
+        out.print("ArrayWithInt32");
+    if (arrayModes & asArrayModes(ArrayWithDouble))
+        out.print("ArrayWithDouble");
+    if (arrayModes & asArrayModes(ArrayWithContiguous))
+        out.print("ArrayWithContiguous");
+    if (arrayModes & asArrayModes(ArrayWithArrayStorage))
+        out.print("ArrayWithArrayStorage");
+    if (arrayModes & asArrayModes(ArrayWithSlowPutArrayStorage))
+        out.print("ArrayWithSlowPutArrayStorage");
 }
 
 ArrayModes ArrayProfile::updatedObservedArrayModes() const
@@ -104,5 +113,58 @@ void ArrayProfile::computeUpdatedPrediction(CodeBlock* codeBlock, OperationInPro
     }
 }
 
+CString ArrayProfile::briefDescription(CodeBlock* codeBlock)
+{
+    computeUpdatedPrediction(codeBlock);
+    
+    StringPrintStream out;
+    
+    bool hasPrinted = false;
+    
+    if (m_observedArrayModes) {
+        if (hasPrinted)
+            out.print(", ");
+        out.print(ArrayModesDump(m_observedArrayModes));
+        hasPrinted = true;
+    }
+    
+    if (m_structureIsPolymorphic) {
+        if (hasPrinted)
+            out.print(", ");
+        out.print("struct = TOP");
+        hasPrinted = true;
+    } else if (m_expectedStructure) {
+        if (hasPrinted)
+            out.print(", ");
+        out.print("struct = ", RawPointer(m_expectedStructure));
+        hasPrinted = true;
+    }
+    
+    if (m_mayStoreToHole) {
+        if (hasPrinted)
+            out.print(", ");
+        out.print("Hole");
+        hasPrinted = true;
+    }
+    
+    if (m_mayInterceptIndexedAccesses) {
+        if (hasPrinted)
+            out.print(", ");
+        out.print("Intercept");
+        hasPrinted = true;
+    }
+    
+    if (m_usesOriginalArrayStructures) {
+        if (hasPrinted)
+            out.print(", ");
+        out.print("Original");
+        hasPrinted = true;
+    }
+    
+    UNUSED_PARAM(hasPrinted);
+    
+    return out.toCString();
+}
+
 } // namespace JSC
 
index 5116cd3..2ba2fbf 100644 (file)
@@ -67,7 +67,8 @@ inline ArrayModes arrayModeFromStructure(Structure* structure)
     return asArrayModes(structure->indexingType());
 }
 
-const char* arrayModesToString(ArrayModes);
+void dumpArrayModes(PrintStream&, ArrayModes);
+MAKE_PRINT_ADAPTOR(ArrayModesDump, ArrayModes, dumpArrayModes);
 
 inline bool mergeArrayModes(ArrayModes& left, ArrayModes right)
 {
@@ -170,6 +171,8 @@ public:
     
     bool usesOriginalArrayStructures() const { return m_usesOriginalArrayStructures; }
     
+    CString briefDescription(CodeBlock*);
+    
 private:
     friend class LLIntOffsetsExtractor;
     
index 79f9db8..92b48c6 100644 (file)
@@ -303,7 +303,7 @@ void CodeBlock::printGetByIdOp(PrintStream& out, ExecState* exec, int location,
     int r1 = (++it)->u.operand;
     int id0 = (++it)->u.operand;
     out.printf("[%4d] %s\t %s, %s, %s", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data());
-    it += 5;
+    it += 4; // Increment up to the value profiler.
 }
 
 #if ENABLE(JIT) || ENABLE(LLINT) // unused in some configurations
@@ -349,8 +349,7 @@ void CodeBlock::printGetByIdCacheStatus(PrintStream& out, ExecState* exec, int l
 #if ENABLE(LLINT)
     if (exec->interpreter()->getOpcodeID(instruction[0].u.opcode) == op_get_array_length)
         out.printf(" llint(array_length)");
-    else {
-        Structure* structure = instruction[4].u.structure.get();
+    else if (Structure* structure = instruction[4].u.structure.get()) {
         out.printf(" llint(");
         dumpStructure(out, "struct", exec, structure, ident);
         out.printf(")");
@@ -359,11 +358,10 @@ void CodeBlock::printGetByIdCacheStatus(PrintStream& out, ExecState* exec, int l
 
 #if ENABLE(JIT)
     if (numberOfStructureStubInfos()) {
-        out.printf(" jit(");
         StructureStubInfo& stubInfo = getStubInfo(location);
-        if (!stubInfo.seen)
-            out.printf("not seen");
-        else {
+        if (stubInfo.seen) {
+            out.printf(" jit(");
+            
             Structure* baseStructure = 0;
             Structure* prototypeStructure = 0;
             StructureChain* chain = 0;
@@ -449,8 +447,8 @@ void CodeBlock::printGetByIdCacheStatus(PrintStream& out, ExecState* exec, int l
                 }
                 out.printf("]");
             }
+            out.printf(")");
         }
-        out.printf(")");
     }
 #endif
 }
@@ -469,16 +467,13 @@ void CodeBlock::printCallOp(PrintStream& out, ExecState* exec, int location, con
                 " llint(%p, exec %p)",
                 callLinkInfo->lastSeenCallee.get(),
                 callLinkInfo->lastSeenCallee->executable());
-        } else
-            out.printf(" llint(not set)");
+        }
 #endif
 #if ENABLE(JIT)
         if (numberOfCallLinkInfos()) {
             JSFunction* target = getCallLinkInfo(location).lastSeenCallee.get();
             if (target)
                 out.printf(" jit(%p, exec %p)", target, target->executable());
-            else
-                out.printf(" jit(not set)");
         }
 #endif
     }
@@ -667,6 +662,32 @@ void CodeBlock::dumpBytecode(PrintStream& out)
     out.printf("\n");
 }
 
+void CodeBlock::dumpValueProfiling(PrintStream& out, const Instruction*& it)
+{
+    ++it;
+#if ENABLE(VALUE_PROFILER)
+    CString description = it->u.profile->briefDescription();
+    if (!description.length())
+        return;
+    out.print("    ", description);
+#else
+    UNUSED_PARAM(out);
+#endif
+}
+
+void CodeBlock::dumpArrayProfiling(PrintStream& out, const Instruction*& it)
+{
+    ++it;
+#if ENABLE(VALUE_PROFILER)
+    CString description = it->u.arrayProfile->briefDescription(this);
+    if (!description.length())
+        return;
+    out.print("    ", description);
+#else
+    UNUSED_PARAM(out);
+#endif
+}
+
 void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instruction* begin, const Instruction*& it)
 {
     int location = it - begin;
@@ -956,8 +977,8 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
             int id0 = (++it)->u.operand;
             int resolveInfo = (++it)->u.operand;
             out.printf("[%4d] resolve\t\t %s, %s, %d", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo);
+            dumpValueProfiling(out, it);
             dumpBytecodeCommentAndNewLine(out, location);
-            it++;
             break;
         }
         case op_init_global_const_nop: {
@@ -998,8 +1019,8 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
             int resolveInfo = (++it)->u.operand;
             int putToBaseInfo = (++it)->u.operand;
             out.printf("[%4d] resolve_base%s\t %s, %s, %d, %d", location, isStrict ? "_strict" : "", registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo, putToBaseInfo);
+            dumpValueProfiling(out, it);
             dumpBytecodeCommentAndNewLine(out, location);
-            it++;
             break;
         }
         case op_ensure_property_exists: {
@@ -1016,8 +1037,8 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
             int resolveInfo = (++it)->u.operand;
             int putToBaseInfo = (++it)->u.operand;
             out.printf("[%4d] resolve_with_base %s, %s, %s, %d, %d", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo, putToBaseInfo);
+            dumpValueProfiling(out, it);
             dumpBytecodeCommentAndNewLine(out, location);
-            it++;
             break;
         }
         case op_resolve_with_this: {
@@ -1026,8 +1047,8 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
             int id0 = (++it)->u.operand;
             int resolveInfo = (++it)->u.operand;
             out.printf("[%4d] resolve_with_this %s, %s, %s, %d", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data(), resolveInfo);
+            dumpValueProfiling(out, it);
             dumpBytecodeCommentAndNewLine(out, location);
-            it++;
             break;
         }
         case op_get_by_id:
@@ -1046,6 +1067,7 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
         case op_get_string_length: {
             printGetByIdOp(out, exec, location, it);
             printGetByIdCacheStatus(out, exec, location);
+            dumpValueProfiling(out, it);
             dumpBytecodeCommentAndNewLine(out, location);
             break;
         }
@@ -1112,9 +1134,9 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
             int r1 = (++it)->u.operand;
             int r2 = (++it)->u.operand;
             out.printf("[%4d] get_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
+            dumpArrayProfiling(out, it);
+            dumpValueProfiling(out, it);
             dumpBytecodeCommentAndNewLine(out, location);
-            it++;
-            it++;
             break;
         }
         case op_get_argument_by_val: {
@@ -1122,9 +1144,9 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
             int r1 = (++it)->u.operand;
             int r2 = (++it)->u.operand;
             out.printf("[%4d] get_argument_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
-            dumpBytecodeCommentAndNewLine(out, location);
-            ++it;
             ++it;
+            dumpValueProfiling(out, it);
+            dumpBytecodeCommentAndNewLine(out, location);
             break;
         }
         case op_get_by_pname: {
@@ -1143,8 +1165,8 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
             int r1 = (++it)->u.operand;
             int r2 = (++it)->u.operand;
             out.printf("[%4d] put_by_val\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
+            dumpArrayProfiling(out, it);
             dumpBytecodeCommentAndNewLine(out, location);
-            ++it;
             break;
         }
         case op_del_by_val: {
@@ -1386,8 +1408,8 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
         case op_call_put_result: {
             int r0 = (++it)->u.operand;
             out.printf("[%4d] call_put_result\t\t %s", location, registerName(exec, r0).data());
+            dumpValueProfiling(out, it);
             dumpBytecodeCommentAndNewLine(out, location);
-            it++;
             break;
         }
         case op_ret_object_or_this: {
index e4c762f..569262d 100644 (file)
@@ -1187,6 +1187,9 @@ namespace JSC {
         enum CacheDumpMode { DumpCaches, DontDumpCaches };
         void printCallOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op, CacheDumpMode);
         void printPutByIdOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op);
+        void dumpValueProfiling(PrintStream&, const Instruction*&);
+        void dumpArrayProfiling(PrintStream&, const Instruction*&);
+
         void visitStructures(SlotVisitor&, Instruction* vPC);
         
 #if ENABLE(DFG_JIT)
index c295c68..028c1f6 100644 (file)
@@ -39,6 +39,7 @@
 #include "Structure.h"
 #include "WriteBarrier.h"
 #include <wtf/PrintStream.h>
+#include <wtf/StringPrintStream.h>
 
 namespace JSC {
 
@@ -110,6 +111,20 @@ struct ValueProfileBase {
         return false;
     }
     
+    CString briefDescription()
+    {
+        computeUpdatedPrediction();
+        
+        StringPrintStream out;
+        
+        if (m_singletonValueIsTop)
+            out.print("predicting ", SpeculationDump(m_prediction));
+        else if (m_singletonValue)
+            out.print("predicting ", m_singletonValue);
+        
+        return out.toCString();
+    }
+    
     void dump(PrintStream& out)
     {
         out.print("samples = ", totalNumberOfSamples(), " prediction = ", SpeculationDump(m_prediction));
index c6cfa2e..0d9fea1 100644 (file)
@@ -374,7 +374,7 @@ struct AbstractValue {
     void dump(PrintStream& out) const
     {
         out.print(
-            "(", SpeculationDump(m_type), ", ", arrayModesToString(m_arrayModes), ", ",
+            "(", SpeculationDump(m_type), ", ", ArrayModesDump(m_arrayModes), ", ",
             m_currentKnownStructure, ", ", m_futurePossibleStructure);
         if (!!m_value)
             out.print(", ", m_value);
index d860128..a56adab 100644 (file)
@@ -3666,6 +3666,11 @@ void ByteCodeParser::parseCodeBlock()
 {
     CodeBlock* codeBlock = m_inlineStackTop->m_codeBlock;
     
+    if (m_graph.m_compilation) {
+        m_graph.m_compilation->addProfiledBytecodes(
+            *m_globalData->m_perBytecodeProfiler, m_inlineStackTop->m_profiledBlock);
+    }
+    
 #if DFG_ENABLE(DEBUG_VERBOSE)
     dataLog(
         "Parsing ", *codeBlock,
index 9c499a3..2fabaed 100644 (file)
@@ -642,8 +642,10 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo
     
     if (Options::showDisassembly() || m_globalData->m_perBytecodeProfiler)
         m_disassembler = adoptPtr(new JITDisassembler(m_codeBlock));
-    if (m_globalData->m_perBytecodeProfiler)
+    if (m_globalData->m_perBytecodeProfiler) {
         m_compilation = m_globalData->m_perBytecodeProfiler->newCompilation(m_codeBlock, Profiler::Baseline);
+        m_compilation->addProfiledBytecodes(*m_globalData->m_perBytecodeProfiler, m_codeBlock);
+    }
     
     if (m_disassembler)
         m_disassembler->setStartOfCode(label());
diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp
new file mode 100644 (file)
index 0000000..02c67e8
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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 "ProfilerBytecodeSequence.h"
+
+#include "CodeBlock.h"
+#include "JSGlobalObject.h"
+#include "Operands.h"
+#include <wtf/StringPrintStream.h>
+
+namespace JSC { namespace Profiler {
+
+BytecodeSequence::BytecodeSequence(CodeBlock* codeBlock)
+{
+    StringPrintStream out;
+    
+#if ENABLE(VALUE_PROFILER)
+    for (unsigned i = 0; i < codeBlock->numberOfArgumentValueProfiles(); ++i) {
+        CString description = codeBlock->valueProfileForArgument(i)->briefDescription();
+        if (!description.length())
+            continue;
+        out.reset();
+        out.print("arg", i, " (r", argumentToOperand(i), "): ", description);
+        m_header.append(out.toCString());
+    }
+#endif // ENABLE(VALUE_PROFILER)
+    
+    for (unsigned bytecodeIndex = 0; bytecodeIndex < codeBlock->instructions().size();) {
+        out.reset();
+        codeBlock->dumpBytecode(out, bytecodeIndex);
+        m_sequence.append(Bytecode(bytecodeIndex, codeBlock->globalData()->interpreter->getOpcodeID(codeBlock->instructions()[bytecodeIndex].u.opcode), out.toCString()));
+        bytecodeIndex += opcodeLength(
+            codeBlock->globalData()->interpreter->getOpcodeID(
+                codeBlock->instructions()[bytecodeIndex].u.opcode));
+    }
+}
+
+BytecodeSequence::~BytecodeSequence()
+{
+}
+
+unsigned BytecodeSequence::indexForBytecodeIndex(unsigned bytecodeIndex) const
+{
+    return binarySearch<Bytecode, unsigned, getBytecodeIndexForBytecode>(const_cast<Bytecode*>(m_sequence.begin()), m_sequence.size(), bytecodeIndex) - m_sequence.begin();
+}
+
+const Bytecode& BytecodeSequence::forBytecodeIndex(unsigned bytecodeIndex) const
+{
+    return at(indexForBytecodeIndex(bytecodeIndex));
+}
+
+void BytecodeSequence::addSequenceProperties(ExecState* exec, JSObject* result) const
+{
+    JSArray* header = constructEmptyArray(exec, 0);
+    for (unsigned i = 0; i < m_header.size(); ++i)
+        header->putDirectIndex(exec, i, jsString(exec, String::fromUTF8(m_header[i])));
+    result->putDirect(exec->globalData(), exec->propertyNames().header, header);
+    
+    JSArray* sequence = constructEmptyArray(exec, 0);
+    for (unsigned i = 0; i < m_sequence.size(); ++i)
+        sequence->putDirectIndex(exec, i, m_sequence[i].toJS(exec));
+    result->putDirect(exec->globalData(), exec->propertyNames().bytecode, sequence);
+}
+
+} } // namespace JSC::Profiler
+
diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.h b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.h
new file mode 100644 (file)
index 0000000..2c99941
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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 ProfilerBytecodeSequence_h
+#define ProfilerBytecodeSequence_h
+
+#include "JSValue.h"
+#include "ProfilerBytecode.h"
+#include <wtf/PrintStream.h>
+#include <wtf/Vector.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+namespace JSC {
+
+class CodeBlock;
+
+namespace Profiler {
+
+class BytecodeSequence {
+public:
+    BytecodeSequence(CodeBlock*);
+    ~BytecodeSequence();
+    
+    // Note that this data structure is not indexed by bytecode index.
+    unsigned size() const { return m_sequence.size(); }
+    const Bytecode& at(unsigned i) const { return m_sequence[i]; }
+
+    unsigned indexForBytecodeIndex(unsigned bytecodeIndex) const;
+    const Bytecode& forBytecodeIndex(unsigned bytecodeIndex) const;
+
+protected:
+    void addSequenceProperties(ExecState*, JSObject*) const;
+    
+private:
+    Vector<CString> m_header;
+    Vector<Bytecode> m_sequence;
+};
+
+} } // namespace JSC::Profiler
+
+#endif // ProfilerBytecodeSequence_h
+
index 254d1bb..d3156e3 100644 (file)
 #include "config.h"
 #include "ProfilerBytecodes.h"
 
+#include "CodeBlock.h"
 #include "JSGlobalObject.h"
 #include <wtf/StringPrintStream.h>
 
 namespace JSC { namespace Profiler {
 
-Bytecodes::Bytecodes(
-    size_t id, const String& inferredName, const String& sourceCode, CodeBlockHash hash)
-    : m_id(id)
-    , m_inferredName(inferredName)
-    , m_sourceCode(sourceCode)
-    , m_hash(hash)
+Bytecodes::Bytecodes(size_t id, CodeBlock* codeBlock)
+    : BytecodeSequence(codeBlock)
+    , m_id(id)
+    , m_inferredName(codeBlock->inferredName())
+    , m_sourceCode(codeBlock->sourceCodeForTools())
+    , m_hash(codeBlock->hash())
+    , m_instructionCount(codeBlock->instructionCount())
 {
 }
 
 Bytecodes::~Bytecodes() { }
 
-unsigned Bytecodes::indexForBytecodeIndex(unsigned bytecodeIndex) const
-{
-    return binarySearch<Bytecode, unsigned, getBytecodeIndexForBytecode>(const_cast<Bytecode*>(m_bytecode.begin()), m_bytecode.size(), bytecodeIndex) - m_bytecode.begin();
-}
-
-const Bytecode& Bytecodes::forBytecodeIndex(unsigned bytecodeIndex) const
-{
-    return at(indexForBytecodeIndex(bytecodeIndex));
-}
-
 void Bytecodes::dump(PrintStream& out) const
 {
     out.print("#", m_hash, "(", m_id, ")");
@@ -65,11 +57,8 @@ JSValue Bytecodes::toJS(ExecState* exec) const
     result->putDirect(exec->globalData(), exec->propertyNames().inferredName, jsString(exec, m_inferredName));
     result->putDirect(exec->globalData(), exec->propertyNames().sourceCode, jsString(exec, m_sourceCode));
     result->putDirect(exec->globalData(), exec->propertyNames().hash, jsString(exec, String::fromUTF8(toCString(m_hash))));
-    
-    JSArray* stream = constructEmptyArray(exec, 0);
-    for (unsigned i = 0; i < m_bytecode.size(); ++i)
-        stream->putDirectIndex(exec, i, m_bytecode[i].toJS(exec));
-    result->putDirect(exec->globalData(), exec->propertyNames().bytecode, stream);
+    result->putDirect(exec->globalData(), exec->propertyNames().instructionCount, jsNumber(m_instructionCount));
+    addSequenceProperties(exec, result);
     
     return result;
 }
index 337392c..96edcd5 100644 (file)
 
 #include "CodeBlockHash.h"
 #include "JSValue.h"
-#include "ProfilerBytecode.h"
+#include "ProfilerBytecodeSequence.h"
 #include <wtf/PrintStream.h>
 #include <wtf/text/WTFString.h>
 
 namespace JSC { namespace Profiler {
 
-class Bytecodes {
+class Bytecodes : public BytecodeSequence {
 public:
-    Bytecodes(size_t id, const String& inferredName, const String& sourceCode, CodeBlockHash);
+    Bytecodes(size_t id, CodeBlock*);
     ~Bytecodes();
     
-    void append(const Bytecode& bytecode) { m_bytecode.append(bytecode); }
-    
     size_t id() const { return m_id; }
     const String& inferredName() const { return m_inferredName; }
     const String& sourceCode() const { return m_sourceCode; }
+    unsigned instructionCount() const { return m_instructionCount; }
     CodeBlockHash hash() const { return m_hash; }
-    
-    // Note that this data structure is not indexed by bytecode index.
-    unsigned size() const { return m_bytecode.size(); }
-    const Bytecode& at(unsigned i) const { return m_bytecode[i]; }
-    
-    unsigned indexForBytecodeIndex(unsigned bytecodeIndex) const;
-    const Bytecode& forBytecodeIndex(unsigned bytecodeIndex) const;
-    
+
     void dump(PrintStream&) const;
     
     JSValue toJS(ExecState*) const;
@@ -62,7 +54,7 @@ private:
     String m_inferredName;
     String m_sourceCode;
     CodeBlockHash m_hash;
-    Vector<Bytecode> m_bytecode;
+    unsigned m_instructionCount;
 };
 
 } } // namespace JSC::Profiler
index fc1901f..870f200 100644 (file)
@@ -27,6 +27,7 @@
 #include "ProfilerCompilation.h"
 
 #include "JSGlobalObject.h"
+#include "ProfilerDatabase.h"
 #include <wtf/StringPrintStream.h>
 
 namespace JSC { namespace Profiler {
@@ -39,6 +40,23 @@ Compilation::Compilation(Bytecodes* bytecodes, CompilationKind kind)
 
 Compilation::~Compilation() { }
 
+void Compilation::addProfiledBytecodes(Database& database, CodeBlock* profiledBlock)
+{
+    Bytecodes* bytecodes = database.ensureBytecodesFor(profiledBlock);
+    
+    // First make sure that we haven't already added profiled bytecodes for this code
+    // block. We do this using an O(N) search because I suspect that this list will
+    // tend to be fairly small, and the additional space costs of having a HashMap/Set
+    // would be greater than the time cost of occasionally doing this search.
+    
+    for (unsigned i = m_profiledBytecodes.size(); i--;) {
+        if (m_profiledBytecodes[i].bytecodes() == bytecodes)
+            return;
+    }
+    
+    m_profiledBytecodes.append(ProfiledBytecodes(bytecodes, profiledBlock));
+}
+
 void Compilation::addDescription(const CompiledBytecode& compiledBytecode)
 {
     m_descriptions.append(compiledBytecode);
@@ -74,6 +92,11 @@ JSValue Compilation::toJS(ExecState* exec) const
     result->putDirect(exec->globalData(), exec->propertyNames().bytecodesID, jsNumber(m_bytecodes->id()));
     result->putDirect(exec->globalData(), exec->propertyNames().compilationKind, jsString(exec, String::fromUTF8(toCString(m_kind))));
     
+    JSArray* profiledBytecodes = constructEmptyArray(exec, 0);
+    for (unsigned i = 0; i < m_profiledBytecodes.size(); ++i)
+        profiledBytecodes->putDirectIndex(exec, i, m_profiledBytecodes[i].toJS(exec));
+    result->putDirect(exec->globalData(), exec->propertyNames().profiledBytecodes, profiledBytecodes);
+    
     JSArray* descriptions = constructEmptyArray(exec, 0);
     for (unsigned i = 0; i < m_descriptions.size(); ++i)
         descriptions->putDirectIndex(exec, i, m_descriptions[i].toJS(exec));
index 697b8cf..3c0b0cb 100644 (file)
 #include "ProfilerOSRExit.h"
 #include "ProfilerOSRExitSite.h"
 #include "ProfilerOriginStack.h"
+#include "ProfilerProfiledBytecodes.h"
 #include <wtf/RefCounted.h>
 #include <wtf/SegmentedVector.h>
 
 namespace JSC { namespace Profiler {
 
 class Bytecodes;
+class Database;
 
 // Represents the act of executing some bytecodes in some engine, and does
 // all of the counting for those executions.
@@ -49,6 +51,10 @@ public:
     Compilation(Bytecodes*, CompilationKind);
     ~Compilation();
     
+    void addProfiledBytecodes(Database&, CodeBlock*);
+    unsigned profiledBytecodesSize() const { return m_profiledBytecodes.size(); }
+    const ProfiledBytecodes& profiledBytecodesAt(unsigned i) const { return m_profiledBytecodes[i]; }
+    
     Bytecodes* bytecodes() const { return m_bytecodes; }
     CompilationKind kind() const { return m_kind; }
     
@@ -62,6 +68,7 @@ public:
 private:
     Bytecodes* m_bytecodes;
     CompilationKind m_kind;
+    Vector<ProfiledBytecodes> m_profiledBytecodes;
     Vector<CompiledBytecode> m_descriptions;
     HashMap<OriginStack, OwnPtr<ExecutionCounter> > m_counters;
     Vector<OSRExitSite> m_osrExitSites;
index a73caba..0d07894 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "CodeBlock.h"
 #include "JSONObject.h"
-#include <wtf/StringPrintStream.h>
 
 namespace JSC { namespace Profiler {
 
@@ -41,35 +40,16 @@ Database::~Database()
 {
 }
 
-Bytecodes* Database::addBytecodes(
-    CodeBlockHash hash, const String& inferredName, const String& sourceCode)
-{
-    m_bytecodes.append(Bytecodes(m_bytecodes.size(), inferredName, sourceCode, hash));
-    return &m_bytecodes.last();
-}
-
 Bytecodes* Database::ensureBytecodesFor(CodeBlock* codeBlock)
 {
-    StringPrintStream out;
-    
     codeBlock = codeBlock->baselineVersion();
     
     HashMap<CodeBlock*, Bytecodes*>::iterator iter = m_bytecodesMap.find(codeBlock);
     if (iter != m_bytecodesMap.end())
         return iter->value;
     
-    Bytecodes* result = addBytecodes(
-        codeBlock->hash(), codeBlock->inferredName(), codeBlock->sourceCodeForTools());
-    
-    for (unsigned bytecodeIndex = 0; bytecodeIndex < codeBlock->instructions().size();) {
-        out.reset();
-        codeBlock->dumpBytecode(out, bytecodeIndex);
-        result->append(Bytecode(bytecodeIndex, m_globalData.interpreter->getOpcodeID(codeBlock->instructions()[bytecodeIndex].u.opcode), out.toCString()));
-        
-        bytecodeIndex += opcodeLength(
-            m_globalData.interpreter->getOpcodeID(
-                codeBlock->instructions()[bytecodeIndex].u.opcode));
-    }
+    m_bytecodes.append(Bytecodes(m_bytecodes.size(), codeBlock));
+    Bytecodes* result = &m_bytecodes.last();
     
     m_bytecodesMap.add(codeBlock, result);
     
index 6634a35..e82f751 100644 (file)
@@ -66,8 +66,7 @@ public:
     JS_EXPORT_PRIVATE bool save(const char* filename) const;
 
 private:
-    Bytecodes* addBytecodes(CodeBlockHash, const String& inferredName, const String& sourceCode);
-    
+
     JSGlobalData& m_globalData;
     SegmentedVector<Bytecodes> m_bytecodes;
     HashMap<CodeBlock*, Bytecodes*> m_bytecodesMap;
diff --git a/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp
new file mode 100644 (file)
index 0000000..ac9f650
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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 "ProfilerProfiledBytecodes.h"
+
+#include "JSGlobalObject.h"
+
+namespace JSC { namespace Profiler {
+
+ProfiledBytecodes::ProfiledBytecodes(Bytecodes* bytecodes, CodeBlock* profiledBlock)
+    : BytecodeSequence(profiledBlock)
+    , m_bytecodes(bytecodes)
+{
+}
+
+ProfiledBytecodes::~ProfiledBytecodes()
+{
+}
+
+JSValue ProfiledBytecodes::toJS(ExecState* exec) const
+{
+    JSObject* result = constructEmptyObject(exec);
+    
+    result->putDirect(exec->globalData(), exec->propertyNames().bytecodesID, jsNumber(m_bytecodes->id()));
+    addSequenceProperties(exec, result);
+    
+    return result;
+}
+
+} } // namespace JSC::Profiler
+
diff --git a/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.h b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.h
new file mode 100644 (file)
index 0000000..d7cb6ff
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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 ProfilerProfiledBytecodes_h
+#define ProfilerProfiledBytecodes_h
+
+#include "ProfilerBytecodeSequence.h"
+#include "ProfilerBytecodes.h"
+#include "ProfilerOriginStack.h"
+
+namespace JSC { namespace Profiler {
+
+class ProfiledBytecodes : public BytecodeSequence {
+public:
+    ProfiledBytecodes(Bytecodes*, CodeBlock*);
+    ~ProfiledBytecodes();
+    
+    const Bytecodes* bytecodes() const { return m_bytecodes; }
+    
+    JSValue toJS(ExecState*) const;
+
+private:
+    Bytecodes* m_bytecodes;
+};
+
+} } // namespace JSC::Profiler
+
+#endif // ProfilerProfiledBytecodes_h
+
index a9ac18e..93f7914 100644 (file)
     macro(get) \
     macro(hasOwnProperty) \
     macro(hash) \
+    macro(header) \
     macro(id) \
     macro(ignoreCase) \
     macro(index) \
     macro(inferredName) \
     macro(input) \
+    macro(instructionCount) \
     macro(isArray) \
     macro(isPrototypeOf) \
     macro(isWatchpoint) \
@@ -77,6 +79,7 @@
     macro(osrExitSites) \
     macro(osrExits) \
     macro(parse) \
+    macro(profiledBytecodes) \
     macro(propertyIsEnumerable) \
     macro(prototype) \
     macro(set) \
index 95f0c60..4a56b19 100644 (file)
@@ -1,3 +1,18 @@
+2012-12-11  Filip Pizlo  <fpizlo@apple.com>
+
+        Profiler should show bytecode dumps as they would have been visible to the JITs, including the profiling data that the JITs would see
+        https://bugs.webkit.org/show_bug.cgi?id=104647
+
+        Reviewed by Oliver Hunt.
+
+        Added a "profiling" (or "p") command to show the profiling data that the JITs saw
+        for each JIT compilation of a code block.
+        
+        Also added instruction counts in the "full" display and made the "full" display the
+        default thing you see.
+
+        * Scripts/display-profiler-output:
+
 2012-12-11  Eric Seidel  <eric@webkit.org>
 
         Unreviewed, rolling out r137371.
index 3ee363d..35f4c87 100755 (executable)
@@ -133,12 +133,13 @@ class Bytecode
 end
 
 class Bytecodes
-    attr_accessor :codeHash, :inferredName, :source, :machineInlineSites, :compilations
+    attr_accessor :codeHash, :inferredName, :source, :instructionCount, :machineInlineSites, :compilations
     
     def initialize(json)
         @codeHash = json["hash"].to_s
         @inferredName = json["inferredName"].to_s
         @source = json["sourceCode"].to_s
+        @instructionCount = json["instructionCount"].to_i
         @bytecode = {}
         json["bytecode"].each {
             | subJson |
@@ -251,6 +252,35 @@ class Bytecodes
     end
 end
 
+class ProfiledBytecode
+    attr_reader :bytecodeIndex, :description
+    
+    def initialize(json)
+        @bytecodeIndex = json["bytecodeIndex"].to_i
+        @description = json["description"].to_s
+    end
+end
+
+class ProfiledBytecodes
+    attr_reader :header, :bytecodes
+    
+    def initialize(json)
+        @header = json["header"]
+        @bytecodes = $bytecodes[json["bytecodesID"].to_i]
+        @sequence = json["bytecode"].map {
+            | subJson |
+            ProfiledBytecode.new(subJson)
+        }
+    end
+    
+    def each
+        @sequence.each {
+            | description |
+            yield description
+        }
+    end
+end
+
 def originStackFromJSON(json)
     json.map {
         | subJson |
@@ -295,7 +325,7 @@ class OSRExit
 end
 
 class Compilation
-    attr_accessor :bytecode, :engine, :descriptions, :counters, :compilationIndex, :osrExits
+    attr_accessor :bytecode, :engine, :descriptions, :counters, :compilationIndex, :osrExits, :profiledBytecodes
     
     def initialize(json)
         @bytecode = $bytecodes[json["bytecodesID"].to_i]
@@ -334,6 +364,11 @@ class Compilation
             osrExits[osrExit.codeAddress] << osrExit
             osrExit.origin[-1].osrExits << osrExit
         }
+        @profiledBytecodes = []
+        json["profiledBytecodes"].each {
+            | subJson |
+            @profiledBytecodes << ProfiledBytecodes.new(subJson)
+        }
     end
     
     def counter(origin)
@@ -425,14 +460,33 @@ end
 def summary(mode)
     remaining = screenWidth
     
-    hashCols = 20
+    # Figure out how many columns we need for the code block names, and for counts
+    maxCount = 0
+    maxName = 0
+    $bytecodes.each {
+        | bytecodes |
+        maxCount = ([maxCount] + $engines.map {
+                        | engine |
+                        bytecodes.maxTopExecutionCount(engine)
+                    } + $engines.map {
+                        | engine |
+                        bytecodes.maxBottomExecutionCount(engine)
+                    }).max
+        maxName = [bytecodes.to_s.size, maxName].max
+    }
+    maxCountDigits = maxCount.to_s.size
+    
+    hashCols = [[maxName, 30].min, "CodeBlock".size].max
     remaining -= hashCols + 1
     
-    countCols = 9 * $engines.size
+    countCols = [maxCountDigits * $engines.size, "Source Counts".size].max
     remaining -= countCols + 1
     
     if mode == :full
-        machineCountCols = 9 * $engines.size
+        instructionCountCols = 6
+        remaining -= instructionCountCols + 1
+        
+        machineCountCols = [maxCountDigits * $engines.size, "Machine Counts".size].max
         remaining -= machineCountCols + 1
         
         compilationsCols = 7
@@ -451,7 +505,11 @@ def summary(mode)
         sourceCols = nil
     end
     
-    print(center("CodeBlock", hashCols) + " " + center("Source Counts", countCols))
+    print(center("CodeBlock", hashCols))
+    if mode == :full
+        print(" " + center("#Instr", instructionCountCols))
+    end
+    print(" " + center("Source Counts", countCols))
     if mode == :full
         print(" " + center("Machine Counts", machineCountCols))
         print(" " + center("#Compil", compilationsCols))
@@ -463,7 +521,11 @@ def summary(mode)
     end
     puts
     
-    print(center("", hashCols) + " " + center("Base/DFG", countCols))
+    print(center("", hashCols))
+    if mode == :full
+        print(" " + (" " * instructionCountCols))
+    end
+    print(" " + center("Base/DFG", countCols))
     if mode == :full
         print(" " + center("Base/DFG", machineCountCols))
         print(" " + (" " * compilationsCols))
@@ -475,7 +537,11 @@ def summary(mode)
         b.totalMaxTopExecutionCount <=> a.totalMaxTopExecutionCount
     }.each {
         | bytecode |
-        print(center(bytecode.name(hashCols), hashCols) + " " +
+        print(center(bytecode.name(hashCols), hashCols))
+        if mode == :full
+            print(" " + center(bytecode.instructionCount.to_s, instructionCountCols))
+        end
+        print(" " +
               center($engines.map {
                          | engine |
                          bytecode.maxTopExecutionCount(engine).to_s
@@ -505,6 +571,7 @@ def executeCommand(*commandArray)
         puts "full (f)        Same as summary, but prints more information."
         puts "source          Show the source for a code block."
         puts "bytecode (b)    Show the bytecode for a code block, with counts."
+        puts "profiling (p)   Show the (internal) profiling data for a code block."
         puts "display (d)     Display details for a code block."
         puts "inlines         Show all inlining stacks that the code block was on."
         puts "help (h)        Print this message."
@@ -570,6 +637,45 @@ def executeCommand(*commandArray)
                 }
             }
         }
+    when "profiling", "p"
+        if args.length != 1
+            puts "Usage: profiling <code block hash>"
+            return
+        end
+        
+        hash = args[0]
+        
+        first = true
+        $compilations.each {
+            | compilation |
+            
+            compilation.profiledBytecodes.each {
+                | profiledBytecodes |
+                if profiledBytecodes.bytecodes.matches(hash)
+                    if first
+                        first = false
+                    else
+                        puts
+                    end
+                    
+                    puts "Compilation #{compilation}:"
+                    profiledBytecodes.header.each {
+                        | header |
+                        puts(" " * 6 + header)
+                    }
+                    profiledBytecodes.each {
+                        | bytecode |
+                        puts(" " * 8 + bytecode.description)
+                        profiledBytecodes.bytecodes.bytecode(bytecode.bytecodeIndex).osrExits.each {
+                            | exit |
+                            if exit.compilation == compilation
+                                puts(" !!!!!           EXIT: due to #{exit.exitKind}, #{exit.count} times")
+                            end
+                        }
+                    }
+                end
+            }
+        }
     when "inlines"
         if args.length != 1
             puts "Usage: inlines <code block hash>"
@@ -787,7 +893,7 @@ def executeCommand(*commandArray)
     end
 end
 
-executeCommand("summary")
+executeCommand("full")
 
 while commandLine = Readline.readline("> ", true)
     executeCommand(*commandLine.split)