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