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