1/*
2 * Copyright (C) 2008, 2013, 2014 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 "JSLexicalEnvironment.h"
33#include "JSCInlines.h"
34#include "VMEntryScope.h"
35#include <wtf/StringPrintStream.h>
36
37namespace JSC {
38
39bool CallFrame::callSiteBitsAreBytecodeOffset() const
40{
41 ASSERT(codeBlock());
42 switch (codeBlock()->jitType()) {
43 case JITCode::InterpreterThunk:
44 case JITCode::BaselineJIT:
45 return true;
46 case JITCode::None:
47 case JITCode::HostCallThunk:
48 RELEASE_ASSERT_NOT_REACHED();
49 return false;
50 default:
51 return false;
52 }
53
54 RELEASE_ASSERT_NOT_REACHED();
55 return false;
56}
57
58bool CallFrame::callSiteBitsAreCodeOriginIndex() const
59{
60 ASSERT(codeBlock());
61 switch (codeBlock()->jitType()) {
62 case JITCode::DFGJIT:
63 case JITCode::FTLJIT:
64 return true;
65 case JITCode::None:
66 case JITCode::HostCallThunk:
67 RELEASE_ASSERT_NOT_REACHED();
68 return false;
69 default:
70 return false;
71 }
72
73 RELEASE_ASSERT_NOT_REACHED();
74 return false;
75}
76
77unsigned CallFrame::callSiteAsRawBits() const
78{
79 return this[JSStack::ArgumentCount].tag();
80}
81
82SUPPRESS_ASAN unsigned CallFrame::unsafeCallSiteAsRawBits() const
83{
84 return this[JSStack::ArgumentCount].unsafeTag();
85}
86
87CallSiteIndex CallFrame::callSiteIndex() const
88{
89 return CallSiteIndex(callSiteAsRawBits());
90}
91
92SUPPRESS_ASAN CallSiteIndex CallFrame::unsafeCallSiteIndex() const
93{
94 return CallSiteIndex(unsafeCallSiteAsRawBits());
95}
96
97#ifndef NDEBUG
98JSStack* CallFrame::stack()
99{
100 return &interpreter()->stack();
101}
102
103#endif
104
105#if USE(JSVALUE32_64)
106Instruction* CallFrame::currentVPC() const
107{
108 return bitwise_cast<Instruction*>(callSiteIndex().bits());
109}
110
111void CallFrame::setCurrentVPC(Instruction* vpc)
112{
113 CallSiteIndex callSite(vpc);
114 this[JSStack::ArgumentCount].tag() = callSite.bits();
115}
116
117unsigned CallFrame::callSiteBitsAsBytecodeOffset() const
118{
119 ASSERT(codeBlock());
120 ASSERT(callSiteBitsAreBytecodeOffset());
121 return currentVPC() - codeBlock()->instructions().begin();
122}
123
124#else // USE(JSVALUE32_64)
125Instruction* CallFrame::currentVPC() const
126{
127 ASSERT(callSiteBitsAreBytecodeOffset());
128 return codeBlock()->instructions().begin() + callSiteBitsAsBytecodeOffset();
129}
130
131void CallFrame::setCurrentVPC(Instruction* vpc)
132{
133 CallSiteIndex callSite(vpc - codeBlock()->instructions().begin());
134 this[JSStack::ArgumentCount].tag() = static_cast<int32_t>(callSite.bits());
135}
136
137unsigned CallFrame::callSiteBitsAsBytecodeOffset() const
138{
139 ASSERT(codeBlock());
140 ASSERT(callSiteBitsAreBytecodeOffset());
141 return callSiteIndex().bits();
142}
143
144#endif
145
146unsigned CallFrame::bytecodeOffset()
147{
148 if (!codeBlock())
149 return 0;
150#if ENABLE(DFG_JIT)
151 if (callSiteBitsAreCodeOriginIndex()) {
152 ASSERT(codeBlock());
153 CodeOrigin codeOrigin = this->codeOrigin();
154 for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) {
155 codeOrigin = inlineCallFrame->directCaller;
156 inlineCallFrame = codeOrigin.inlineCallFrame;
157 }
158 return codeOrigin.bytecodeIndex;
159 }
160#endif
161 ASSERT(callSiteBitsAreBytecodeOffset());
162 return callSiteBitsAsBytecodeOffset();
163}
164
165CodeOrigin CallFrame::codeOrigin()
166{
167 if (!codeBlock())
168 return CodeOrigin(0);
169#if ENABLE(DFG_JIT)
170 if (callSiteBitsAreCodeOriginIndex()) {
171 CallSiteIndex index = callSiteIndex();
172 ASSERT(codeBlock()->canGetCodeOrigin(index));
173 return codeBlock()->codeOrigin(index);
174 }
175#endif
176 return CodeOrigin(callSiteBitsAsBytecodeOffset());
177}
178
179Register* CallFrame::topOfFrameInternal()
180{
181 CodeBlock* codeBlock = this->codeBlock();
182 ASSERT(codeBlock);
183 return registers() + codeBlock->stackPointerOffset();
184}
185
186JSGlobalObject* CallFrame::vmEntryGlobalObject()
187{
188 if (this == lexicalGlobalObject()->globalExec())
189 return lexicalGlobalObject();
190
191 // For any ExecState that's not a globalExec, the
192 // dynamic global object must be set since code is running
193 ASSERT(vm().entryScope);
194 return vm().entryScope->globalObject();
195}
196
197CallFrame* CallFrame::callerFrame(VMEntryFrame*& currVMEntryFrame)
198{
199 if (callerFrameOrVMEntryFrame() == currVMEntryFrame) {
200 VMEntryRecord* currVMEntryRecord = vmEntryRecord(currVMEntryFrame);
201 currVMEntryFrame = currVMEntryRecord->prevTopVMEntryFrame();
202 return currVMEntryRecord->prevTopCallFrame();
203 }
204 return static_cast<CallFrame*>(callerFrameOrVMEntryFrame());
205}
206
207SUPPRESS_ASAN CallFrame* CallFrame::unsafeCallerFrame(VMEntryFrame*& currVMEntryFrame)
208{
209 if (unsafeCallerFrameOrVMEntryFrame() == currVMEntryFrame) {
210 VMEntryRecord* currVMEntryRecord = vmEntryRecord(currVMEntryFrame);
211 currVMEntryFrame = currVMEntryRecord->unsafePrevTopVMEntryFrame();
212 return currVMEntryRecord->unsafePrevTopCallFrame();
213 }
214 return static_cast<CallFrame*>(unsafeCallerFrameOrVMEntryFrame());
215}
216
217String CallFrame::friendlyFunctionName()
218{
219 CodeBlock* codeBlock = this->codeBlock();
220 if (!codeBlock)
221 return emptyString();
222
223 switch (codeBlock->codeType()) {
224 case EvalCode:
225 return ASCIILiteral("eval code");
226 case ModuleCode:
227 return ASCIILiteral("module code");
228 case GlobalCode:
229 return ASCIILiteral("global code");
230 case FunctionCode:
231 if (callee())
232 return getCalculatedDisplayName(this, callee());
233 return emptyString();
234 }
235
236 ASSERT_NOT_REACHED();
237 return emptyString();
238}
239
240void CallFrame::dump(PrintStream& out)
241{
242 if (CodeBlock* codeBlock = this->codeBlock()) {
243 out.print(codeBlock->inferredName(), "#", codeBlock->hashAsStringIfPossible(), " [", codeBlock->jitType(), "]");
244
245 out.print("(");
246 thisValue().dumpForBacktrace(out);
247
248 for (size_t i = 0; i < argumentCount(); ++i) {
249 out.print(", ");
250 JSValue value = argument(i);
251 value.dumpForBacktrace(out);
252 }
253
254 out.print(")");
255
256 return;
257 }
258
259 out.print(returnPC());
260}
261
262const char* CallFrame::describeFrame()
263{
264 const size_t bufferSize = 200;
265 static char buffer[bufferSize + 1];
266
267 WTF::StringPrintStream stringStream;
268
269 dump(stringStream);
270
271 strncpy(buffer, stringStream.toCString().data(), bufferSize);
272 buffer[bufferSize] = '\0';
273
274 return buffer;
275}
276
277} // namespace JSC
278