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