]> git.saurik.com Git - apple/javascriptcore.git/blob - interpreter/StackVisitor.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / interpreter / StackVisitor.cpp
1 /*
2 * Copyright (C) 2013, 2015 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 "StackVisitor.h"
28
29 #include "CallFrameInlines.h"
30 #include "ClonedArguments.h"
31 #include "Executable.h"
32 #include "Interpreter.h"
33 #include "JSCInlines.h"
34 #include <wtf/DataLog.h>
35
36 namespace JSC {
37
38 StackVisitor::StackVisitor(CallFrame* startFrame)
39 {
40 m_frame.m_index = 0;
41 CallFrame* topFrame;
42 if (startFrame) {
43 m_frame.m_VMEntryFrame = startFrame->vm().topVMEntryFrame;
44 topFrame = startFrame->vm().topCallFrame;
45 } else {
46 m_frame.m_VMEntryFrame = 0;
47 topFrame = 0;
48 }
49 m_frame.m_callerIsVMEntryFrame = false;
50 readFrame(topFrame);
51
52 // Find the frame the caller wants to start unwinding from.
53 while (m_frame.callFrame() && m_frame.callFrame() != startFrame)
54 gotoNextFrame();
55 }
56
57 void StackVisitor::gotoNextFrame()
58 {
59 #if ENABLE(DFG_JIT)
60 if (m_frame.isInlinedFrame()) {
61 InlineCallFrame* inlineCallFrame = m_frame.inlineCallFrame();
62 CodeOrigin* callerCodeOrigin = &inlineCallFrame->caller;
63 readInlinedFrame(m_frame.callFrame(), callerCodeOrigin);
64 return;
65 }
66 #endif // ENABLE(DFG_JIT)
67 m_frame.m_VMEntryFrame = m_frame.m_CallerVMEntryFrame;
68 readFrame(m_frame.callerFrame());
69 }
70
71 void StackVisitor::readFrame(CallFrame* callFrame)
72 {
73 if (!callFrame) {
74 m_frame.setToEnd();
75 return;
76 }
77
78 #if !ENABLE(DFG_JIT)
79 readNonInlinedFrame(callFrame);
80
81 #else // !ENABLE(DFG_JIT)
82 // If the frame doesn't have a code block, then it's not a DFG frame.
83 // Hence, we're not at an inlined frame.
84 CodeBlock* codeBlock = callFrame->codeBlock();
85 if (!codeBlock) {
86 readNonInlinedFrame(callFrame);
87 return;
88 }
89
90 // If the code block does not have any code origins, then there's no
91 // inlining. Hence, we're not at an inlined frame.
92 if (!codeBlock->hasCodeOrigins()) {
93 readNonInlinedFrame(callFrame);
94 return;
95 }
96
97 unsigned index = callFrame->locationAsCodeOriginIndex();
98 ASSERT(codeBlock->canGetCodeOrigin(index));
99 if (!codeBlock->canGetCodeOrigin(index)) {
100 // See assertion above. In release builds, we try to protect ourselves
101 // from crashing even though stack walking will be goofed up.
102 m_frame.setToEnd();
103 return;
104 }
105
106 CodeOrigin codeOrigin = codeBlock->codeOrigin(index);
107 if (!codeOrigin.inlineCallFrame) {
108 readNonInlinedFrame(callFrame, &codeOrigin);
109 return;
110 }
111
112 readInlinedFrame(callFrame, &codeOrigin);
113 #endif // !ENABLE(DFG_JIT)
114 }
115
116 void StackVisitor::readNonInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin)
117 {
118 m_frame.m_callFrame = callFrame;
119 m_frame.m_argumentCountIncludingThis = callFrame->argumentCountIncludingThis();
120 m_frame.m_CallerVMEntryFrame = m_frame.m_VMEntryFrame;
121 m_frame.m_callerFrame = callFrame->callerFrame(m_frame.m_CallerVMEntryFrame);
122 m_frame.m_callerIsVMEntryFrame = m_frame.m_CallerVMEntryFrame != m_frame.m_VMEntryFrame;
123 m_frame.m_callee = callFrame->callee();
124 m_frame.m_codeBlock = callFrame->codeBlock();
125 m_frame.m_bytecodeOffset = !m_frame.codeBlock() ? 0
126 : codeOrigin ? codeOrigin->bytecodeIndex
127 : callFrame->locationAsBytecodeOffset();
128 #if ENABLE(DFG_JIT)
129 m_frame.m_inlineCallFrame = 0;
130 #endif
131 }
132
133 #if ENABLE(DFG_JIT)
134 static int inlinedFrameOffset(CodeOrigin* codeOrigin)
135 {
136 InlineCallFrame* inlineCallFrame = codeOrigin->inlineCallFrame;
137 int frameOffset = inlineCallFrame ? inlineCallFrame->stackOffset : 0;
138 return frameOffset;
139 }
140
141 void StackVisitor::readInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin)
142 {
143 ASSERT(codeOrigin);
144
145 int frameOffset = inlinedFrameOffset(codeOrigin);
146 bool isInlined = !!frameOffset;
147 if (isInlined) {
148 InlineCallFrame* inlineCallFrame = codeOrigin->inlineCallFrame;
149
150 m_frame.m_callFrame = callFrame;
151 m_frame.m_inlineCallFrame = inlineCallFrame;
152 if (inlineCallFrame->argumentCountRegister.isValid())
153 m_frame.m_argumentCountIncludingThis = callFrame->r(inlineCallFrame->argumentCountRegister.offset()).unboxedInt32();
154 else
155 m_frame.m_argumentCountIncludingThis = inlineCallFrame->arguments.size();
156 m_frame.m_codeBlock = inlineCallFrame->baselineCodeBlock();
157 m_frame.m_bytecodeOffset = codeOrigin->bytecodeIndex;
158
159 JSFunction* callee = inlineCallFrame->calleeForCallFrame(callFrame);
160 m_frame.m_callee = callee;
161 ASSERT(m_frame.callee());
162
163 // The callerFrame just needs to be non-null to indicate that we
164 // haven't reached the last frame yet. Setting it to the root
165 // frame (i.e. the callFrame that this inlined frame is called from)
166 // would work just fine.
167 m_frame.m_callerFrame = callFrame;
168 return;
169 }
170
171 readNonInlinedFrame(callFrame, codeOrigin);
172 }
173 #endif // ENABLE(DFG_JIT)
174
175 StackVisitor::Frame::CodeType StackVisitor::Frame::codeType() const
176 {
177 if (!isJSFrame())
178 return CodeType::Native;
179
180 switch (codeBlock()->codeType()) {
181 case EvalCode:
182 return CodeType::Eval;
183 case FunctionCode:
184 return CodeType::Function;
185 case GlobalCode:
186 return CodeType::Global;
187 }
188 RELEASE_ASSERT_NOT_REACHED();
189 return CodeType::Global;
190 }
191
192 String StackVisitor::Frame::functionName()
193 {
194 String traceLine;
195 JSObject* callee = this->callee();
196
197 switch (codeType()) {
198 case CodeType::Eval:
199 traceLine = ASCIILiteral("eval code");
200 break;
201 case CodeType::Native:
202 if (callee)
203 traceLine = getCalculatedDisplayName(callFrame(), callee).impl();
204 break;
205 case CodeType::Function:
206 traceLine = getCalculatedDisplayName(callFrame(), callee).impl();
207 break;
208 case CodeType::Global:
209 traceLine = ASCIILiteral("global code");
210 break;
211 }
212 return traceLine.isNull() ? emptyString() : traceLine;
213 }
214
215 String StackVisitor::Frame::sourceURL()
216 {
217 String traceLine;
218
219 switch (codeType()) {
220 case CodeType::Eval:
221 case CodeType::Function:
222 case CodeType::Global: {
223 String sourceURL = codeBlock()->ownerExecutable()->sourceURL();
224 if (!sourceURL.isEmpty())
225 traceLine = sourceURL.impl();
226 break;
227 }
228 case CodeType::Native:
229 traceLine = ASCIILiteral("[native code]");
230 break;
231 }
232 return traceLine.isNull() ? emptyString() : traceLine;
233 }
234
235 String StackVisitor::Frame::toString()
236 {
237 StringBuilder traceBuild;
238 String functionName = this->functionName();
239 String sourceURL = this->sourceURL();
240 traceBuild.append(functionName);
241 if (!sourceURL.isEmpty()) {
242 if (!functionName.isEmpty())
243 traceBuild.append('@');
244 traceBuild.append(sourceURL);
245 if (isJSFrame()) {
246 unsigned line = 0;
247 unsigned column = 0;
248 computeLineAndColumn(line, column);
249 traceBuild.append(':');
250 traceBuild.appendNumber(line);
251 traceBuild.append(':');
252 traceBuild.appendNumber(column);
253 }
254 }
255 return traceBuild.toString().impl();
256 }
257
258 ClonedArguments* StackVisitor::Frame::createArguments()
259 {
260 ASSERT(m_callFrame);
261 CallFrame* physicalFrame = m_callFrame;
262 ClonedArguments* arguments;
263 ArgumentsMode mode;
264 if (Options::enableFunctionDotArguments())
265 mode = ArgumentsMode::Cloned;
266 else
267 mode = ArgumentsMode::FakeValues;
268 #if ENABLE(DFG_JIT)
269 if (isInlinedFrame()) {
270 ASSERT(m_inlineCallFrame);
271 arguments = ClonedArguments::createWithInlineFrame(physicalFrame, physicalFrame, m_inlineCallFrame, mode);
272 } else
273 #endif
274 arguments = ClonedArguments::createWithMachineFrame(physicalFrame, physicalFrame, mode);
275 return arguments;
276 }
277
278 void StackVisitor::Frame::computeLineAndColumn(unsigned& line, unsigned& column)
279 {
280 CodeBlock* codeBlock = this->codeBlock();
281 if (!codeBlock) {
282 line = 0;
283 column = 0;
284 return;
285 }
286
287 int divot = 0;
288 int unusedStartOffset = 0;
289 int unusedEndOffset = 0;
290 unsigned divotLine = 0;
291 unsigned divotColumn = 0;
292 retrieveExpressionInfo(divot, unusedStartOffset, unusedEndOffset, divotLine, divotColumn);
293
294 line = divotLine + codeBlock->ownerExecutable()->firstLine();
295 column = divotColumn + (divotLine ? 1 : codeBlock->firstLineColumnOffset());
296
297 if (codeBlock->ownerExecutable()->hasOverrideLineNumber())
298 line = codeBlock->ownerExecutable()->overrideLineNumber();
299 }
300
301 void StackVisitor::Frame::retrieveExpressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column)
302 {
303 CodeBlock* codeBlock = this->codeBlock();
304 codeBlock->unlinkedCodeBlock()->expressionRangeForBytecodeOffset(bytecodeOffset(), divot, startOffset, endOffset, line, column);
305 divot += codeBlock->sourceOffset();
306 }
307
308 void StackVisitor::Frame::setToEnd()
309 {
310 m_callFrame = 0;
311 #if ENABLE(DFG_JIT)
312 m_inlineCallFrame = 0;
313 #endif
314 }
315
316 static void printIndents(int levels)
317 {
318 while (levels--)
319 dataLogFString(" ");
320 }
321
322 template<typename... Types>
323 void log(unsigned indent, const Types&... values)
324 {
325 printIndents(indent);
326 dataLog(values...);
327 }
328
329 template<typename... Types>
330 void logF(unsigned indent, const char* format, const Types&... values)
331 {
332 printIndents(indent);
333
334 #if COMPILER(CLANG) || COMPILER(GCC)
335 #pragma GCC diagnostic push
336 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
337 #pragma GCC diagnostic ignored "-Wmissing-format-attribute"
338 #endif
339
340 dataLogF(format, values...);
341
342 #if COMPILER(CLANG) || COMPILER(GCC)
343 #pragma GCC diagnostic pop
344 #endif
345 }
346
347 void StackVisitor::Frame::print(int indent)
348 {
349 if (!this->callFrame()) {
350 log(indent, "frame 0x0\n");
351 return;
352 }
353
354 CodeBlock* codeBlock = this->codeBlock();
355 logF(indent, "frame %p {\n", this->callFrame());
356
357 {
358 indent++;
359
360 CallFrame* callFrame = m_callFrame;
361 CallFrame* callerFrame = this->callerFrame();
362 void* returnPC = callFrame->hasReturnPC() ? callFrame->returnPC().value() : nullptr;
363
364 log(indent, "name: ", functionName(), "\n");
365 log(indent, "sourceURL: ", sourceURL(), "\n");
366
367 bool isInlined = false;
368 #if ENABLE(DFG_JIT)
369 isInlined = isInlinedFrame();
370 log(indent, "isInlinedFrame: ", isInlinedFrame(), "\n");
371 if (isInlinedFrame())
372 logF(indent, "InlineCallFrame: %p\n", m_inlineCallFrame);
373 #endif
374
375 logF(indent, "callee: %p\n", callee());
376 logF(indent, "returnPC: %p\n", returnPC);
377 logF(indent, "callerFrame: %p\n", callerFrame);
378 unsigned locationRawBits = callFrame->locationAsRawBits();
379 logF(indent, "rawLocationBits: %u 0x%x\n", locationRawBits, locationRawBits);
380 logF(indent, "codeBlock: %p ", codeBlock);
381 if (codeBlock)
382 dataLog(*codeBlock);
383 dataLog("\n");
384 if (codeBlock && !isInlined) {
385 indent++;
386
387 if (callFrame->hasLocationAsBytecodeOffset()) {
388 unsigned bytecodeOffset = callFrame->locationAsBytecodeOffset();
389 log(indent, "bytecodeOffset: ", bytecodeOffset, " of ", codeBlock->instructions().size(), "\n");
390 #if ENABLE(DFG_JIT)
391 } else {
392 log(indent, "hasCodeOrigins: ", codeBlock->hasCodeOrigins(), "\n");
393 if (codeBlock->hasCodeOrigins()) {
394 unsigned codeOriginIndex = callFrame->locationAsCodeOriginIndex();
395 log(indent, "codeOriginIndex: ", codeOriginIndex, " of ", codeBlock->codeOrigins().size(), "\n");
396
397 JITCode::JITType jitType = codeBlock->jitType();
398 if (jitType != JITCode::FTLJIT) {
399 JITCode* jitCode = codeBlock->jitCode().get();
400 logF(indent, "jitCode: %p start %p end %p\n", jitCode, jitCode->start(), jitCode->end());
401 }
402 }
403 #endif
404 }
405 unsigned line = 0;
406 unsigned column = 0;
407 computeLineAndColumn(line, column);
408 log(indent, "line: ", line, "\n");
409 log(indent, "column: ", column, "\n");
410
411 indent--;
412 }
413 indent--;
414 }
415 log(indent, "}\n");
416 }
417
418 } // namespace JSC