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