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.
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: http://svn.webkit.org/repository/webkit/trunk@137379 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index 1aeaebf..d0b2f19 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -176,6 +176,7 @@
profiler/ProfilerBytecode.cpp
profiler/ProfilerBytecode.h
+ profiler/ProfilerBytecodeSequence.cpp
profiler/ProfilerBytecodes.cpp
profiler/ProfilerBytecodes.h
profiler/ProfilerCompilation.cpp
@@ -193,6 +194,7 @@
profiler/ProfilerOriginStack.h
profiler/ProfilerOSRExit.cpp
profiler/ProfilerOSRExitSite.cpp
+ profiler/ProfilerProfiledBytecodes.cpp
profiler/Profile.cpp
profiler/ProfileGenerator.cpp
profiler/ProfileNode.cpp
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 8a114c1..56b2bef 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -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
diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am
index f4d20e1..4dec66a 100644
--- a/Source/JavaScriptCore/GNUmakefile.list.am
+++ b/Source/JavaScriptCore/GNUmakefile.list.am
@@ -479,6 +479,8 @@
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 @@
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 \
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
index ddc84ee..3b466f0 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
+++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
@@ -1534,6 +1534,14 @@
>
</File>
<File
+ RelativePath="..\..\profiler\ProfilerBytecodeSequence.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\profiler\ProfilerBytecodeSequence.h"
+ >
+ </File>
+ <File
RelativePath="..\..\profiler\ProfilerBytecodes.cpp"
>
</File>
@@ -1610,6 +1618,14 @@
>
</File>
<File
+ RelativePath="..\..\profiler\ProfilerProfiledBytecodes.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\profiler\ProfilerProfiledBytecodes.h"
+ >
+ </File>
+ <File
RelativePath="..\..\profiler\Profile.cpp"
>
</File>
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index eda1440..fc9c855 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -73,6 +73,10 @@
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 */; };
@@ -902,6 +906,10 @@
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>"; };
@@ -2578,6 +2586,8 @@
0FF72993166AD347000F5BA3 /* ProfilerBytecode.h */,
0FF72994166AD347000F5BA3 /* ProfilerBytecodes.cpp */,
0FF72995166AD347000F5BA3 /* ProfilerBytecodes.h */,
+ 0F13912416771C30009CCB07 /* ProfilerBytecodeSequence.cpp */,
+ 0F13912516771C30009CCB07 /* ProfilerBytecodeSequence.h */,
0FF72996166AD347000F5BA3 /* ProfilerCompilation.cpp */,
0FF72997166AD347000F5BA3 /* ProfilerCompilation.h */,
0FF72998166AD347000F5BA3 /* ProfilerCompilationKind.cpp */,
@@ -2595,6 +2605,8 @@
0FB105881675482E00F8AB6E /* ProfilerOSRExit.h */,
0FB105891675482E00F8AB6E /* ProfilerOSRExitSite.cpp */,
0FB1058A1675482E00F8AB6E /* ProfilerOSRExitSite.h */,
+ 0F13912616771C30009CCB07 /* ProfilerProfiledBytecodes.cpp */,
+ 0F13912716771C30009CCB07 /* ProfilerProfiledBytecodes.h */,
);
name = profiler;
sourceTree = "<group>";
@@ -3165,6 +3177,8 @@
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;
};
@@ -3765,6 +3779,8 @@
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;
};
diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri
index 03f85e7..e0c671f 100644
--- a/Source/JavaScriptCore/Target.pri
+++ b/Source/JavaScriptCore/Target.pri
@@ -186,6 +186,7 @@
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 @@
profiler/ProfilerOriginStack.h \
profiler/ProfilerOSRExit.cpp \
profiler/ProfilerOSRExitSite.cpp \
+ profiler/ProfilerProfiledBytecodes.cpp \
profiler/Profile.cpp \
profiler/ProfileGenerator.cpp \
profiler/ProfileNode.cpp \
diff --git a/Source/JavaScriptCore/bytecode/ArrayProfile.cpp b/Source/JavaScriptCore/bytecode/ArrayProfile.cpp
index 51baf33..4fa3096 100644
--- a/Source/JavaScriptCore/bytecode/ArrayProfile.cpp
+++ b/Source/JavaScriptCore/bytecode/ArrayProfile.cpp
@@ -28,41 +28,50 @@
#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 @@
}
}
+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
diff --git a/Source/JavaScriptCore/bytecode/ArrayProfile.h b/Source/JavaScriptCore/bytecode/ArrayProfile.h
index 5116cd3..2ba2fbf 100644
--- a/Source/JavaScriptCore/bytecode/ArrayProfile.h
+++ b/Source/JavaScriptCore/bytecode/ArrayProfile.h
@@ -67,7 +67,8 @@
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 @@
bool usesOriginalArrayStructures() const { return m_usesOriginalArrayStructures; }
+ CString briefDescription(CodeBlock*);
+
private:
friend class LLIntOffsetsExtractor;
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index 79f9db8..92b48c6 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -303,7 +303,7 @@
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 @@
#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 @@
#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 @@
}
out.printf("]");
}
+ out.printf(")");
}
- out.printf(")");
}
#endif
}
@@ -469,16 +467,13 @@
" 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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());
+ ++it;
+ dumpValueProfiling(out, it);
dumpBytecodeCommentAndNewLine(out, location);
- ++it;
- ++it;
break;
}
case op_get_by_pname: {
@@ -1143,8 +1165,8 @@
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 @@
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: {
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h
index e4c762f1..569262d 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h
@@ -1187,6 +1187,9 @@
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)
diff --git a/Source/JavaScriptCore/bytecode/ValueProfile.h b/Source/JavaScriptCore/bytecode/ValueProfile.h
index c295c68..028c1f6 100644
--- a/Source/JavaScriptCore/bytecode/ValueProfile.h
+++ b/Source/JavaScriptCore/bytecode/ValueProfile.h
@@ -39,6 +39,7 @@
#include "Structure.h"
#include "WriteBarrier.h"
#include <wtf/PrintStream.h>
+#include <wtf/StringPrintStream.h>
namespace JSC {
@@ -110,6 +111,20 @@
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));
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractValue.h b/Source/JavaScriptCore/dfg/DFGAbstractValue.h
index c6cfa2e..0d9fea1 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractValue.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractValue.h
@@ -374,7 +374,7 @@
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);
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index d860128..a56adab 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -3666,6 +3666,11 @@
{
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,
diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp
index 9c499a3..2fabaed 100644
--- a/Source/JavaScriptCore/jit/JIT.cpp
+++ b/Source/JavaScriptCore/jit/JIT.cpp
@@ -642,8 +642,10 @@
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
index 0000000..02c67e8
--- /dev/null
+++ b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp
@@ -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
index 0000000..2c99941
--- /dev/null
+++ b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.h
@@ -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
+
diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp
index 254d1bb..d3156e3 100644
--- a/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp
@@ -26,32 +26,24 @@
#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 @@
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;
}
diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodes.h b/Source/JavaScriptCore/profiler/ProfilerBytecodes.h
index 337392c..96edcd5 100644
--- a/Source/JavaScriptCore/profiler/ProfilerBytecodes.h
+++ b/Source/JavaScriptCore/profiler/ProfilerBytecodes.h
@@ -28,31 +28,23 @@
#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 @@
String m_inferredName;
String m_sourceCode;
CodeBlockHash m_hash;
- Vector<Bytecode> m_bytecode;
+ unsigned m_instructionCount;
};
} } // namespace JSC::Profiler
diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp b/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp
index fc1901f..870f200 100644
--- a/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp
@@ -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() { }
+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 @@
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));
diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilation.h b/Source/JavaScriptCore/profiler/ProfilerCompilation.h
index 697b8cf..3c0b0cb 100644
--- a/Source/JavaScriptCore/profiler/ProfilerCompilation.h
+++ b/Source/JavaScriptCore/profiler/ProfilerCompilation.h
@@ -34,12 +34,14 @@
#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 @@
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 @@
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;
diff --git a/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp b/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp
index a73caba..0d07894 100644
--- a/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp
@@ -28,7 +28,6 @@
#include "CodeBlock.h"
#include "JSONObject.h"
-#include <wtf/StringPrintStream.h>
namespace JSC { namespace Profiler {
@@ -41,35 +40,16 @@
{
}
-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);
diff --git a/Source/JavaScriptCore/profiler/ProfilerDatabase.h b/Source/JavaScriptCore/profiler/ProfilerDatabase.h
index 6634a35..e82f751 100644
--- a/Source/JavaScriptCore/profiler/ProfilerDatabase.h
+++ b/Source/JavaScriptCore/profiler/ProfilerDatabase.h
@@ -66,8 +66,7 @@
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
index 0000000..ac9f650
--- /dev/null
+++ b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp
@@ -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
index 0000000..d7cb6ff
--- /dev/null
+++ b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.h
@@ -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
+
diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.h b/Source/JavaScriptCore/runtime/CommonIdentifiers.h
index a9ac18e..93f7914 100644
--- a/Source/JavaScriptCore/runtime/CommonIdentifiers.h
+++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.h
@@ -57,11 +57,13 @@
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) \
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
index 95f0c60..4a56b19 100644
--- a/Tools/ChangeLog
+++ b/Tools/ChangeLog
@@ -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.
diff --git a/Tools/Scripts/display-profiler-output b/Tools/Scripts/display-profiler-output
index 3ee363d..35f4c87 100755
--- a/Tools/Scripts/display-profiler-output
+++ b/Tools/Scripts/display-profiler-output
@@ -133,12 +133,13 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
}
+ 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 @@
end
end
-executeCommand("summary")
+executeCommand("full")
while commandLine = Readline.readline("> ", true)
executeCommand(*commandLine.split)