Unreviewed, rolling out r109837.
[WebKit-https.git] / Source / JavaScriptCore / tools / CodeProfile.cpp
1 /*
2  * Copyright (C) 2012 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "CodeProfile.h"
28
29 #include "CodeBlock.h"
30 #include "CodeProfiling.h"
31 #include "LinkBuffer.h"
32 #include "ProfileTreeNode.h"
33 #include "Vector.h"
34 #include <wtf/text/WTFString.h>
35
36 #if PLATFORM(MAC)
37 #include <cxxabi.h>
38 #include <dlfcn.h>
39 #include <execinfo.h>
40 #endif
41
42 namespace JSC {
43
44 // Map from CodeType enum to a corresponding name.
45 const char* CodeProfile::s_codeTypeNames[CodeProfile::NumberOfCodeTypes] = {
46     "[[EngineCode]]",
47     "[[GlobalThunk]]",
48     "[[RegExpCode]]",
49     "[[DFGJIT]]",
50     "[[BaselineOnly]]",
51     "[[BaselineProfile]]",
52     "[[BaselineOSR]]",
53     "[[EngineFrame]]"
54 };
55
56 // Helper function, find the symbol name for a pc in JSC.
57 static const char* symbolName(void* address)
58 {
59 #if PLATFORM(MAC)
60     Dl_info info;
61     if (!dladdr(address, &info) || !info.dli_sname)
62         return "<unknown>";
63
64     const char* mangledName = info.dli_sname;
65     const char* cxaDemangled = abi::__cxa_demangle(mangledName, 0, 0, 0);
66     return cxaDemangled ? cxaDemangled : mangledName;
67 #else
68     UNUSED_PARAM(address);
69     return "<unknown>";
70 #endif
71 }
72
73 // Helper function, truncate traces to prune the output & make very verbose mode a little more readable.
74 static bool truncateTrace(const char* symbolName)
75 {
76     return !strcmp(symbolName, "JSC::BytecodeGenerator::generate()")
77         || !strcmp(symbolName, "JSC::Parser<JSC::Lexer<unsigned char> >::parseInner()")
78         || !strcmp(symbolName, "WTF::fastMalloc(unsigned long)")
79         || !strcmp(symbolName, "WTF::calculateUTCOffset()")
80         || !strcmp(symbolName, "JSC::DFG::ByteCodeParser::parseCodeBlock()");
81         
82 }
83
84 // Each trace consists of a sequence of zero or more 'EngineFrame' entries,
85 // followed by a sample in JIT code, or one or more 'EngineFrame' entries,
86 // followed by a 'EngineCode' terminator.
87 void CodeProfile::sample(void* pc, void** framePointer)
88 {
89     // Disallow traces containing only a 'EngineCode' terminator, without any 'EngineFrame' frames.
90     if (!framePointer)
91         return;
92
93     while (framePointer) {
94         CodeType type;
95
96 #if ENABLE(JIT)
97         // Determine if this sample fell in JIT code, and if so, from which JIT & why.
98         void* ownerUID = CodeProfiling::getOwnerUIDForPC(pc);
99
100         if (!ownerUID)
101             type = EngineFrame;
102         else if (ownerUID == GLOBAL_THUNK_ID)
103             type = GlobalThunk;
104         else if (ownerUID == REGEXP_CODE_ID)
105             type = RegExpCode;
106         else {
107             CodeBlock* codeBlock = static_cast<CodeBlock*>(ownerUID);
108             if (codeBlock->getJITType() == JITCode::DFGJIT)
109                 type = DFGJIT;
110             else if (codeBlock->canCompileWithDFGState() == CodeBlock::CompileWithDFGFalse)
111                 type = BaselineOnly;
112             else if (codeBlock->replacement())
113                 type = BaselineOSR;
114             else
115                 type = BaselineProfile;
116         }
117 #else
118         type = EngineFrame;
119 #endif
120
121         // A sample in JIT code terminates the trace.
122         m_samples.append(CodeRecord(pc, type));
123         if (type != EngineFrame)
124             return;
125
126 #if PLATFORM(MAC) && CPU(X86_64)
127         // Walk up the stack.
128         pc = framePointer[1];
129         framePointer = reinterpret_cast<void**>(*framePointer);
130 #elif OS(LINUX) && CPU(X86)
131         // Don't unwind the stack as some dependent third party libraries
132         // may be compiled with -fomit-frame-pointer.
133         framePointer = 0;
134 #else
135         // This platform is not yet supported!
136         ASSERT_NOT_REACHED();
137 #endif
138     }
139
140     // If we get here, we walked the entire stack without finding any frames of JIT code.
141     m_samples.append(CodeRecord(0, EngineCode));
142 }
143
144 void CodeProfile::report()
145 {
146     dataLog("<CodeProfiling %s:%d>\n", m_file.data(), m_lineNo);
147
148     // How many frames of C-code to print - 0, if not verbose, 1 if verbose, up to 1024 if very verbose.
149     unsigned recursionLimit = CodeProfiling::beVeryVerbose() ? 1024 : CodeProfiling::beVerbose();
150
151     ProfileTreeNode profile;
152
153     // Walk through the sample buffer.
154     size_t trace = 0;
155     while (trace < m_samples.size()) {
156
157         // All traces are zero or more 'EngineFrame's, followed by a non-'EngineFrame'.
158         // Scan to find the last sample in the trace.
159         size_t lastInTrace = trace;
160         while (m_samples[lastInTrace].type == EngineFrame)
161             ++lastInTrace;
162
163         // We use the last sample type to look up a name (used as a bucket in the profiler).
164         ProfileTreeNode* callbacks = profile.sampleChild(s_codeTypeNames[m_samples[lastInTrace].type]);
165
166         // If there are any samples in C-code, add up to recursionLimit of them into the profile tree.
167         size_t lastEngineFrame = lastInTrace;
168         for (unsigned count = 0; lastEngineFrame > trace && count < recursionLimit; ++count) {
169             --lastEngineFrame;
170             ASSERT(m_samples[lastEngineFrame].type == EngineFrame);
171             const char* name = symbolName(m_samples[lastEngineFrame].pc);
172             callbacks = callbacks->sampleChild(name);
173             if (truncateTrace(name))
174                 break;
175         }
176
177         // Move on to the next trace.
178         trace = lastInTrace + 1;
179         ASSERT(trace <= m_samples.size());
180     }
181
182     // Output the profile tree.
183     dataLog("Total samples: %lld\n", static_cast<long long>(profile.childCount()));
184     profile.dump();
185     
186     for (size_t i = 0 ; i < m_children.size(); ++i)
187         m_children[i]->report();
188
189     dataLog("</CodeProfiling %s:%d>\n", m_file.data(), m_lineNo);
190 }
191
192 }