display-profiler-output should be able to show source code
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 5 Dec 2012 02:24:17 +0000 (02:24 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 5 Dec 2012 02:24:17 +0000 (02:24 +0000)
https://bugs.webkit.org/show_bug.cgi?id=104073

Reviewed by Oliver Hunt.

Source/JavaScriptCore:

Modify the profiler database to store source code. For functions, we store the
function including the function signature.

* bytecode/CodeBlock.h:
(JSC::CodeBlock::unlinkedCodeBlock):
(CodeBlock):
* profiler/ProfilerBytecodes.cpp:
(JSC::Profiler::Bytecodes::Bytecodes):
(JSC::Profiler::Bytecodes::toJS):
* profiler/ProfilerBytecodes.h:
(Bytecodes):
(JSC::Profiler::Bytecodes::sourceCode):
* profiler/ProfilerDatabase.cpp:
(JSC::Profiler::Database::addBytecodes):
(JSC::Profiler::Database::ensureBytecodesFor):
* profiler/ProfilerDatabase.h:
(Database):
* runtime/CommonIdentifiers.h:
* runtime/Executable.h:
(FunctionExecutable):
(JSC::FunctionExecutable::unlinkedExecutable):

Tools:

Display source code in the summary, using a one-line shortening.

* Scripts/display-profiler-output:

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp
Source/JavaScriptCore/profiler/ProfilerBytecodes.h
Source/JavaScriptCore/profiler/ProfilerDatabase.cpp
Source/JavaScriptCore/profiler/ProfilerDatabase.h
Source/JavaScriptCore/runtime/CommonIdentifiers.h
Source/JavaScriptCore/runtime/Executable.h
Tools/ChangeLog
Tools/Scripts/display-profiler-output

index c9ba7b6..11d16e6 100644 (file)
@@ -1,3 +1,32 @@
+2012-12-04  Filip Pizlo  <fpizlo@apple.com>
+
+        display-profiler-output should be able to show source code
+        https://bugs.webkit.org/show_bug.cgi?id=104073
+
+        Reviewed by Oliver Hunt.
+
+        Modify the profiler database to store source code. For functions, we store the
+        function including the function signature.
+
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::unlinkedCodeBlock):
+        (CodeBlock):
+        * profiler/ProfilerBytecodes.cpp:
+        (JSC::Profiler::Bytecodes::Bytecodes):
+        (JSC::Profiler::Bytecodes::toJS):
+        * profiler/ProfilerBytecodes.h:
+        (Bytecodes):
+        (JSC::Profiler::Bytecodes::sourceCode):
+        * profiler/ProfilerDatabase.cpp:
+        (JSC::Profiler::Database::addBytecodes):
+        (JSC::Profiler::Database::ensureBytecodesFor):
+        * profiler/ProfilerDatabase.h:
+        (Database):
+        * runtime/CommonIdentifiers.h:
+        * runtime/Executable.h:
+        (FunctionExecutable):
+        (JSC::FunctionExecutable::unlinkedExecutable):
+
 2012-12-02  Filip Pizlo  <fpizlo@apple.com>
 
         JSC should be able to report profiling data associated with the IR dumps and disassembly
index 599f541..3ec965e 100644 (file)
@@ -129,6 +129,8 @@ namespace JSC {
     public:
         JS_EXPORT_PRIVATE virtual ~CodeBlock();
         
+        UnlinkedCodeBlock* unlinkedCodeBlock() const { return m_unlinkedCode.get(); }
+
         CodeBlockHash hash() const;
         void dumpAssumingJITType(PrintStream&, JITCode::JITType) const;
         void dump(PrintStream&) const;
@@ -1188,8 +1190,6 @@ namespace JSC {
         virtual void visitWeakReferences(SlotVisitor&);
         virtual void finalizeUnconditionally();
 
-        UnlinkedCodeBlock* unlinkedCodeBlock() const { return m_unlinkedCode.get(); }
-
     private:
         friend class DFGCodeBlocks;
 
index 949e94b..76f668b 100644 (file)
@@ -31,8 +31,9 @@
 
 namespace JSC { namespace Profiler {
 
-Bytecodes::Bytecodes(size_t id, CodeBlockHash hash)
+Bytecodes::Bytecodes(size_t id, const String& sourceCode, CodeBlockHash hash)
     : m_id(id)
+    , m_sourceCode(sourceCode)
     , m_hash(hash)
 {
 }
@@ -59,6 +60,7 @@ JSValue Bytecodes::toJS(ExecState* exec) const
     JSObject* result = constructEmptyObject(exec);
     
     result->putDirect(exec->globalData(), exec->propertyNames().bytecodesID, jsNumber(m_id));
+    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);
index 1917ca8..9ca4d19 100644 (file)
 #include "JSValue.h"
 #include "ProfilerBytecode.h"
 #include <wtf/PrintStream.h>
+#include <wtf/text/WTFString.h>
 
 namespace JSC { namespace Profiler {
 
 class Bytecodes {
 public:
-    Bytecodes(size_t id, CodeBlockHash);
+    Bytecodes(size_t id, const String& sourceCode, CodeBlockHash);
     ~Bytecodes();
     
     void append(const Bytecode& bytecode) { m_bytecode.append(bytecode); }
     
     size_t id() const { return m_id; }
+    const String& sourceCode() const { return m_sourceCode; }
     CodeBlockHash hash() const { return m_hash; }
     
     // Note that this data structure is not indexed by bytecode index.
@@ -56,6 +58,7 @@ public:
     
 private:
     size_t m_id;
+    String m_sourceCode;
     CodeBlockHash m_hash;
     Vector<Bytecode> m_bytecode;
 };
index 191f6f2..2cef7cd 100644 (file)
@@ -41,9 +41,9 @@ Database::~Database()
 {
 }
 
-Bytecodes* Database::addBytecodes(CodeBlockHash hash)
+Bytecodes* Database::addBytecodes(CodeBlockHash hash, const String& sourceCode)
 {
-    m_bytecodes.append(Bytecodes(m_bytecodes.size(), hash));
+    m_bytecodes.append(Bytecodes(m_bytecodes.size(), sourceCode, hash));
     return &m_bytecodes.last();
 }
 
@@ -57,7 +57,25 @@ Bytecodes* Database::ensureBytecodesFor(CodeBlock* codeBlock)
     if (iter != m_bytecodesMap.end())
         return iter->value;
     
-    Bytecodes* result = addBytecodes(codeBlock->hash());
+    String sourceCode;
+    
+    if (codeBlock->codeType() == FunctionCode) {
+        SourceProvider* provider = codeBlock->source();
+        FunctionExecutable* executable = jsCast<FunctionExecutable*>(codeBlock->ownerExecutable());
+        UnlinkedFunctionExecutable* unlinked = executable->unlinkedExecutable();
+        unsigned unlinkedStartOffset = unlinked->startOffset();
+        unsigned linkedStartOffset = executable->source().startOffset();
+        int delta = linkedStartOffset - unlinkedStartOffset;
+        StringBuilder builder;
+        builder.append("function ");
+        builder.append(provider->getRange(
+            delta + unlinked->functionStartOffset(),
+            delta + unlinked->startOffset() + unlinked->sourceLength()));
+        sourceCode = builder.toString();
+    } else
+        sourceCode = codeBlock->ownerExecutable()->source().toString();
+    
+    Bytecodes* result = addBytecodes(codeBlock->hash(), sourceCode);
     
     for (unsigned bytecodeIndex = 0; bytecodeIndex < codeBlock->instructions().size();) {
         out.reset();
index cdffacc..d45d654 100644 (file)
@@ -65,7 +65,7 @@ public:
     JS_EXPORT_PRIVATE bool save(const char* filename) const;
 
 private:
-    Bytecodes* addBytecodes(CodeBlockHash);
+    Bytecodes* addBytecodes(CodeBlockHash, const String& sourceCode);
     
     JSGlobalData& m_globalData;
     SegmentedVector<Bytecodes> m_bytecodes;
index f053748..a9a43b9 100644 (file)
@@ -73,6 +73,7 @@
     macro(prototype) \
     macro(set) \
     macro(source) \
+    macro(sourceCode) \
     macro(stack) \
     macro(test) \
     macro(toExponential) \
index 83eb602..958f4f2 100644 (file)
@@ -564,6 +564,11 @@ namespace JSC {
         static FunctionExecutable* fromGlobalCode(const Identifier& name, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
 
         static void destroy(JSCell*);
+        
+        UnlinkedFunctionExecutable* unlinkedExecutable()
+        {
+            return m_unlinkedExecutable.get();
+        }
 
         // Returns either call or construct bytecode. This can be appropriate
         // for answering questions that that don't vary between call and construct --
index bc57cbe..e3620e7 100644 (file)
@@ -1,5 +1,16 @@
 2012-12-04  Filip Pizlo  <fpizlo@apple.com>
 
+        display-profiler-output should be able to show source code
+        https://bugs.webkit.org/show_bug.cgi?id=104073
+
+        Reviewed by Oliver Hunt.
+
+        Display source code in the summary, using a one-line shortening.
+
+        * Scripts/display-profiler-output:
+
+2012-12-04  Filip Pizlo  <fpizlo@apple.com>
+
         display-profiler-output should not use reflective infocation to resolve command names
 
         Rubber stamped by Mark Hahnenberg.
index 510c0da..7e06bb1 100755 (executable)
@@ -63,11 +63,12 @@ class Bytecode
 end
 
 class Bytecodes
-    attr_accessor :hash
+    attr_accessor :hash, :source
     include Enumerable
     
     def initialize(json)
         @hash = json["hash"].to_s
+        @source = json["sourceCode"].to_s
         @bytecode = {}
         json["bytecode"].each {
             | subJson |
@@ -201,6 +202,15 @@ def getHash(hash)
     end
 end
 
+def sourceOnOneLine(source)
+    source = source.gsub(/\s+/, ' ')
+    if source.size > 80
+        source[0..77] + "..."
+    else
+        source
+    end
+end
+
 def executeCommand(*commandArray)
     command = commandArray[0]
     args = commandArray[1..-1]
@@ -216,7 +226,7 @@ def executeCommand(*commandArray)
         hashCols = 14
         countCols = 10 * $engines.size
         
-        puts(rpad("CodeBlock", hashCols) + " " + rpad($engines.join("/") + " Counts", countCols))
+        puts(rpad("CodeBlock", hashCols) + " " + rpad($engines.join("/") + " Counts", countCols) + " Source")
         $bytecodes.sort {
             | a, b |
             b.totalMaxExecutionCount <=> a.totalMaxExecutionCount
@@ -226,7 +236,8 @@ def executeCommand(*commandArray)
                  center($engines.map {
                             | engine |
                             bytecode.maxExecutionCount(engine).to_s
-                        }.join("/"), countCols))
+                        }.join("/"), countCols) + " " +
+                 sourceOnOneLine(bytecode.source))
         }
     when "display", "d"
         case args.length