Gardening: fix CLOOP build after r182927.
[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 "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