Profiler should say things about OSR exits
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 10 Dec 2012 18:17:46 +0000 (18:17 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 10 Dec 2012 18:17:46 +0000 (18:17 +0000)
https://bugs.webkit.org/show_bug.cgi?id=104497

Reviewed by Oliver Hunt.

Source/JavaScriptCore:

This adds support for profiling OSR exits. For each exit that is taken, the profiler
records the machine code address that the exit occurred on, the exit kind, the origin
stack, and the number of times that it happened.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* assembler/AbstractMacroAssembler.h:
(Jump):
(JSC::AbstractMacroAssembler::Jump::label):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::saveCompilation):
(CodeBlock):
(JSC::CodeBlock::compilation):
(DFGData):
* bytecode/DFGExitProfile.h:
(DFG):
* bytecode/ExitKind.cpp: Added.
(JSC):
(JSC::exitKindToString):
(JSC::exitKindIsCountable):
(WTF):
(WTF::printInternal):
* bytecode/ExitKind.h: Added.
(JSC):
(WTF):
* dfg/DFGGraph.h:
(Graph):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::linkOSRExits):
(JSC::DFG::JITCompiler::link):
(JSC::DFG::JITCompiler::compile):
(JSC::DFG::JITCompiler::compileFunction):
* dfg/DFGJITCompiler.h:
(JITCompiler):
* dfg/DFGOSRExitCompiler.cpp:
* jit/JIT.cpp:
(JSC::JIT::JIT):
(JSC::JIT::privateCompile):
* jit/JIT.h:
(JIT):
* jit/JumpReplacementWatchpoint.h:
(JSC::JumpReplacementWatchpoint::sourceLabel):
(JumpReplacementWatchpoint):
* profiler/ProfilerCompilation.cpp:
(JSC::Profiler::Compilation::addOSRExitSite):
(Profiler):
(JSC::Profiler::Compilation::addOSRExit):
(JSC::Profiler::Compilation::toJS):
* profiler/ProfilerCompilation.h:
(Compilation):
* profiler/ProfilerDatabase.cpp:
(JSC::Profiler::Database::newCompilation):
* profiler/ProfilerDatabase.h:
(Database):
* profiler/ProfilerOSRExit.cpp: Added.
(Profiler):
(JSC::Profiler::OSRExit::OSRExit):
(JSC::Profiler::OSRExit::~OSRExit):
(JSC::Profiler::OSRExit::toJS):
* profiler/ProfilerOSRExit.h: Added.
(Profiler):
(OSRExit):
(JSC::Profiler::OSRExit::id):
(JSC::Profiler::OSRExit::origin):
(JSC::Profiler::OSRExit::exitKind):
(JSC::Profiler::OSRExit::isWatchpoint):
(JSC::Profiler::OSRExit::counterAddress):
(JSC::Profiler::OSRExit::count):
* profiler/ProfilerOSRExitSite.cpp: Added.
(Profiler):
(JSC::Profiler::OSRExitSite::toJS):
* profiler/ProfilerOSRExitSite.h: Added.
(Profiler):
(OSRExitSite):
(JSC::Profiler::OSRExitSite::OSRExitSite):
(JSC::Profiler::OSRExitSite::codeAddress):
* runtime/CommonIdentifiers.h:

Tools:

Adds support for displaying OSR exit information for full summary (just displays the
counts and the number of recompilations), bytecode display (says which bytecodes
exited), and DFG display (annotates disassembly with taken OSR exits and their
counts).

* Scripts/display-profiler-output:

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

29 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/assembler/AbstractMacroAssembler.h
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecode/DFGExitProfile.h
Source/JavaScriptCore/bytecode/ExitKind.cpp [new file with mode: 0644]
Source/JavaScriptCore/bytecode/ExitKind.h [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
Source/JavaScriptCore/dfg/DFGJITCompiler.h
Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JumpReplacementWatchpoint.h
Source/JavaScriptCore/profiler/ProfilerCompilation.cpp
Source/JavaScriptCore/profiler/ProfilerCompilation.h
Source/JavaScriptCore/profiler/ProfilerDatabase.cpp
Source/JavaScriptCore/profiler/ProfilerDatabase.h
Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp [new file with mode: 0644]
Source/JavaScriptCore/profiler/ProfilerOSRExit.h [new file with mode: 0644]
Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp [new file with mode: 0644]
Source/JavaScriptCore/profiler/ProfilerOSRExitSite.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/CommonIdentifiers.h
Tools/ChangeLog
Tools/Scripts/display-profiler-output

index be91d8b..1aeaebf 100644 (file)
@@ -50,6 +50,7 @@ set(JavaScriptCore_SOURCES
     bytecode/CodeType.cpp
     bytecode/DFGExitProfile.cpp
     bytecode/ExecutionCounter.cpp
+    bytecode/ExitKind.cpp
     bytecode/GetByIdStatus.cpp
     bytecode/JumpTable.cpp
     bytecode/LazyOperandValueProfile.cpp
@@ -190,6 +191,8 @@ set(JavaScriptCore_SOURCES
     profiler/ProfilerOrigin.h
     profiler/ProfilerOriginStack.cpp
     profiler/ProfilerOriginStack.h
+    profiler/ProfilerOSRExit.cpp
+    profiler/ProfilerOSRExitSite.cpp
     profiler/Profile.cpp
     profiler/ProfileGenerator.cpp
     profiler/ProfileNode.cpp
index b0b9f84..f6b007e 100644 (file)
@@ -1,3 +1,91 @@
+2012-12-09  Filip Pizlo  <fpizlo@apple.com>
+
+        Profiler should say things about OSR exits
+        https://bugs.webkit.org/show_bug.cgi?id=104497
+
+        Reviewed by Oliver Hunt.
+
+        This adds support for profiling OSR exits. For each exit that is taken, the profiler
+        records the machine code address that the exit occurred on, the exit kind, the origin
+        stack, and the number of times that it happened.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Target.pri:
+        * assembler/AbstractMacroAssembler.h:
+        (Jump):
+        (JSC::AbstractMacroAssembler::Jump::label):
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::saveCompilation):
+        (CodeBlock):
+        (JSC::CodeBlock::compilation):
+        (DFGData):
+        * bytecode/DFGExitProfile.h:
+        (DFG):
+        * bytecode/ExitKind.cpp: Added.
+        (JSC):
+        (JSC::exitKindToString):
+        (JSC::exitKindIsCountable):
+        (WTF):
+        (WTF::printInternal):
+        * bytecode/ExitKind.h: Added.
+        (JSC):
+        (WTF):
+        * dfg/DFGGraph.h:
+        (Graph):
+        * dfg/DFGJITCompiler.cpp:
+        (JSC::DFG::JITCompiler::linkOSRExits):
+        (JSC::DFG::JITCompiler::link):
+        (JSC::DFG::JITCompiler::compile):
+        (JSC::DFG::JITCompiler::compileFunction):
+        * dfg/DFGJITCompiler.h:
+        (JITCompiler):
+        * dfg/DFGOSRExitCompiler.cpp:
+        * jit/JIT.cpp:
+        (JSC::JIT::JIT):
+        (JSC::JIT::privateCompile):
+        * jit/JIT.h:
+        (JIT):
+        * jit/JumpReplacementWatchpoint.h:
+        (JSC::JumpReplacementWatchpoint::sourceLabel):
+        (JumpReplacementWatchpoint):
+        * profiler/ProfilerCompilation.cpp:
+        (JSC::Profiler::Compilation::addOSRExitSite):
+        (Profiler):
+        (JSC::Profiler::Compilation::addOSRExit):
+        (JSC::Profiler::Compilation::toJS):
+        * profiler/ProfilerCompilation.h:
+        (Compilation):
+        * profiler/ProfilerDatabase.cpp:
+        (JSC::Profiler::Database::newCompilation):
+        * profiler/ProfilerDatabase.h:
+        (Database):
+        * profiler/ProfilerOSRExit.cpp: Added.
+        (Profiler):
+        (JSC::Profiler::OSRExit::OSRExit):
+        (JSC::Profiler::OSRExit::~OSRExit):
+        (JSC::Profiler::OSRExit::toJS):
+        * profiler/ProfilerOSRExit.h: Added.
+        (Profiler):
+        (OSRExit):
+        (JSC::Profiler::OSRExit::id):
+        (JSC::Profiler::OSRExit::origin):
+        (JSC::Profiler::OSRExit::exitKind):
+        (JSC::Profiler::OSRExit::isWatchpoint):
+        (JSC::Profiler::OSRExit::counterAddress):
+        (JSC::Profiler::OSRExit::count):
+        * profiler/ProfilerOSRExitSite.cpp: Added.
+        (Profiler):
+        (JSC::Profiler::OSRExitSite::toJS):
+        * profiler/ProfilerOSRExitSite.h: Added.
+        (Profiler):
+        (OSRExitSite):
+        (JSC::Profiler::OSRExitSite::OSRExitSite):
+        (JSC::Profiler::OSRExitSite::codeAddress):
+        * runtime/CommonIdentifiers.h:
+
 2012-12-10  Alexis Menard  <alexis@webkit.org>
 
         [CSS3 Backgrounds and Borders] Remove CSS3_BACKGROUND feature flag.
index d0be71b..f57dc54 100644 (file)
@@ -110,6 +110,8 @@ javascriptcore_sources += \
        Source/JavaScriptCore/bytecode/EvalCodeCache.h \
        Source/JavaScriptCore/bytecode/ExecutionCounter.cpp \
        Source/JavaScriptCore/bytecode/ExecutionCounter.h \
+       Source/JavaScriptCore/bytecode/ExitKind.cpp \
+       Source/JavaScriptCore/bytecode/ExitKind.h \
        Source/JavaScriptCore/bytecode/ExpressionRangeInfo.h \
        Source/JavaScriptCore/bytecode/GetByIdStatus.cpp \
        Source/JavaScriptCore/bytecode/GetByIdStatus.h \
@@ -490,6 +492,10 @@ javascriptcore_sources += \
        Source/JavaScriptCore/profiler/ProfilerOrigin.h \
        Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp \
        Source/JavaScriptCore/profiler/ProfilerOriginStack.h \
+       Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp \
+       Source/JavaScriptCore/profiler/ProfilerOSRExit.h \
+       Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp \
+       Source/JavaScriptCore/profiler/ProfilerOSRExitSite.h \
        Source/JavaScriptCore/profiler/Profile.cpp \
        Source/JavaScriptCore/profiler/ProfileGenerator.cpp \
        Source/JavaScriptCore/profiler/ProfileGenerator.h \
index 68eadd6..ddc84ee 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\profiler\ProfilerOSRExit.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\profiler\ProfilerOSRExit.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\profiler\ProfilerOSRExitSite.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\profiler\ProfilerOSRExitSite.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\profiler\Profile.cpp"
                                >
                        </File>
                                >
                        </File>
                        <File
+                               RelativePath="..\..\bytecode\ExitKind.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\bytecode\ExitKind.cpp"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\bytecode\GetByIdStatus.cpp"
                                >
                        </File>
index b4f7368..eda1440 100644 (file)
                0FA581BC150E953000B9A2D9 /* DFGNodeType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FA581B9150E952A00B9A2D9 /* DFGNodeType.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FAF7EFD165BA91B000C8455 /* JITDisassembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FAF7EFA165BA919000C8455 /* JITDisassembler.cpp */; };
                0FAF7EFE165BA91F000C8455 /* JITDisassembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FAF7EFB165BA919000C8455 /* JITDisassembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FB105851675480F00F8AB6E /* ExitKind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB105821675480C00F8AB6E /* ExitKind.cpp */; };
+               0FB105861675481200F8AB6E /* ExitKind.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB105831675480C00F8AB6E /* ExitKind.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FB1058B1675483100F8AB6E /* ProfilerOSRExit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB105871675482E00F8AB6E /* ProfilerOSRExit.cpp */; };
+               0FB1058C1675483300F8AB6E /* ProfilerOSRExit.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB105881675482E00F8AB6E /* ProfilerOSRExit.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FB1058D1675483700F8AB6E /* ProfilerOSRExitSite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB105891675482E00F8AB6E /* ProfilerOSRExitSite.cpp */; };
+               0FB1058E1675483A00F8AB6E /* ProfilerOSRExitSite.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB1058A1675482E00F8AB6E /* ProfilerOSRExitSite.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FB5467714F59B5C002C2989 /* LazyOperandValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB5467614F59AD1002C2989 /* LazyOperandValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FB5467914F5C46B002C2989 /* LazyOperandValueProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB5467814F5C468002C2989 /* LazyOperandValueProfile.cpp */; };
                0FB5467B14F5C7E1002C2989 /* MethodOfGettingAValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB5467A14F5C7D4002C2989 /* MethodOfGettingAValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FA581B9150E952A00B9A2D9 /* DFGNodeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGNodeType.h; path = dfg/DFGNodeType.h; sourceTree = "<group>"; };
                0FAF7EFA165BA919000C8455 /* JITDisassembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITDisassembler.cpp; sourceTree = "<group>"; };
                0FAF7EFB165BA919000C8455 /* JITDisassembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITDisassembler.h; sourceTree = "<group>"; };
+               0FB105821675480C00F8AB6E /* ExitKind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExitKind.cpp; sourceTree = "<group>"; };
+               0FB105831675480C00F8AB6E /* ExitKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExitKind.h; sourceTree = "<group>"; };
+               0FB105871675482E00F8AB6E /* ProfilerOSRExit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProfilerOSRExit.cpp; path = profiler/ProfilerOSRExit.cpp; sourceTree = "<group>"; };
+               0FB105881675482E00F8AB6E /* ProfilerOSRExit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProfilerOSRExit.h; path = profiler/ProfilerOSRExit.h; sourceTree = "<group>"; };
+               0FB105891675482E00F8AB6E /* ProfilerOSRExitSite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProfilerOSRExitSite.cpp; path = profiler/ProfilerOSRExitSite.cpp; sourceTree = "<group>"; };
+               0FB1058A1675482E00F8AB6E /* ProfilerOSRExitSite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProfilerOSRExitSite.h; path = profiler/ProfilerOSRExitSite.h; sourceTree = "<group>"; };
                0FB5467614F59AD1002C2989 /* LazyOperandValueProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LazyOperandValueProfile.h; sourceTree = "<group>"; };
                0FB5467814F5C468002C2989 /* LazyOperandValueProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LazyOperandValueProfile.cpp; sourceTree = "<group>"; };
                0FB5467A14F5C7D4002C2989 /* MethodOfGettingAValueProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MethodOfGettingAValueProfile.h; sourceTree = "<group>"; };
                        isa = PBXGroup;
                        children = (
                                95E3BC040E1AE68200B2D1C1 /* CallIdentifier.h */,
+                               95AB832E0DA42CAD00BC83F3 /* LegacyProfiler.cpp */,
+                               95AB832F0DA42CAD00BC83F3 /* LegacyProfiler.h */,
+                               95742F630DD11F5A000917FB /* Profile.cpp */,
+                               95742F640DD11F5A000917FB /* Profile.h */,
+                               95CD45740E1C4FDD0085358E /* ProfileGenerator.cpp */,
+                               95CD45750E1C4FDD0085358E /* ProfileGenerator.h */,
+                               95AB83540DA43B4400BC83F3 /* ProfileNode.cpp */,
+                               95AB83550DA43B4400BC83F3 /* ProfileNode.h */,
                                0FF72992166AD347000F5BA3 /* ProfilerBytecode.cpp */,
                                0FF72993166AD347000F5BA3 /* ProfilerBytecode.h */,
                                0FF72994166AD347000F5BA3 /* ProfilerBytecodes.cpp */,
                                0FF729A0166AD347000F5BA3 /* ProfilerOrigin.h */,
                                0FF729A1166AD347000F5BA3 /* ProfilerOriginStack.cpp */,
                                0FF729A2166AD347000F5BA3 /* ProfilerOriginStack.h */,
-                               95742F630DD11F5A000917FB /* Profile.cpp */,
-                               95742F640DD11F5A000917FB /* Profile.h */,
-                               95CD45740E1C4FDD0085358E /* ProfileGenerator.cpp */,
-                               95CD45750E1C4FDD0085358E /* ProfileGenerator.h */,
-                               95AB83540DA43B4400BC83F3 /* ProfileNode.cpp */,
-                               95AB83550DA43B4400BC83F3 /* ProfileNode.h */,
-                               95AB832E0DA42CAD00BC83F3 /* LegacyProfiler.cpp */,
-                               95AB832F0DA42CAD00BC83F3 /* LegacyProfiler.h */,
+                               0FB105871675482E00F8AB6E /* ProfilerOSRExit.cpp */,
+                               0FB105881675482E00F8AB6E /* ProfilerOSRExit.h */,
+                               0FB105891675482E00F8AB6E /* ProfilerOSRExitSite.cpp */,
+                               0FB1058A1675482E00F8AB6E /* ProfilerOSRExitSite.h */,
                        );
                        name = profiler;
                        sourceTree = "<group>";
                                969A07920ED1D3AE00F1F681 /* EvalCodeCache.h */,
                                0F56A1D415001CF2002992B1 /* ExecutionCounter.cpp */,
                                0F56A1D115000F31002992B1 /* ExecutionCounter.h */,
+                               0FB105821675480C00F8AB6E /* ExitKind.cpp */,
+                               0FB105831675480C00F8AB6E /* ExitKind.h */,
                                0F0B83AA14BCF5B900885B4F /* ExpressionRangeInfo.h */,
                                0F93329514CA7DC10085F3C6 /* GetByIdStatus.cpp */,
                                0F93329614CA7DC10085F3C6 /* GetByIdStatus.h */,
                                0FF729BE166AD360000F5BA3 /* ProfilerExecutionCounter.h in Headers */,
                                0FF729BF166AD360000F5BA3 /* ProfilerOrigin.h in Headers */,
                                0FF729C0166AD360000F5BA3 /* ProfilerOriginStack.h in Headers */,
+                               0FB105861675481200F8AB6E /* ExitKind.h in Headers */,
+                               0FB1058C1675483300F8AB6E /* ProfilerOSRExit.h in Headers */,
+                               0FB1058E1675483A00F8AB6E /* ProfilerOSRExitSite.h in Headers */,
                                0FF60AC216740F8300029779 /* ReduceWhitespace.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                                0FF729B2166AD35C000F5BA3 /* ProfilerDatabase.cpp in Sources */,
                                0FF729B3166AD35C000F5BA3 /* ProfilerOrigin.cpp in Sources */,
                                0FF729B4166AD35C000F5BA3 /* ProfilerOriginStack.cpp in Sources */,
+                               0FB105851675480F00F8AB6E /* ExitKind.cpp in Sources */,
+                               0FB1058B1675483100F8AB6E /* ProfilerOSRExit.cpp in Sources */,
+                               0FB1058D1675483700F8AB6E /* ProfilerOSRExitSite.cpp in Sources */,
                                0FF60AC316740F8800029779 /* ReduceWhitespace.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
index 52197e6..03f85e7 100644 (file)
@@ -60,6 +60,7 @@ SOURCES += \
     bytecode/CodeType.cpp \
     bytecode/DFGExitProfile.cpp \
     bytecode/ExecutionCounter.cpp \
+    bytecode/ExitKind.cpp \
     bytecode/GetByIdStatus.cpp \
     bytecode/JumpTable.cpp \
     bytecode/LazyOperandValueProfile.cpp \
@@ -200,6 +201,8 @@ SOURCES += \
     profiler/ProfilerOrigin.h \
     profiler/ProfilerOriginStack.cpp \
     profiler/ProfilerOriginStack.h \
+    profiler/ProfilerOSRExit.cpp \
+    profiler/ProfilerOSRExitSite.cpp \
     profiler/Profile.cpp \
     profiler/ProfileGenerator.cpp \
     profiler/ProfileNode.cpp \
index 673031b..7fbe0df 100644 (file)
@@ -528,6 +528,13 @@ public:
         {
         }
 #endif
+        
+        Label label() const
+        {
+            Label result;
+            result.m_label = m_label;
+            return result;
+        }
 
         void link(AbstractMacroAssembler<AssemblerType>* masm) const
         {
index fb2ccd2..a638993 100644 (file)
@@ -62,6 +62,7 @@
 #include "LazyOperandValueProfile.h"
 #include "LineInfo.h"
 #include "Nodes.h"
+#include "ProfilerCompilation.h"
 #include "RegExpObject.h"
 #include "ResolveOperation.h"
 #include "StructureStubInfo.h"
@@ -324,6 +325,19 @@ namespace JSC {
             m_dfgData = adoptPtr(new DFGData);
         }
         
+        void saveCompilation(PassRefPtr<Profiler::Compilation> compilation)
+        {
+            createDFGDataIfNecessary();
+            m_dfgData->compilation = compilation;
+        }
+        
+        Profiler::Compilation* compilation()
+        {
+            if (!m_dfgData)
+                return 0;
+            return m_dfgData->compilation.get();
+        }
+        
         DFG::OSREntryData* appendDFGOSREntryData(unsigned bytecodeIndex, unsigned machineCodeOffset)
         {
             createDFGDataIfNecessary();
@@ -1275,6 +1289,7 @@ namespace JSC {
             Vector<WriteBarrier<JSCell> > weakReferences;
             DFG::VariableEventStream variableEventStream;
             DFG::MinifiedGraph minifiedDFG;
+            RefPtr<Profiler::Compilation> compilation;
             bool mayBeExecuting;
             bool isJettisoned;
             bool livenessHasBeenProved; // Initialized and used on every GC.
index 7132adf..74dabae 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 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
 #ifndef DFGExitProfile_h
 #define DFGExitProfile_h
 
+#include "ExitKind.h"
 #include <wtf/HashSet.h>
 #include <wtf/OwnPtr.h>
 #include <wtf/Vector.h>
 
 namespace JSC { namespace DFG {
 
-enum ExitKind {
-    ExitKindUnset,
-    BadType, // We exited because a type prediction was wrong.
-    BadCache, // We exited because an inline cache was wrong.
-    BadWeakConstantCache, // We exited because a cache on a weak constant (usually a prototype) was wrong.
-    BadIndexingType, // We exited because an indexing type was wrong.
-    Overflow, // We exited because of overflow.
-    NegativeZero, // We exited because we encountered negative zero.
-    OutOfBounds, // We had an out-of-bounds access to an array.
-    InadequateCoverage, // We exited because we ended up in code that didn't have profiling coverage.
-    ArgumentsEscaped, // We exited because arguments escaped but we didn't expect them to.
-    Uncountable, // We exited for none of the above reasons, and we should not count it. Most uses of this should be viewed as a FIXME.
-    UncountableWatchpoint // We exited because of a watchpoint, which isn't counted because watchpoints do tracking themselves.
-};
-
-inline const char* exitKindToString(ExitKind kind)
-{
-    switch (kind) {
-    case ExitKindUnset:
-        return "Unset";
-    case BadType:
-        return "BadType";
-    case BadCache:
-        return "BadCache";
-    case BadWeakConstantCache:
-        return "BadWeakConstantCache";
-    case BadIndexingType:
-        return "BadIndexingType";
-    case Overflow:
-        return "Overflow";
-    case NegativeZero:
-        return "NegativeZero";
-    case OutOfBounds:
-        return "OutOfBounds";
-    case InadequateCoverage:
-        return "InadequateCoverage";
-    case ArgumentsEscaped:
-        return "ArgumentsEscaped";
-    case Uncountable:
-        return "Uncountable";
-    case UncountableWatchpoint:
-        return "UncountableWatchpoint";
-    default:
-        return "Unknown";
-    }
-}
-
-inline bool exitKindIsCountable(ExitKind kind)
-{
-    switch (kind) {
-    case ExitKindUnset:
-        ASSERT_NOT_REACHED();
-    case BadType:
-    case Uncountable:
-    case UncountableWatchpoint:
-        return false;
-    default:
-        return true;
-    }
-}
-
 class FrequentExitSite {
 public:
     FrequentExitSite()
diff --git a/Source/JavaScriptCore/bytecode/ExitKind.cpp b/Source/JavaScriptCore/bytecode/ExitKind.cpp
new file mode 100644 (file)
index 0000000..2902d35
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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 "ExitKind.h"
+
+#include <wtf/Assertions.h>
+#include <wtf/PrintStream.h>
+
+namespace JSC {
+
+const char* exitKindToString(ExitKind kind)
+{
+    switch (kind) {
+    case ExitKindUnset:
+        return "Unset";
+    case BadType:
+        return "BadType";
+    case BadCache:
+        return "BadCache";
+    case BadWeakConstantCache:
+        return "BadWeakConstantCache";
+    case BadIndexingType:
+        return "BadIndexingType";
+    case Overflow:
+        return "Overflow";
+    case NegativeZero:
+        return "NegativeZero";
+    case OutOfBounds:
+        return "OutOfBounds";
+    case InadequateCoverage:
+        return "InadequateCoverage";
+    case ArgumentsEscaped:
+        return "ArgumentsEscaped";
+    case Uncountable:
+        return "Uncountable";
+    case UncountableWatchpoint:
+        return "UncountableWatchpoint";
+    default:
+        return "Unknown";
+    }
+}
+
+bool exitKindIsCountable(ExitKind kind)
+{
+    switch (kind) {
+    case ExitKindUnset:
+        ASSERT_NOT_REACHED();
+    case BadType:
+    case Uncountable:
+    case UncountableWatchpoint:
+        return false;
+    default:
+        return true;
+    }
+}
+
+} // namespace JSC
+
+namespace WTF {
+
+void printInternal(PrintStream& out, JSC::ExitKind kind)
+{
+    out.print(exitKindToString(kind));
+}
+
+} // namespace WTF
+
diff --git a/Source/JavaScriptCore/bytecode/ExitKind.h b/Source/JavaScriptCore/bytecode/ExitKind.h
new file mode 100644 (file)
index 0000000..5578765
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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 ExitKind_h
+#define ExitKind_h
+
+namespace JSC {
+
+enum ExitKind {
+    ExitKindUnset,
+    BadType, // We exited because a type prediction was wrong.
+    BadCache, // We exited because an inline cache was wrong.
+    BadWeakConstantCache, // We exited because a cache on a weak constant (usually a prototype) was wrong.
+    BadIndexingType, // We exited because an indexing type was wrong.
+    Overflow, // We exited because of overflow.
+    NegativeZero, // We exited because we encountered negative zero.
+    OutOfBounds, // We had an out-of-bounds access to an array.
+    InadequateCoverage, // We exited because we ended up in code that didn't have profiling coverage.
+    ArgumentsEscaped, // We exited because arguments escaped but we didn't expect them to.
+    Uncountable, // We exited for none of the above reasons, and we should not count it. Most uses of this should be viewed as a FIXME.
+    UncountableWatchpoint // We exited because of a watchpoint, which isn't counted because watchpoints do tracking themselves.
+};
+
+const char* exitKindToString(ExitKind);
+bool exitKindIsCountable(ExitKind);
+
+} // namespace JSC
+
+namespace WTF {
+
+class PrintStream;
+void printInternal(PrintStream&, JSC::ExitKind);
+
+} // namespace WTF
+
+#endif // ExitKind_h
+
index e45e8db..bbf1396 100644 (file)
@@ -671,7 +671,7 @@ public:
     
     JSGlobalData& m_globalData;
     CodeBlock* m_codeBlock;
-    Profiler::Compilation* m_compilation;
+    RefPtr<Profiler::Compilation> m_compilation;
     CodeBlock* m_profiledBlock;
 
     Vector< OwnPtr<BasicBlock> , 8> m_blocks;
index 4c42f72..5408a6c 100644 (file)
@@ -51,6 +51,16 @@ JITCompiler::JITCompiler(Graph& dfg)
 
 void JITCompiler::linkOSRExits()
 {
+    if (m_graph.m_compilation) {
+        for (unsigned i = 0; i < codeBlock()->numberOfOSRExits(); ++i) {
+            OSRExit& exit = codeBlock()->osrExit(i);
+            if (exit.m_watchpointIndex == std::numeric_limits<unsigned>::max())
+                m_exitSiteLabels.append(exit.m_check.initialJump().label());
+            else
+                m_exitSiteLabels.append(codeBlock()->watchpoint(exit.m_watchpointIndex).sourceLabel());
+        }
+    }
+    
     for (unsigned i = 0; i < codeBlock()->numberOfOSRExits(); ++i) {
         OSRExit& exit = codeBlock()->osrExit(i);
         ASSERT(!exit.m_check.isSet() == (exit.m_watchpointIndex != std::numeric_limits<unsigned>::max()));
@@ -206,6 +216,17 @@ void JITCompiler::link(LinkBuffer& linkBuffer)
             codeBlock()->watchpoint(exit.m_watchpointIndex).correctLabels(linkBuffer);
     }
     
+    if (m_graph.m_compilation) {
+        ASSERT(m_exitSiteLabels.size() == codeBlock()->numberOfOSRExits());
+        for (unsigned i = 0; i < m_exitSiteLabels.size(); ++i) {
+            m_graph.m_compilation->addOSRExitSite(
+                linkBuffer.locationOf(m_exitSiteLabels[i]).executableAddress());
+        }
+    } else
+        ASSERT(!m_exitSiteLabels.size());
+    
+    codeBlock()->saveCompilation(m_graph.m_compilation);
+    
     codeBlock()->minifiedDFG().setOriginalGraphSize(m_graph.size());
     codeBlock()->shrinkToFit(CodeBlock::LateShrink);
 }
@@ -239,7 +260,7 @@ bool JITCompiler::compile(JITCode& entry)
     if (shouldShowDisassembly())
         m_disassembler->dump(linkBuffer);
     if (m_graph.m_compilation)
-        m_disassembler->reportToProfiler(m_graph.m_compilation, linkBuffer);
+        m_disassembler->reportToProfiler(m_graph.m_compilation.get(), linkBuffer);
 
     entry = JITCode(
         linkBuffer.finalizeCodeWithoutDisassembly(),
@@ -332,7 +353,7 @@ bool JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWi
     if (shouldShowDisassembly())
         m_disassembler->dump(linkBuffer);
     if (m_graph.m_compilation)
-        m_disassembler->reportToProfiler(m_graph.m_compilation, linkBuffer);
+        m_disassembler->reportToProfiler(m_graph.m_compilation.get(), linkBuffer);
 
     entryWithArityCheck = linkBuffer.locationOf(arityCheck);
     entry = JITCode(
index 0bd88b7..d010a9c 100644 (file)
@@ -460,6 +460,7 @@ private:
     
     Vector<PropertyAccessRecord, 4> m_propertyAccesses;
     Vector<JSCallRecord, 4> m_jsCalls;
+    Vector<Label> m_exitSiteLabels;
     unsigned m_currentCodeOriginIndex;
 };
 
index 5d2155c..3a54dec 100644 (file)
@@ -85,7 +85,7 @@ void compileOSRExit(ExecState* exec)
     dataLog(
         "Generating OSR exit #", exitIndex, " (seq#", exit.m_streamIndex,
         ", bc#", exit.m_codeOrigin.bytecodeIndex, ", @", exit.m_nodeIndex, ", ",
-        exitKindToString(exit.m_kind), ") for ", *codeBlock, ".\n");
+        exit.m_kind, ") for ", *codeBlock, ".\n");
 #endif
 
     {
@@ -93,6 +93,18 @@ void compileOSRExit(ExecState* exec)
         OSRExitCompiler exitCompiler(jit);
 
         jit.jitAssertHasValidCallFrame();
+        
+        if (globalData->m_perBytecodeProfiler && codeBlock->compilation()) {
+            Profiler::Database& database = *globalData->m_perBytecodeProfiler;
+            Profiler::Compilation* compilation = codeBlock->compilation();
+            
+            Profiler::OSRExit* profilerExit = compilation->addOSRExit(
+                exitIndex, Profiler::OriginStack(database, codeBlock, exit.m_codeOrigin),
+                exit.m_kind,
+                exit.m_watchpointIndex != std::numeric_limits<unsigned>::max());
+            jit.add64(CCallHelpers::TrustedImm32(1), CCallHelpers::AbsoluteAddress(profilerExit->counterAddress()));
+        }
+        
         exitCompiler.compileExit(exit, operands, recovery);
         
         LinkBuffer patchBuffer(*globalData, &jit, codeBlock);
index 1592347..9c499a3 100644 (file)
@@ -89,7 +89,6 @@ JIT::JIT(JSGlobalData* globalData, CodeBlock* codeBlock)
     , m_lastResultBytecodeRegister(std::numeric_limits<int>::max())
     , m_jumpTargetsPosition(0)
 #endif
-    , m_compilation(0)
 #if USE(OS_RANDOMNESS)
     , m_randomGenerator(cryptographicallyRandomNumber())
 #else
@@ -838,7 +837,7 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo
     if (Options::showDisassembly())
         m_disassembler->dump(patchBuffer);
     if (m_compilation)
-        m_disassembler->reportToProfiler(m_compilation, patchBuffer);
+        m_disassembler->reportToProfiler(m_compilation.get(), patchBuffer);
     
     CodeRef result = patchBuffer.finalizeCodeWithoutDisassembly();
     
index 8780f1c..ae92b7c 100644 (file)
@@ -947,7 +947,7 @@ namespace JSC {
 #endif
 #endif
         OwnPtr<JITDisassembler> m_disassembler;
-        Profiler::Compilation* m_compilation;
+        RefPtr<Profiler::Compilation> m_compilation;
         WeakRandom m_randomGenerator;
         static CodeRef stringGetByValStubGenerator(JSGlobalData*);
 
index b4f35c7..457cbb2 100644 (file)
@@ -50,6 +50,13 @@ public:
     {
     }
     
+    MacroAssembler::Label sourceLabel() const
+    {
+        MacroAssembler::Label label;
+        label.m_label.m_offset = m_source;
+        return label;
+    }
+    
     void setDestination(MacroAssembler::Label destination)
     {
         m_destination = destination.m_label.m_offset;
index a4dcba0..fc1901f 100644 (file)
@@ -56,6 +56,17 @@ ExecutionCounter* Compilation::executionCounterFor(const OriginStack& origin)
     return result;
 }
 
+void Compilation::addOSRExitSite(const void* codeAddress)
+{
+    m_osrExitSites.append(OSRExitSite(codeAddress));
+}
+
+OSRExit* Compilation::addOSRExit(unsigned id, const OriginStack& originStack, ExitKind exitKind, bool isWatchpoint)
+{
+    m_osrExits.append(OSRExit(id, originStack, exitKind, isWatchpoint));
+    return &m_osrExits.last();
+}
+
 JSValue Compilation::toJS(ExecState* exec) const
 {
     JSObject* result = constructEmptyObject(exec);
@@ -78,6 +89,16 @@ JSValue Compilation::toJS(ExecState* exec) const
     }
     result->putDirect(exec->globalData(), exec->propertyNames().counters, counters);
     
+    JSArray* exitSites = constructEmptyArray(exec, 0);
+    for (unsigned i = 0; i < m_osrExitSites.size(); ++i)
+        exitSites->putDirectIndex(exec, i, m_osrExitSites[i].toJS(exec));
+    result->putDirect(exec->globalData(), exec->propertyNames().osrExitSites, exitSites);
+    
+    JSArray* exits = constructEmptyArray(exec, 0);
+    for (unsigned i = 0; i < m_osrExits.size(); ++i)
+        exits->putDirectIndex(exec, i, m_osrExits[i].toJS(exec));
+    result->putDirect(exec->globalData(), exec->propertyNames().osrExits, exits);
+    
     return result;
 }
 
index d14c05c..697b8cf 100644 (file)
 #ifndef ProfilerCompilation_h
 #define ProfilerCompilation_h
 
+#include "ExitKind.h"
 #include "JSValue.h"
 #include "ProfilerCompilationKind.h"
 #include "ProfilerCompiledBytecode.h"
 #include "ProfilerExecutionCounter.h"
+#include "ProfilerOSRExit.h"
+#include "ProfilerOSRExitSite.h"
 #include "ProfilerOriginStack.h"
-#include <wtf/FastAllocBase.h>
-#include <wtf/Noncopyable.h>
+#include <wtf/RefCounted.h>
+#include <wtf/SegmentedVector.h>
 
 namespace JSC { namespace Profiler {
 
@@ -41,8 +44,7 @@ class Bytecodes;
 // Represents the act of executing some bytecodes in some engine, and does
 // all of the counting for those executions.
 
-class Compilation {
-    WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(Compilation);
+class Compilation : public RefCounted<Compilation> {
 public:
     Compilation(Bytecodes*, CompilationKind);
     ~Compilation();
@@ -52,6 +54,8 @@ public:
     
     void addDescription(const CompiledBytecode&);
     ExecutionCounter* executionCounterFor(const OriginStack&);
+    void addOSRExitSite(const void* codeAddress);
+    OSRExit* addOSRExit(unsigned id, const OriginStack&, ExitKind, bool isWatchpoint);
     
     JSValue toJS(ExecState*) const;
     
@@ -60,6 +64,8 @@ private:
     CompilationKind m_kind;
     Vector<CompiledBytecode> m_descriptions;
     HashMap<OriginStack, OwnPtr<ExecutionCounter> > m_counters;
+    Vector<OSRExitSite> m_osrExitSites;
+    SegmentedVector<OSRExit> m_osrExits;
 };
 
 } } // namespace JSC::Profiler
index 72e083a..fce17e9 100644 (file)
@@ -79,15 +79,14 @@ void Database::notifyDestruction(CodeBlock* codeBlock)
     m_bytecodesMap.remove(codeBlock);
 }
 
-Compilation* Database::newCompilation(Bytecodes* bytecodes, CompilationKind kind)
+PassRefPtr<Compilation> Database::newCompilation(Bytecodes* bytecodes, CompilationKind kind)
 {
-    OwnPtr<Compilation> compilation = adoptPtr(new Compilation(bytecodes, kind));
-    Compilation* result = compilation.get();
-    m_compilations.append(compilation.release());
-    return result;
+    RefPtr<Compilation> compilation = adoptRef(new Compilation(bytecodes, kind));
+    m_compilations.append(compilation);
+    return compilation.release();
 }
 
-Compilation* Database::newCompilation(CodeBlock* codeBlock, CompilationKind kind)
+PassRefPtr<Compilation> Database::newCompilation(CodeBlock* codeBlock, CompilationKind kind)
 {
     return newCompilation(ensureBytecodesFor(codeBlock), kind);
 }
index d45d654..5f1270d 100644 (file)
@@ -33,6 +33,7 @@
 #include <wtf/FastAllocBase.h>
 #include <wtf/HashMap.h>
 #include <wtf/Noncopyable.h>
+#include <wtf/PassRefPtr.h>
 #include <wtf/SegmentedVector.h>
 #include <wtf/text/WTFString.h>
 
@@ -47,8 +48,8 @@ public:
     Bytecodes* ensureBytecodesFor(CodeBlock*);
     void notifyDestruction(CodeBlock*);
     
-    Compilation* newCompilation(CodeBlock*, CompilationKind);
-    Compilation* newCompilation(Bytecodes*, CompilationKind);
+    PassRefPtr<Compilation> newCompilation(CodeBlock*, CompilationKind);
+    PassRefPtr<Compilation> newCompilation(Bytecodes*, CompilationKind);
     
     // Converts the database to a JavaScript object that is suitable for JSON stringification.
     // Note that it's probably a good idea to use an ExecState* associated with a global
@@ -70,7 +71,7 @@ private:
     JSGlobalData& m_globalData;
     SegmentedVector<Bytecodes> m_bytecodes;
     HashMap<CodeBlock*, Bytecodes*> m_bytecodesMap;
-    Vector<OwnPtr<Compilation> > m_compilations;
+    Vector<RefPtr<Compilation> > m_compilations;
 };
 
 } } // namespace JSC::Profiler
diff --git a/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp b/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp
new file mode 100644 (file)
index 0000000..da0398d
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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 "ProfilerOSRExit.h"
+
+#include "JSGlobalObject.h"
+
+namespace JSC { namespace Profiler {
+
+OSRExit::OSRExit(unsigned id, const OriginStack& origin, ExitKind kind, bool isWatchpoint)
+    : m_id(id)
+    , m_origin(origin)
+    , m_exitKind(kind)
+    , m_isWatchpoint(isWatchpoint)
+    , m_counter(0)
+{
+}
+
+OSRExit::~OSRExit()
+{
+}
+
+JSValue OSRExit::toJS(ExecState* exec) const
+{
+    JSObject* result = constructEmptyObject(exec);
+    result->putDirect(exec->globalData(), exec->propertyNames().id, jsNumber(m_id));
+    result->putDirect(exec->globalData(), exec->propertyNames().origin, m_origin.toJS(exec));
+    result->putDirect(exec->globalData(), exec->propertyNames().exitKind, jsString(exec, exitKindToString(m_exitKind)));
+    result->putDirect(exec->globalData(), exec->propertyNames().isWatchpoint, jsBoolean(m_isWatchpoint));
+    result->putDirect(exec->globalData(), exec->propertyNames().count, jsNumber(m_counter));
+    return result;
+}
+
+} } // namespace JSC::Profiler
+
diff --git a/Source/JavaScriptCore/profiler/ProfilerOSRExit.h b/Source/JavaScriptCore/profiler/ProfilerOSRExit.h
new file mode 100644 (file)
index 0000000..b96d1d6
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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 ProfilerOSRExit_h
+#define ProfilerOSRExit_h
+
+#include "ExitKind.h"
+#include "JSValue.h"
+#include "ProfilerOriginStack.h"
+
+namespace JSC { namespace Profiler {
+
+class OSRExit {
+public:
+    OSRExit(unsigned id, const OriginStack&, ExitKind, bool isWatchpoint);
+    ~OSRExit();
+    
+    unsigned id() const { return m_id; }
+    const OriginStack& origin() const { return m_origin; }
+    ExitKind exitKind() const { return m_exitKind; }
+    bool isWatchpoint() const { return m_isWatchpoint; }
+    
+    uint64_t* counterAddress() { return &m_counter; }
+    uint64_t count() const { return m_counter; }
+    
+    JSValue toJS(ExecState*) const;
+
+private:
+    unsigned m_id;
+    OriginStack m_origin;
+    ExitKind m_exitKind;
+    bool m_isWatchpoint;
+    uint64_t m_counter;
+};
+
+} } // namespace JSC::Profiler
+
+#endif // ProfilerOSRExit_h
+
diff --git a/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp b/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp
new file mode 100644 (file)
index 0000000..908236f
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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 "ProfilerOSRExitSite.h"
+
+#include "JSScope.h"
+#include "JSString.h"
+#include <wtf/StringPrintStream.h>
+
+namespace JSC { namespace Profiler {
+
+JSValue OSRExitSite::toJS(ExecState* exec) const
+{
+    return jsString(exec, toString(RawPointer(m_codeAddress)));
+}
+
+} } // namespace JSC::Profiler
+
diff --git a/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.h b/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.h
new file mode 100644 (file)
index 0000000..9339ac1
--- /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 ProfilerOSRExitSite_h
+#define ProfilerOSRExitSite_h
+
+#include "JSValue.h"
+
+namespace JSC { namespace Profiler {
+
+class OSRExitSite {
+public:
+    explicit OSRExitSite(const void* codeAddress)
+        : m_codeAddress(codeAddress)
+    {
+    }
+    
+    const void* codeAddress() const { return m_codeAddress; }
+    
+    JSValue toJS(ExecState*) const;
+
+private:
+    const void* m_codeAddress;
+};
+
+} } // namespace JSC::Profiler
+
+#endif // ProfilerOSRExitSite_h
+
index 91d2e08..1011969 100644 (file)
@@ -43,6 +43,7 @@
     macro(compile) \
     macro(configurable) \
     macro(constructor) \
+    macro(count) \
     macro(counters) \
     macro(description) \
     macro(descriptions) \
     macro(eval) \
     macro(exec) \
     macro(executionCount) \
+    macro(exitKind) \
     macro(fromCharCode) \
     macro(global) \
     macro(get) \
     macro(hasOwnProperty) \
     macro(hash) \
+    macro(id) \
     macro(ignoreCase) \
     macro(index) \
     macro(input) \
     macro(isArray) \
     macro(isPrototypeOf) \
+    macro(isWatchpoint) \
     macro(lastIndex) \
     macro(length) \
     macro(message) \
@@ -69,6 +73,8 @@
     macro(Object) \
     macro(opcode) \
     macro(origin) \
+    macro(osrExitSites) \
+    macro(osrExits) \
     macro(parse) \
     macro(propertyIsEnumerable) \
     macro(prototype) \
index 59e1293..ddad26c 100644 (file)
@@ -1,3 +1,17 @@
+2012-12-09  Filip Pizlo  <fpizlo@apple.com>
+
+        Profiler should say things about OSR exits
+        https://bugs.webkit.org/show_bug.cgi?id=104497
+
+        Reviewed by Oliver Hunt.
+
+        Adds support for displaying OSR exit information for full summary (just displays the
+        counts and the number of recompilations), bytecode display (says which bytecodes
+        exited), and DFG display (annotates disassembly with taken OSR exits and their
+        counts).
+
+        * Scripts/display-profiler-output:
+
 2012-12-10  Alexis Menard  <alexis@webkit.org>
 
         [CSS3 Backgrounds and Borders] Remove CSS3_BACKGROUND feature flag.
index bdd871e..0f2595c 100755 (executable)
@@ -41,7 +41,7 @@ rescue LoadError
 end
 
 class Bytecode
-    attr_accessor :bytecodes, :bytecodeIndex, :opcode, :description, :topCounts, :bottomCounts, :machineInlinees
+    attr_accessor :bytecodes, :bytecodeIndex, :opcode, :description, :topCounts, :bottomCounts, :machineInlinees, :osrExits
     
     def initialize(bytecodes, bytecodeIndex, opcode, description)
         @bytecodes = bytecodes
@@ -51,6 +51,7 @@ class Bytecode
         @topCounts = [] # "source" counts
         @bottomCounts = {} # "machine" counts, maps compilations to counts
         @machineInlinees = {} # maps my compilation to a set of inlinees
+        @osrExits = []
     end
     
     def shouldHaveCounts?
@@ -120,6 +121,15 @@ class Bytecode
         }
         sum
     end
+    
+    def totalExitCount
+        sum = 0
+        @osrExits.each {
+            | exit |
+            sum += exit.count
+        }
+        sum
+    end
 end
 
 class Bytecodes
@@ -207,6 +217,15 @@ class Bytecodes
         }
         max
     end
+    
+    def totalExitCount
+        sum = 0
+        each {
+            | bytecode |
+            sum += bytecode.totalExitCount
+        }
+        sum
+    end
 end
 
 def originStackFromJSON(json)
@@ -235,8 +254,25 @@ class ExecutionCounter
     end
 end
 
+class OSRExit
+    attr_reader :compilation, :origin, :codeAddress, :exitKind, :isWatchpoint, :count
+    
+    def initialize(compilation, origin, codeAddress, exitKind, isWatchpoint, count)
+        @compilation = compilation
+        @origin = origin
+        @codeAddress = codeAddress
+        @exitKind = exitKind
+        @isWatchpoint = isWatchpoint
+        @count = count
+    end
+    
+    def dumpForDisplay(prefix)
+        puts(prefix + "EXIT: due to #{@exitKind}, #{@count} times")
+    end
+end
+
 class Compilation
-    attr_accessor :bytecode, :engine, :descriptions, :counters, :compilationIndex
+    attr_accessor :bytecode, :engine, :descriptions, :counters, :compilationIndex, :osrExits
     
     def initialize(json)
         @bytecode = $bytecodes[json["bytecodesID"].to_i]
@@ -265,6 +301,16 @@ class Compilation
             origin[-1].addTopCount(counter)
             origin[0].addBottomCountForCompilation(counter, self)
         }
+        @osrExits = {}
+        json["osrExits"].each {
+            | subJson |
+            osrExit = OSRExit.new(self, originStackFromJSON(subJson["origin"]),
+                                  json["osrExitSites"][subJson["id"]].hex, subJson["exitKind"],
+                                  subJson["isWatchpoint"], subJson["count"])
+            osrExits[osrExit.codeAddress] = [] unless osrExits[osrExit.codeAddress]
+            osrExits[osrExit.codeAddress] << osrExit
+            osrExit.origin[-1].osrExits << osrExit
+        }
     end
     
     def counter(origin)
@@ -276,6 +322,25 @@ class Compilation
     end
 end
 
+class DescriptionLine
+    attr_reader :actualCountsString, :sourceCountsString, :disassembly, :shouldShow
+    
+    def initialize(actualCountsString, sourceCountsString, disassembly, shouldShow)
+        @actualCountsString = actualCountsString
+        @sourceCountsString = sourceCountsString
+        @disassembly = disassembly
+        @shouldShow = shouldShow
+    end
+    
+    def codeAddress
+        if @disassembly =~ /^\s*(0x[0-9a-fA-F]+):/
+            $1.hex
+        else
+            nil
+        end
+    end
+end
+            
 if ARGV.length != 1
     $stderr.puts "Usage: display-profiler-output <path to profiler output file>"
     $stderr.puts
@@ -348,15 +413,21 @@ def summary(mode)
     hashCols = 11
     remaining -= hashCols + 1
     
-    countCols = 10 * $engines.size
+    countCols = 9 * $engines.size
     remaining -= countCols + 1
     
     if mode == :full
-        machineCountCols = 10 * $engines.size
+        machineCountCols = 9 * $engines.size
         remaining -= machineCountCols + 1
         
+        compilationsCols = 7
+        remaining -= compilationsCols + 1
+        
         inlinesCols = 9
         remaining -= inlinesCols + 1
+        
+        exitCountCols = 7
+        remaining -= exitCountCols + 1
     end
     
     if remaining > 0
@@ -368,7 +439,9 @@ def summary(mode)
     print(center("CodeBlock", hashCols) + " " + center("Source Counts", countCols))
     if mode == :full
         print(" " + center("Machine Counts", machineCountCols))
+        print(" " + center("#Compil", compilationsCols))
         print(" " + center("Inlines", inlinesCols))
+        print(" " + center("#Exits", exitCountCols))
     end
     if sourceCols
         print(" " + center("Source", sourceCols))
@@ -378,6 +451,7 @@ def summary(mode)
     print(center("", hashCols) + " " + center("Base/DFG", countCols))
     if mode == :full
         print(" " + center("Base/DFG", machineCountCols))
+        print(" " + (" " * compilationsCols))
         print(" " + center("Src/Total", inlinesCols))
     end
     puts
@@ -396,7 +470,9 @@ def summary(mode)
                                    | engine |
                                    bytecode.maxBottomExecutionCount(engine).to_s
                                }.join("/"), machineCountCols))
+            print(" " + center(bytecode.compilations.size.to_s, compilationsCols))
             print(" " + center(bytecode.sourceMachineInlineSites.to_s + "/" + bytecode.totalMachineInlineSites.to_s, inlinesCols))
+            print(" " + center(bytecode.totalExitCount.to_s, exitCountCols))
         end
         if sourceCols
             print(" " + sourceOnOneLine(bytecode.source, sourceCols))
@@ -472,6 +548,11 @@ def executeCommand(*commandArray)
                     machineString = ""
                 end
                 puts(center(countsString, countCols) + " " + center(machineString, machineCols) + (" " * pad) + bytecode.description.chomp)
+                bytecode.osrExits.each {
+                    | exit |
+                    puts(center("!!!!!", countCols) + " " + center("!!!!!", machineCols) + (" " * (pad + 10)) +
+                         "EXIT: in #{exit.compilation} due to #{exit.exitKind}, #{exit.count} times")
+                }
             }
         }
     when "inlines"
@@ -551,6 +632,8 @@ def executeCommand(*commandArray)
             }
         }
     when "display", "d"
+        compilationIndex = nil
+        
         case args.length
         when 1
             hash = args[0]
@@ -568,6 +651,12 @@ def executeCommand(*commandArray)
             return
         end
         
+        if hash =~ /-([0-9]+)-/
+            hash = $~.pre_match
+            engine = $~.post_match
+            compilationIndex = $1.to_i
+        end
+        
         if engine and not $engines.index(engine)
             pattern = Regexp.new(Regexp.escape(engine), "i")
             trueEngine = nil
@@ -585,6 +674,8 @@ def executeCommand(*commandArray)
             engine = trueEngine
         end
         
+        hash = getHash(hash)
+        
         actualCountCols = 13
         sourceCountCols = 10 * $engines.size
         
@@ -593,6 +684,7 @@ def executeCommand(*commandArray)
             | compilation |
             next if compilation.bytecode.codeHash != hash
             next if engine and compilation.engine != engine
+            next if compilationIndex and compilation.compilationIndex != compilationIndex
             
             if first
                 first = false
@@ -603,11 +695,18 @@ def executeCommand(*commandArray)
             puts("Compilation #{compilation}:")
             puts(center("Actual Counts", actualCountCols) + " " + center("Source Counts", sourceCountCols) + " " + center("Disassembly in #{compilation.engine}", screenWidth - 1 - sourceCountCols - 1 - actualCountCols))
             puts((" " * actualCountCols) + " " + center("Base/DFG", sourceCountCols))
+
+            lines = []
+
             compilation.descriptions.each {
                 | description |
                 # FIXME: We should have a better way of detecting things like CountExecution nodes
                 # and slow path entries in the baseline JIT.
-                next if description.description =~ /CountExecution\(/ and compilation.engine == "DFG"
+                if description.description =~ /CountExecution\(/ and compilation.engine == "DFG"
+                    shouldShow = false
+                else
+                    shouldShow = true
+                end
                 if description.origin.empty? or not description.origin[-1].shouldHaveCounts? or (compilation.engine == "Baseline" and description.description =~ /^\s*\(S\)/)
                     actualCountsString = ""
                     sourceCountsString = ""
@@ -620,9 +719,55 @@ def executeCommand(*commandArray)
                 end
                 description.description.split("\n").each {
                     | line |
-                    puts(center(actualCountsString, actualCountCols) + " " + center(sourceCountsString, sourceCountCols) + " " + line.chomp)
+                    lines << DescriptionLine.new(actualCountsString, sourceCountsString, line.chomp, shouldShow)
                 }
             }
+            
+            exitPrefix = center("!!!!!", actualCountCols) + " " + center("!!!!!", sourceCountCols) + (" " * 25)
+            
+            lines.each_with_index {
+                | line, index |
+                codeAddress = line.codeAddress
+                if codeAddress
+                    list = compilation.osrExits[codeAddress]
+                    if list
+                        list.each {
+                            | exit |
+                            if exit.isWatchpoint
+                                exit.dumpForDisplay(exitPrefix)
+                            end
+                        }
+                    end
+                end
+                if line.shouldShow
+                    puts(center(line.actualCountsString, actualCountCols) + " " + center(line.sourceCountsString, sourceCountCols) + " " + line.disassembly)
+                end
+                if codeAddress
+                    # Find the next disassembly address.
+                    endIndex = index + 1
+                    endAddress = nil
+                    while endIndex < lines.size
+                        myAddress = lines[endIndex].codeAddress
+                        if myAddress
+                            endAddress = myAddress
+                            break
+                        end
+                        endIndex += 1
+                    end
+                    
+                    if endAddress
+                        list = compilation.osrExits[endAddress]
+                        if list
+                            list.each {
+                                | exit |
+                                unless exit.isWatchpoint
+                                    exit.dumpForDisplay(exitPrefix)
+                                end
+                            }
+                        end
+                    end
+                end
+            }
         }
     else
         puts "Invalid command: #{command}"