Make JITType an enum class
[WebKit-https.git] / Source / JavaScriptCore / interpreter / CallFrame.cpp
1 /*
2  * Copyright (C) 2008-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 "CallFrame.h"
28
29 #include "CodeBlock.h"
30 #include "InlineCallFrame.h"
31 #include "Interpreter.h"
32 #include "JSCInlines.h"
33 #include "JSWebAssemblyInstance.h"
34 #include "VMEntryScope.h"
35 #include "WasmContextInlines.h"
36 #include "WasmInstance.h"
37 #include <wtf/StringPrintStream.h>
38
39 namespace JSC {
40
41 void ExecState::initGlobalExec(ExecState* globalExec, JSCallee* globalCallee)
42 {
43     globalExec->setCodeBlock(nullptr);
44     globalExec->setCallerFrame(noCaller());
45     globalExec->setReturnPC(0);
46     globalExec->setArgumentCountIncludingThis(0);
47     globalExec->setCallee(globalCallee);
48     ASSERT(globalExec->isGlobalExec());
49 }
50
51 bool CallFrame::callSiteBitsAreBytecodeOffset() const
52 {
53     ASSERT(codeBlock());
54     switch (codeBlock()->jitType()) {
55     case JITType::InterpreterThunk:
56     case JITType::BaselineJIT:
57         return true;
58     case JITType::None:
59     case JITType::HostCallThunk:
60         RELEASE_ASSERT_NOT_REACHED();
61         return false;
62     default:
63         return false;
64     }
65
66     RELEASE_ASSERT_NOT_REACHED();
67     return false;
68 }
69
70 bool CallFrame::callSiteBitsAreCodeOriginIndex() const
71 {
72     ASSERT(codeBlock());
73     switch (codeBlock()->jitType()) {
74     case JITType::DFGJIT:
75     case JITType::FTLJIT:
76         return true;
77     case JITType::None:
78     case JITType::HostCallThunk:
79         RELEASE_ASSERT_NOT_REACHED();
80         return false;
81     default:
82         return false;
83     }
84
85     RELEASE_ASSERT_NOT_REACHED();
86     return false;
87 }
88
89 unsigned CallFrame::callSiteAsRawBits() const
90 {
91     return this[CallFrameSlot::argumentCount].tag();
92 }
93
94 SUPPRESS_ASAN unsigned CallFrame::unsafeCallSiteAsRawBits() const
95 {
96     return this[CallFrameSlot::argumentCount].unsafeTag();
97 }
98
99 CallSiteIndex CallFrame::callSiteIndex() const
100 {
101     return CallSiteIndex(callSiteAsRawBits());
102 }
103
104 SUPPRESS_ASAN CallSiteIndex CallFrame::unsafeCallSiteIndex() const
105 {
106     return CallSiteIndex(unsafeCallSiteAsRawBits());
107 }
108
109 #if USE(JSVALUE32_64)
110 const Instruction* CallFrame::currentVPC() const
111 {
112     return bitwise_cast<Instruction*>(callSiteIndex().bits());
113 }
114
115 void CallFrame::setCurrentVPC(const Instruction* vpc)
116 {
117     CallSiteIndex callSite(vpc);
118     this[CallFrameSlot::argumentCount].tag() = callSite.bits();
119 }
120
121 unsigned CallFrame::callSiteBitsAsBytecodeOffset() const
122 {
123     ASSERT(codeBlock());
124     ASSERT(callSiteBitsAreBytecodeOffset());
125     return codeBlock()->bytecodeOffset(currentVPC());     
126 }
127
128 #else // USE(JSVALUE32_64)
129 const Instruction* CallFrame::currentVPC() const
130 {
131     ASSERT(callSiteBitsAreBytecodeOffset());
132     return codeBlock()->instructions().at(callSiteBitsAsBytecodeOffset()).ptr();
133 }
134
135 void CallFrame::setCurrentVPC(const Instruction* vpc)
136 {
137     CallSiteIndex callSite(codeBlock()->bytecodeOffset(vpc));
138     this[CallFrameSlot::argumentCount].tag() = static_cast<int32_t>(callSite.bits());
139 }
140
141 unsigned CallFrame::callSiteBitsAsBytecodeOffset() const
142 {
143     ASSERT(codeBlock());
144     ASSERT(callSiteBitsAreBytecodeOffset());
145     return callSiteIndex().bits();
146 }
147
148 #endif
149     
150 unsigned CallFrame::bytecodeOffset()
151 {
152     ASSERT(!callee().isWasm());
153     if (!codeBlock())
154         return 0;
155 #if ENABLE(DFG_JIT)
156     if (callSiteBitsAreCodeOriginIndex()) {
157         ASSERT(codeBlock());
158         CodeOrigin codeOrigin = this->codeOrigin();
159         for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame(); inlineCallFrame;) {
160             codeOrigin = inlineCallFrame->directCaller;
161             inlineCallFrame = codeOrigin.inlineCallFrame();
162         }
163         return codeOrigin.bytecodeIndex();
164     }
165 #endif
166     ASSERT(callSiteBitsAreBytecodeOffset());
167     return callSiteBitsAsBytecodeOffset();
168 }
169
170 CodeOrigin CallFrame::codeOrigin()
171 {
172     if (!codeBlock())
173         return CodeOrigin(0);
174 #if ENABLE(DFG_JIT)
175     if (callSiteBitsAreCodeOriginIndex()) {
176         CallSiteIndex index = callSiteIndex();
177         ASSERT(codeBlock()->canGetCodeOrigin(index));
178         return codeBlock()->codeOrigin(index);
179     }
180 #endif
181     return CodeOrigin(callSiteBitsAsBytecodeOffset());
182 }
183
184 Register* CallFrame::topOfFrameInternal()
185 {
186     CodeBlock* codeBlock = this->codeBlock();
187     ASSERT(codeBlock);
188     return registers() + codeBlock->stackPointerOffset();
189 }
190
191 JSGlobalObject* CallFrame::wasmAwareLexicalGlobalObject(VM& vm)
192 {
193 #if ENABLE(WEBASSEMBLY)
194     if (!callee().isWasm())
195         return lexicalGlobalObject();
196     return vm.wasmContext.load()->owner<JSWebAssemblyInstance>()->globalObject(vm);
197 #else
198     UNUSED_PARAM(vm);
199     return lexicalGlobalObject();
200 #endif
201 }
202
203 bool CallFrame::isAnyWasmCallee()
204 {
205     CalleeBits callee = this->callee();
206     if (callee.isWasm())
207         return true;
208
209     ASSERT(callee.isCell());
210     if (!!callee.rawPtr() && isWebAssemblyToJSCallee(callee.asCell()))
211         return true;
212
213     return false;
214 }
215
216 CallFrame* CallFrame::callerFrame(EntryFrame*& currEntryFrame) const
217 {
218     if (callerFrameOrEntryFrame() == currEntryFrame) {
219         VMEntryRecord* currVMEntryRecord = vmEntryRecord(currEntryFrame);
220         currEntryFrame = currVMEntryRecord->prevTopEntryFrame();
221         return currVMEntryRecord->prevTopCallFrame();
222     }
223     return static_cast<CallFrame*>(callerFrameOrEntryFrame());
224 }
225
226 SUPPRESS_ASAN CallFrame* CallFrame::unsafeCallerFrame(EntryFrame*& currEntryFrame) const
227 {
228     if (unsafeCallerFrameOrEntryFrame() == currEntryFrame) {
229         VMEntryRecord* currVMEntryRecord = vmEntryRecord(currEntryFrame);
230         currEntryFrame = currVMEntryRecord->unsafePrevTopEntryFrame();
231         return currVMEntryRecord->unsafePrevTopCallFrame();
232     }
233     return static_cast<CallFrame*>(unsafeCallerFrameOrEntryFrame());
234 }
235
236 SourceOrigin CallFrame::callerSourceOrigin()
237 {
238     RELEASE_ASSERT(callee().isCell());
239     VM* vm = &this->vm();
240     SourceOrigin sourceOrigin;
241     bool haveSkippedFirstFrame = false;
242     StackVisitor::visit(this, vm, [&](StackVisitor& visitor) {
243         if (!std::exchange(haveSkippedFirstFrame, true))
244             return StackVisitor::Status::Continue;
245
246         switch (visitor->codeType()) {
247         case StackVisitor::Frame::CodeType::Function:
248             // Skip the builtin functions since they should not pass the source origin to the dynamic code generation calls.
249             // Consider the following code.
250             //
251             // [ "42 + 44" ].forEach(eval);
252             //
253             // In the above case, the eval function will be interpreted as the indirect call to eval inside forEach function.
254             // At that time, the generated eval code should have the source origin to the original caller of the forEach function
255             // instead of the source origin of the forEach function.
256             if (static_cast<FunctionExecutable*>(visitor->codeBlock()->ownerExecutable())->isBuiltinFunction())
257                 return StackVisitor::Status::Continue;
258             FALLTHROUGH;
259
260         case StackVisitor::Frame::CodeType::Eval:
261         case StackVisitor::Frame::CodeType::Module:
262         case StackVisitor::Frame::CodeType::Global:
263             sourceOrigin = visitor->codeBlock()->ownerExecutable()->sourceOrigin();
264             return StackVisitor::Status::Done;
265
266         case StackVisitor::Frame::CodeType::Native:
267             return StackVisitor::Status::Continue;
268
269         case StackVisitor::Frame::CodeType::Wasm:
270             // FIXME: Should return the source origin for WASM.
271             return StackVisitor::Status::Done;
272         }
273
274         RELEASE_ASSERT_NOT_REACHED();
275         return StackVisitor::Status::Done;
276     });
277     return sourceOrigin;
278 }
279
280 String CallFrame::friendlyFunctionName()
281 {
282     CodeBlock* codeBlock = this->codeBlock();
283     if (!codeBlock)
284         return emptyString();
285
286     switch (codeBlock->codeType()) {
287     case EvalCode:
288         return "eval code"_s;
289     case ModuleCode:
290         return "module code"_s;
291     case GlobalCode:
292         return "global code"_s;
293     case FunctionCode:
294         if (jsCallee())
295             return getCalculatedDisplayName(vm(), jsCallee());
296         return emptyString();
297     }
298
299     ASSERT_NOT_REACHED();
300     return emptyString();
301 }
302
303 void CallFrame::dump(PrintStream& out)
304 {
305     if (CodeBlock* codeBlock = this->codeBlock()) {
306         out.print(codeBlock->inferredName(), "#", codeBlock->hashAsStringIfPossible(), " [", codeBlock->jitType(), " bc#", bytecodeOffset(), "]");
307
308         out.print("(");
309         thisValue().dumpForBacktrace(out);
310
311         for (size_t i = 0; i < argumentCount(); ++i) {
312             out.print(", ");
313             JSValue value = argument(i);
314             value.dumpForBacktrace(out);
315         }
316
317         out.print(")");
318
319         return;
320     }
321
322     out.print(returnPC());
323 }
324
325 const char* CallFrame::describeFrame()
326 {
327     const size_t bufferSize = 200;
328     static char buffer[bufferSize + 1];
329     
330     WTF::StringPrintStream stringStream;
331
332     dump(stringStream);
333
334     strncpy(buffer, stringStream.toCString().data(), bufferSize);
335     buffer[bufferSize] = '\0';
336     
337     return buffer;
338 }
339
340 void CallFrame::convertToStackOverflowFrame(VM& vm, CodeBlock* codeBlockToKeepAliveUntilFrameIsUnwound)
341 {
342     ASSERT(!isGlobalExec());
343     ASSERT(codeBlockToKeepAliveUntilFrameIsUnwound->inherits<CodeBlock>(vm));
344
345     EntryFrame* entryFrame = vm.topEntryFrame;
346     CallFrame* throwOriginFrame = this;
347     do {
348         throwOriginFrame = throwOriginFrame->callerFrame(entryFrame);
349     } while (throwOriginFrame && throwOriginFrame->callee().isWasm());
350
351     JSObject* originCallee = throwOriginFrame ? throwOriginFrame->jsCallee() : vmEntryRecord(vm.topEntryFrame)->callee();
352     JSObject* stackOverflowCallee = originCallee->globalObject()->stackOverflowFrameCallee();
353
354     setCodeBlock(codeBlockToKeepAliveUntilFrameIsUnwound);
355     setCallee(stackOverflowCallee);
356     setArgumentCountIncludingThis(0);
357 }
358
359 } // namespace JSC