833df06da0a101f30d4ff5e77130d1577e5ad660
[WebKit-https.git] / Source / JavaScriptCore / interpreter / StackVisitor.cpp
1 /*
2  * Copyright (C) 2013-2018 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 "DebuggerPrimitives.h"
31 #include "InlineCallFrame.h"
32 #include "Interpreter.h"
33 #include "JSCInlines.h"
34 #include "WasmCallee.h"
35 #include "WasmIndexOrName.h"
36 #include <wtf/text/StringBuilder.h>
37
38 namespace JSC {
39
40 StackVisitor::StackVisitor(CallFrame* startFrame, VM* vm)
41 {
42     m_frame.m_index = 0;
43     m_frame.m_isWasmFrame = false;
44     CallFrame* topFrame;
45     if (startFrame) {
46         ASSERT(vm);
47         ASSERT(!vm->topCallFrame || reinterpret_cast<void*>(vm->topCallFrame) != vm->topEntryFrame);
48
49         m_frame.m_entryFrame = vm->topEntryFrame;
50         topFrame = vm->topCallFrame;
51
52         if (topFrame && topFrame->isStackOverflowFrame()) {
53             topFrame = topFrame->callerFrame(m_frame.m_entryFrame);
54             m_topEntryFrameIsEmpty = (m_frame.m_entryFrame != vm->topEntryFrame);
55             if (startFrame == vm->topCallFrame)
56                 startFrame = topFrame;
57         }
58
59     } else {
60         m_frame.m_entryFrame = 0;
61         topFrame = 0;
62     }
63     m_frame.m_callerIsEntryFrame = false;
64     readFrame(topFrame);
65
66     // Find the frame the caller wants to start unwinding from.
67     while (m_frame.callFrame() && m_frame.callFrame() != startFrame)
68         gotoNextFrame();
69 }
70
71 void StackVisitor::gotoNextFrame()
72 {
73     m_frame.m_index++;
74 #if ENABLE(DFG_JIT)
75     if (m_frame.isInlinedFrame()) {
76         InlineCallFrame* inlineCallFrame = m_frame.inlineCallFrame();
77         CodeOrigin* callerCodeOrigin = inlineCallFrame->getCallerSkippingTailCalls();
78         if (!callerCodeOrigin) {
79             while (inlineCallFrame) {
80                 readInlinedFrame(m_frame.callFrame(), &inlineCallFrame->directCaller);
81                 inlineCallFrame = m_frame.inlineCallFrame();
82             }
83             m_frame.m_entryFrame = m_frame.m_callerEntryFrame;
84             readFrame(m_frame.callerFrame());
85         } else
86             readInlinedFrame(m_frame.callFrame(), callerCodeOrigin);
87         return;
88     }
89 #endif // ENABLE(DFG_JIT)
90     m_frame.m_entryFrame = m_frame.m_callerEntryFrame;
91     readFrame(m_frame.callerFrame());
92 }
93
94 void StackVisitor::unwindToMachineCodeBlockFrame()
95 {
96 #if ENABLE(DFG_JIT)
97     if (m_frame.isInlinedFrame()) {
98         CodeOrigin codeOrigin = m_frame.inlineCallFrame()->directCaller;
99         while (codeOrigin.inlineCallFrame())
100             codeOrigin = codeOrigin.inlineCallFrame()->directCaller;
101         readNonInlinedFrame(m_frame.callFrame(), &codeOrigin);
102     }
103 #endif
104 }
105
106 void StackVisitor::readFrame(CallFrame* callFrame)
107 {
108     if (!callFrame) {
109         m_frame.setToEnd();
110         return;
111     }
112
113     if (callFrame->isAnyWasmCallee()) {
114         readNonInlinedFrame(callFrame);
115         return;
116     }
117
118 #if !ENABLE(DFG_JIT)
119     readNonInlinedFrame(callFrame);
120
121 #else // !ENABLE(DFG_JIT)
122     // If the frame doesn't have a code block, then it's not a DFG frame.
123     // Hence, we're not at an inlined frame.
124     CodeBlock* codeBlock = callFrame->codeBlock();
125     if (!codeBlock) {
126         readNonInlinedFrame(callFrame);
127         return;
128     }
129
130     // If the code block does not have any code origins, then there's no
131     // inlining. Hence, we're not at an inlined frame.
132     if (!codeBlock->hasCodeOrigins()) {
133         readNonInlinedFrame(callFrame);
134         return;
135     }
136
137     CallSiteIndex index = callFrame->callSiteIndex();
138     ASSERT(codeBlock->canGetCodeOrigin(index));
139     if (!codeBlock->canGetCodeOrigin(index)) {
140         // See assertion above. In release builds, we try to protect ourselves
141         // from crashing even though stack walking will be goofed up.
142         m_frame.setToEnd();
143         return;
144     }
145
146     CodeOrigin codeOrigin = codeBlock->codeOrigin(index);
147     if (!codeOrigin.inlineCallFrame()) {
148         readNonInlinedFrame(callFrame, &codeOrigin);
149         return;
150     }
151
152     readInlinedFrame(callFrame, &codeOrigin);
153 #endif // !ENABLE(DFG_JIT)
154 }
155
156 void StackVisitor::readNonInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin)
157 {
158     m_frame.m_callFrame = callFrame;
159     m_frame.m_argumentCountIncludingThis = callFrame->argumentCountIncludingThis();
160     m_frame.m_callerEntryFrame = m_frame.m_entryFrame;
161     m_frame.m_callerFrame = callFrame->callerFrame(m_frame.m_callerEntryFrame);
162     m_frame.m_callerIsEntryFrame = m_frame.m_callerEntryFrame != m_frame.m_entryFrame;
163     m_frame.m_isWasmFrame = false;
164
165     CalleeBits callee = callFrame->callee();
166     m_frame.m_callee = callee;
167
168     if (callFrame->isAnyWasmCallee()) {
169         m_frame.m_isWasmFrame = true;
170         m_frame.m_codeBlock = nullptr;
171         m_frame.m_bytecodeOffset = 0;
172 #if ENABLE(WEBASSEMBLY)
173         CalleeBits bits = callFrame->callee();
174         if (bits.isWasm())
175             m_frame.m_wasmFunctionIndexOrName = bits.asWasmCallee()->indexOrName();
176 #endif
177     } else {
178         m_frame.m_codeBlock = callFrame->codeBlock();
179         m_frame.m_bytecodeOffset = !m_frame.codeBlock() ? 0
180             : codeOrigin ? codeOrigin->bytecodeIndex()
181             : callFrame->bytecodeOffset();
182
183     }
184
185 #if ENABLE(DFG_JIT)
186     m_frame.m_inlineCallFrame = 0;
187 #endif
188 }
189
190 #if ENABLE(DFG_JIT)
191 static int inlinedFrameOffset(CodeOrigin* codeOrigin)
192 {
193     InlineCallFrame* inlineCallFrame = codeOrigin->inlineCallFrame();
194     int frameOffset = inlineCallFrame ? inlineCallFrame->stackOffset : 0;
195     return frameOffset;
196 }
197
198 void StackVisitor::readInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin)
199 {
200     ASSERT(codeOrigin);
201     m_frame.m_isWasmFrame = false;
202
203     int frameOffset = inlinedFrameOffset(codeOrigin);
204     bool isInlined = !!frameOffset;
205     if (isInlined) {
206         InlineCallFrame* inlineCallFrame = codeOrigin->inlineCallFrame();
207
208         m_frame.m_callFrame = callFrame;
209         m_frame.m_inlineCallFrame = inlineCallFrame;
210         if (inlineCallFrame->argumentCountRegister.isValid())
211             m_frame.m_argumentCountIncludingThis = callFrame->r(inlineCallFrame->argumentCountRegister.offset()).unboxedInt32();
212         else
213             m_frame.m_argumentCountIncludingThis = inlineCallFrame->argumentCountIncludingThis;
214         m_frame.m_codeBlock = inlineCallFrame->baselineCodeBlock.get();
215         m_frame.m_bytecodeOffset = codeOrigin->bytecodeIndex();
216
217         JSFunction* callee = inlineCallFrame->calleeForCallFrame(callFrame);
218         m_frame.m_callee = callee;
219         ASSERT(!!m_frame.callee().rawPtr());
220
221         // The callerFrame just needs to be non-null to indicate that we
222         // haven't reached the last frame yet. Setting it to the root
223         // frame (i.e. the callFrame that this inlined frame is called from)
224         // would work just fine.
225         m_frame.m_callerFrame = callFrame;
226         return;
227     }
228
229     readNonInlinedFrame(callFrame, codeOrigin);
230 }
231 #endif // ENABLE(DFG_JIT)
232
233 StackVisitor::Frame::CodeType StackVisitor::Frame::codeType() const
234 {
235     if (isWasmFrame())
236         return CodeType::Wasm;
237
238     if (!codeBlock())
239         return CodeType::Native;
240
241     switch (codeBlock()->codeType()) {
242     case EvalCode:
243         return CodeType::Eval;
244     case ModuleCode:
245         return CodeType::Module;
246     case FunctionCode:
247         return CodeType::Function;
248     case GlobalCode:
249         return CodeType::Global;
250     }
251     RELEASE_ASSERT_NOT_REACHED();
252     return CodeType::Global;
253 }
254
255 const RegisterAtOffsetList* StackVisitor::Frame::calleeSaveRegisters()
256 {
257     if (isInlinedFrame())
258         return nullptr;
259
260 #if !ENABLE(C_LOOP) && NUMBER_OF_CALLEE_SAVES_REGISTERS > 0
261
262 #if ENABLE(WEBASSEMBLY)
263     if (isWasmFrame()) {
264         if (callee().isCell()) {
265             RELEASE_ASSERT(isWebAssemblyToJSCallee(callee().asCell()));
266             return nullptr;
267         }
268         Wasm::Callee* wasmCallee = callee().asWasmCallee();
269         return wasmCallee->calleeSaveRegisters();
270     }
271 #endif // ENABLE(WEBASSEMBLY)
272
273     if (CodeBlock* codeBlock = this->codeBlock())
274         return codeBlock->calleeSaveRegisters();
275
276 #endif // !ENABLE(C_LOOP) && NUMBER_OF_CALLEE_SAVES_REGISTERS > 0
277
278     return nullptr;
279 }
280
281 String StackVisitor::Frame::functionName() const
282 {
283     String traceLine;
284
285     switch (codeType()) {
286     case CodeType::Wasm:
287         traceLine = makeString(m_wasmFunctionIndexOrName);
288         break;
289     case CodeType::Eval:
290         traceLine = "eval code"_s;
291         break;
292     case CodeType::Module:
293         traceLine = "module code"_s;
294         break;
295     case CodeType::Native: {
296         JSCell* callee = this->callee().asCell();
297         if (callee)
298             traceLine = getCalculatedDisplayName(callFrame()->vm(), jsCast<JSObject*>(callee)).impl();
299         break;
300     }
301     case CodeType::Function: 
302         traceLine = getCalculatedDisplayName(callFrame()->vm(), jsCast<JSObject*>(this->callee().asCell())).impl();
303         break;
304     case CodeType::Global:
305         traceLine = "global code"_s;
306         break;
307     }
308     return traceLine.isNull() ? emptyString() : traceLine;
309 }
310
311 String StackVisitor::Frame::sourceURL() const
312 {
313     String traceLine;
314
315     switch (codeType()) {
316     case CodeType::Eval:
317     case CodeType::Module:
318     case CodeType::Function:
319     case CodeType::Global: {
320         String sourceURL = codeBlock()->ownerExecutable()->sourceURL();
321         if (!sourceURL.isEmpty())
322             traceLine = sourceURL.impl();
323         break;
324     }
325     case CodeType::Native:
326         traceLine = "[native code]"_s;
327         break;
328     case CodeType::Wasm:
329         traceLine = "[wasm code]"_s;
330         break;
331     }
332     return traceLine.isNull() ? emptyString() : traceLine;
333 }
334
335 String StackVisitor::Frame::toString() const
336 {
337     StringBuilder traceBuild;
338     String functionName = this->functionName();
339     String sourceURL = this->sourceURL();
340     traceBuild.append(functionName);
341     if (!sourceURL.isEmpty()) {
342         if (!functionName.isEmpty())
343             traceBuild.append('@');
344         traceBuild.append(sourceURL);
345         if (hasLineAndColumnInfo()) {
346             unsigned line = 0;
347             unsigned column = 0;
348             computeLineAndColumn(line, column);
349             traceBuild.append(':');
350             traceBuild.appendNumber(line);
351             traceBuild.append(':');
352             traceBuild.appendNumber(column);
353         }
354     }
355     return traceBuild.toString().impl();
356 }
357
358 intptr_t StackVisitor::Frame::sourceID()
359 {
360     if (CodeBlock* codeBlock = this->codeBlock())
361         return codeBlock->ownerExecutable()->sourceID();
362     return noSourceID;
363 }
364
365 ClonedArguments* StackVisitor::Frame::createArguments()
366 {
367     ASSERT(m_callFrame);
368     CallFrame* physicalFrame = m_callFrame;
369     ClonedArguments* arguments;
370     ArgumentsMode mode;
371     if (Options::useFunctionDotArguments())
372         mode = ArgumentsMode::Cloned;
373     else
374         mode = ArgumentsMode::FakeValues;
375 #if ENABLE(DFG_JIT)
376     if (isInlinedFrame()) {
377         ASSERT(m_inlineCallFrame);
378         arguments = ClonedArguments::createWithInlineFrame(physicalFrame, physicalFrame, m_inlineCallFrame, mode);
379     } else 
380 #endif
381         arguments = ClonedArguments::createWithMachineFrame(physicalFrame, physicalFrame, mode);
382     return arguments;
383 }
384
385 bool StackVisitor::Frame::hasLineAndColumnInfo() const
386 {
387     return !!codeBlock();
388 }
389
390 void StackVisitor::Frame::computeLineAndColumn(unsigned& line, unsigned& column) const
391 {
392     CodeBlock* codeBlock = this->codeBlock();
393     if (!codeBlock) {
394         line = 0;
395         column = 0;
396         return;
397     }
398
399     int divot = 0;
400     int unusedStartOffset = 0;
401     int unusedEndOffset = 0;
402     unsigned divotLine = 0;
403     unsigned divotColumn = 0;
404     retrieveExpressionInfo(divot, unusedStartOffset, unusedEndOffset, divotLine, divotColumn);
405
406     line = divotLine + codeBlock->ownerExecutable()->firstLine();
407     column = divotColumn + (divotLine ? 1 : codeBlock->firstLineColumnOffset());
408
409     if (Optional<int> overrideLineNumber = codeBlock->ownerExecutable()->overrideLineNumber(*codeBlock->vm()))
410         line = overrideLineNumber.value();
411 }
412
413 void StackVisitor::Frame::retrieveExpressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column) const
414 {
415     CodeBlock* codeBlock = this->codeBlock();
416     codeBlock->unlinkedCodeBlock()->expressionRangeForBytecodeOffset(bytecodeOffset(), divot, startOffset, endOffset, line, column);
417     divot += codeBlock->sourceOffset();
418 }
419
420 void StackVisitor::Frame::setToEnd()
421 {
422     m_callFrame = 0;
423 #if ENABLE(DFG_JIT)
424     m_inlineCallFrame = 0;
425 #endif
426     m_isWasmFrame = false;
427 }
428
429 void StackVisitor::Frame::dump(PrintStream& out, Indenter indent) const
430 {
431     dump(out, indent, [] (PrintStream&) { });
432 }
433
434 void StackVisitor::Frame::dump(PrintStream& out, Indenter indent, WTF::Function<void(PrintStream&)> prefix) const
435 {
436     if (!this->callFrame()) {
437         out.print(indent, "frame 0x0\n");
438         return;
439     }
440
441     CodeBlock* codeBlock = this->codeBlock();
442     out.print(indent);
443     prefix(out);
444     out.print("frame ", RawPointer(this->callFrame()), " {\n");
445
446     {
447         indent++;
448
449         CallFrame* callFrame = m_callFrame;
450         CallFrame* callerFrame = this->callerFrame();
451         const void* returnPC = callFrame->hasReturnPC() ? callFrame->returnPC().value() : nullptr;
452
453         out.print(indent, "name: ", functionName(), "\n");
454         out.print(indent, "sourceURL: ", sourceURL(), "\n");
455
456         bool isInlined = false;
457 #if ENABLE(DFG_JIT)
458         isInlined = isInlinedFrame();
459         out.print(indent, "isInlinedFrame: ", isInlinedFrame(), "\n");
460         if (isInlinedFrame())
461             out.print(indent, "InlineCallFrame: ", RawPointer(m_inlineCallFrame), "\n");
462 #endif
463
464         out.print(indent, "callee: ", RawPointer(callee().rawPtr()), "\n");
465         out.print(indent, "returnPC: ", RawPointer(returnPC), "\n");
466         out.print(indent, "callerFrame: ", RawPointer(callerFrame), "\n");
467         uintptr_t locationRawBits = callFrame->callSiteAsRawBits();
468         out.print(indent, "rawLocationBits: ", locationRawBits,
469             " ", RawPointer(reinterpret_cast<void*>(locationRawBits)), "\n");
470         out.print(indent, "codeBlock: ", RawPointer(codeBlock));
471         if (codeBlock)
472             out.print(" ", *codeBlock);
473         out.print("\n");
474         if (codeBlock && !isInlined) {
475             indent++;
476
477             if (callFrame->callSiteBitsAreBytecodeOffset()) {
478                 unsigned bytecodeOffset = callFrame->bytecodeOffset();
479                 out.print(indent, "bytecodeOffset: ", bytecodeOffset, " of ", codeBlock->instructions().size(), "\n");
480 #if ENABLE(DFG_JIT)
481             } else {
482                 out.print(indent, "hasCodeOrigins: ", codeBlock->hasCodeOrigins(), "\n");
483                 if (codeBlock->hasCodeOrigins()) {
484                     CallSiteIndex callSiteIndex = callFrame->callSiteIndex();
485                     out.print(indent, "callSiteIndex: ", callSiteIndex.bits(), " of ", codeBlock->codeOrigins().size(), "\n");
486
487                     JITCode::JITType jitType = codeBlock->jitType();
488                     if (jitType != JITCode::FTLJIT) {
489                         JITCode* jitCode = codeBlock->jitCode().get();
490                         out.print(indent, "jitCode: ", RawPointer(jitCode),
491                             " start ", RawPointer(jitCode->start()),
492                             " end ", RawPointer(jitCode->end()), "\n");
493                     }
494                 }
495 #endif
496             }
497             unsigned line = 0;
498             unsigned column = 0;
499             computeLineAndColumn(line, column);
500             out.print(indent, "line: ", line, "\n");
501             out.print(indent, "column: ", column, "\n");
502
503             indent--;
504         }
505         out.print(indent, "EntryFrame: ", RawPointer(m_entryFrame), "\n");
506         indent--;
507     }
508     out.print(indent, "}\n");
509 }
510
511 } // namespace JSC