]> git.saurik.com Git - apple/javascriptcore.git/blame - tools/CodeProfile.cpp
JavaScriptCore-1097.13.tar.gz
[apple/javascriptcore.git] / tools / CodeProfile.cpp
CommitLineData
6fe7ccc8
A
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 <wtf/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
42namespace JSC {
43
44// Map from CodeType enum to a corresponding name.
45const 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.
57static 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.
74static 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.
87void 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
144void 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}