]>
Commit | Line | Data |
---|---|---|
9dae56ea A |
1 | /* |
2 | * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) | |
3 | * Copyright (C) 2001 Peter Kelly (pmk@post.com) | |
81345200 | 4 | * Copyright (C) 2003, 2007, 2008, 2011, 2013, 2014 Apple Inc. All rights reserved. |
9dae56ea A |
5 | * |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Library General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2 of the License, or (at your option) any later version. | |
10 | * | |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Library General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Library General Public License | |
17 | * along with this library; see the file COPYING.LIB. If not, write to | |
18 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
19 | * Boston, MA 02110-1301, USA. | |
20 | * | |
21 | */ | |
22 | ||
23 | #ifndef CallFrame_h | |
24 | #define CallFrame_h | |
25 | ||
6fe7ccc8 | 26 | #include "AbstractPC.h" |
93a37866 | 27 | #include "JSStack.h" |
14957cd0 | 28 | #include "MacroAssemblerCodeRef.h" |
93a37866 | 29 | #include "Register.h" |
81345200 | 30 | #include "StackVisitor.h" |
ed1e77d3 A |
31 | #include "VM.h" |
32 | #include "VMEntryRecord.h" | |
9dae56ea A |
33 | |
34 | namespace JSC { | |
35 | ||
36 | class Arguments; | |
ed1e77d3 | 37 | class JSLexicalEnvironment; |
9dae56ea | 38 | class Interpreter; |
93a37866 | 39 | class JSScope; |
9dae56ea A |
40 | |
41 | // Represents the current state of script execution. | |
42 | // Passed as the first argument to most functions. | |
43 | class ExecState : private Register { | |
44 | public: | |
93a37866 | 45 | JSValue calleeAsValue() const { return this[JSStack::Callee].jsValue(); } |
ed1e77d3 | 46 | JSObject* callee() const { return this[JSStack::Callee].object(); } |
93a37866 | 47 | CodeBlock* codeBlock() const { return this[JSStack::CodeBlock].Register::codeBlock(); } |
ed1e77d3 | 48 | JSScope* scope(int scopeRegisterOffset) const |
f9bf01c6 | 49 | { |
ed1e77d3 A |
50 | ASSERT(this[scopeRegisterOffset].Register::scope()); |
51 | return this[scopeRegisterOffset].Register::scope(); | |
f9bf01c6 | 52 | } |
9dae56ea | 53 | |
ed1e77d3 A |
54 | bool hasActivation() const; |
55 | JSLexicalEnvironment* lexicalEnvironment() const; | |
56 | JSLexicalEnvironment* lexicalEnvironmentOrNullptr() const; | |
81345200 A |
57 | JSValue uncheckedActivation() const; |
58 | ||
9dae56ea | 59 | // Global object in which execution began. |
81345200 | 60 | JS_EXPORT_PRIVATE JSGlobalObject* vmEntryGlobalObject(); |
9dae56ea A |
61 | |
62 | // Global object in which the currently executing code was defined. | |
81345200 | 63 | // Differs from vmEntryGlobalObject() during function calls across web browser frames. |
93a37866 | 64 | JSGlobalObject* lexicalGlobalObject() const; |
9dae56ea A |
65 | |
66 | // Differs from lexicalGlobalObject because this will have DOM window shell rather than | |
67 | // the actual DOM window, which can't be "this" for security reasons. | |
93a37866 | 68 | JSObject* globalThisValue() const; |
9dae56ea | 69 | |
93a37866 | 70 | VM& vm() const; |
9dae56ea A |
71 | |
72 | // Convenience functions for access to global data. | |
73 | // It takes a few memory references to get from a call frame to the global data | |
74 | // pointer, so these are inefficient, and should be used sparingly in new code. | |
75 | // But they're used in many places in legacy code, so they're not going away any time soon. | |
76 | ||
81345200 | 77 | void clearException() { vm().clearException(); } |
9dae56ea | 78 | |
ed1e77d3 A |
79 | Exception* exception() const { return vm().exception(); } |
80 | bool hadException() const { return !!vm().exception(); } | |
81 | ||
82 | Exception* lastException() const { return vm().lastException(); } | |
83 | void clearLastException() { vm().clearLastException(); } | |
93a37866 | 84 | |
81345200 | 85 | AtomicStringTable* atomicStringTable() const { return vm().atomicStringTable(); } |
93a37866 A |
86 | const CommonIdentifiers& propertyNames() const { return *vm().propertyNames; } |
87 | const MarkedArgumentBuffer& emptyList() const { return *vm().emptyList; } | |
88 | Interpreter* interpreter() { return vm().interpreter; } | |
89 | Heap* heap() { return &vm().heap; } | |
81345200 | 90 | |
9dae56ea | 91 | |
9dae56ea A |
92 | static CallFrame* create(Register* callFrameBase) { return static_cast<CallFrame*>(callFrameBase); } |
93 | Register* registers() { return this; } | |
81345200 | 94 | const Register* registers() const { return this; } |
9dae56ea A |
95 | |
96 | CallFrame& operator=(const Register& r) { *static_cast<Register*>(this) = r; return *this; } | |
97 | ||
ed1e77d3 A |
98 | CallFrame* callerFrame() const { return static_cast<CallFrame*>(callerFrameOrVMEntryFrame()); } |
99 | ||
100 | JS_EXPORT_PRIVATE CallFrame* callerFrame(VMEntryFrame*&); | |
101 | ||
81345200 A |
102 | static ptrdiff_t callerFrameOffset() { return OBJECT_OFFSETOF(CallerFrameAndPC, callerFrame); } |
103 | ||
104 | ReturnAddressPtr returnPC() const { return ReturnAddressPtr(callerFrameAndPC().pc); } | |
105 | bool hasReturnPC() const { return !!callerFrameAndPC().pc; } | |
106 | void clearReturnPC() { callerFrameAndPC().pc = 0; } | |
107 | static ptrdiff_t returnPCOffset() { return OBJECT_OFFSETOF(CallerFrameAndPC, pc); } | |
93a37866 | 108 | AbstractPC abstractReturnPC(VM& vm) { return AbstractPC(vm, this); } |
81345200 A |
109 | |
110 | class Location { | |
111 | public: | |
112 | static inline uint32_t decode(uint32_t bits); | |
113 | ||
114 | static inline bool isBytecodeLocation(uint32_t bits); | |
115 | #if USE(JSVALUE64) | |
116 | static inline uint32_t encodeAsBytecodeOffset(uint32_t bits); | |
6fe7ccc8 | 117 | #else |
81345200 | 118 | static inline uint32_t encodeAsBytecodeInstruction(Instruction*); |
6fe7ccc8 A |
119 | #endif |
120 | ||
81345200 A |
121 | static inline bool isCodeOriginIndex(uint32_t bits); |
122 | static inline uint32_t encodeAsCodeOriginIndex(uint32_t bits); | |
123 | ||
124 | private: | |
125 | enum TypeTag { | |
126 | BytecodeLocationTag = 0, | |
127 | CodeOriginIndexTag = 1, | |
128 | }; | |
129 | ||
130 | static inline uint32_t encode(TypeTag, uint32_t bits); | |
131 | ||
132 | static const uint32_t s_mask = 0x1; | |
133 | #if USE(JSVALUE64) | |
134 | static const uint32_t s_shift = 31; | |
135 | static const uint32_t s_shiftedMask = s_mask << s_shift; | |
136 | #else | |
137 | static const uint32_t s_shift = 1; | |
138 | #endif | |
139 | }; | |
140 | ||
141 | bool hasLocationAsBytecodeOffset() const; | |
142 | bool hasLocationAsCodeOriginIndex() const; | |
143 | ||
144 | unsigned locationAsRawBits() const; | |
145 | unsigned locationAsBytecodeOffset() const; | |
146 | unsigned locationAsCodeOriginIndex() const; | |
147 | ||
148 | void setLocationAsRawBits(unsigned); | |
149 | void setLocationAsBytecodeOffset(unsigned); | |
150 | ||
151 | #if ENABLE(DFG_JIT) | |
152 | unsigned bytecodeOffsetFromCodeOriginIndex(); | |
153 | #endif | |
154 | ||
155 | // This will try to get you the bytecode offset, but you should be aware that | |
156 | // this bytecode offset may be bogus in the presence of inlining. This will | |
157 | // also return 0 if the call frame has no notion of bytecode offsets (for | |
158 | // example if it's native code). | |
159 | // https://bugs.webkit.org/show_bug.cgi?id=121754 | |
160 | unsigned bytecodeOffset(); | |
161 | ||
162 | // This will get you a CodeOrigin. It will always succeed. May return | |
163 | // CodeOrigin(0) if we're in native code. | |
164 | CodeOrigin codeOrigin(); | |
165 | ||
166 | Register* topOfFrame() | |
6fe7ccc8 | 167 | { |
ed1e77d3 | 168 | if (!codeBlock()) |
6fe7ccc8 | 169 | return registers(); |
81345200 | 170 | return topOfFrameInternal(); |
6fe7ccc8 A |
171 | } |
172 | ||
6fe7ccc8 A |
173 | #if USE(JSVALUE32_64) |
174 | Instruction* currentVPC() const | |
175 | { | |
93a37866 | 176 | return bitwise_cast<Instruction*>(this[JSStack::ArgumentCount].tag()); |
6fe7ccc8 A |
177 | } |
178 | void setCurrentVPC(Instruction* vpc) | |
179 | { | |
93a37866 | 180 | this[JSStack::ArgumentCount].tag() = bitwise_cast<int32_t>(vpc); |
6fe7ccc8 A |
181 | } |
182 | #else | |
183 | Instruction* currentVPC() const; | |
184 | void setCurrentVPC(Instruction* vpc); | |
185 | #endif | |
9dae56ea | 186 | |
81345200 | 187 | void setCallerFrame(CallFrame* frame) { callerFrameAndPC().callerFrame = frame; } |
ed1e77d3 A |
188 | void setScope(int scopeRegisterOffset, JSScope* scope) { static_cast<Register*>(this)[scopeRegisterOffset] = scope; } |
189 | void setActivation(JSLexicalEnvironment*); | |
190 | ||
191 | ALWAYS_INLINE void init(CodeBlock* codeBlock, Instruction* vPC, | |
192 | CallFrame* callerFrame, int argc, JSObject* callee) | |
193 | { | |
194 | ASSERT(callerFrame == noCaller() || callerFrame->stack()->containsAddress(this)); | |
195 | ||
196 | setCodeBlock(codeBlock); | |
197 | setCallerFrame(callerFrame); | |
198 | setReturnPC(vPC); // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*. | |
199 | setArgumentCountIncludingThis(argc); // original argument count (for the sake of the "arguments" object) | |
200 | setCallee(callee); | |
9dae56ea A |
201 | } |
202 | ||
ba379fdc | 203 | // Read a register from the codeframe (or constant from the CodeBlock). |
93a37866 | 204 | Register& r(int); |
ed1e77d3 | 205 | Register& r(VirtualRegister); |
81345200 | 206 | // Read a register for a non-constant |
93a37866 | 207 | Register& uncheckedR(int); |
ed1e77d3 | 208 | Register& uncheckedR(VirtualRegister); |
14957cd0 | 209 | |
93a37866 | 210 | // Access to arguments as passed. (After capture, arguments may move to a different location.) |
14957cd0 | 211 | size_t argumentCount() const { return argumentCountIncludingThis() - 1; } |
93a37866 | 212 | size_t argumentCountIncludingThis() const { return this[JSStack::ArgumentCount].payload(); } |
81345200 A |
213 | static int argumentOffset(int argument) { return (JSStack::FirstArgument + argument); } |
214 | static int argumentOffsetIncludingThis(int argument) { return (JSStack::ThisArgument + argument); } | |
93a37866 A |
215 | |
216 | // In the following (argument() and setArgument()), the 'argument' | |
217 | // parameter is the index of the arguments of the target function of | |
218 | // this frame. The index starts at 0 for the first arg, 1 for the | |
219 | // second, etc. | |
220 | // | |
221 | // The arguments (in this case) do not include the 'this' value. | |
222 | // arguments(0) will not fetch the 'this' value. To get/set 'this', | |
223 | // use thisValue() and setThisValue() below. | |
6fe7ccc8 A |
224 | |
225 | JSValue argument(size_t argument) | |
226 | { | |
227 | if (argument >= argumentCount()) | |
228 | return jsUndefined(); | |
81345200 A |
229 | return getArgumentUnsafe(argument); |
230 | } | |
231 | JSValue uncheckedArgument(size_t argument) | |
232 | { | |
233 | ASSERT(argument < argumentCount()); | |
234 | return getArgumentUnsafe(argument); | |
6fe7ccc8 A |
235 | } |
236 | void setArgument(size_t argument, JSValue value) | |
14957cd0 | 237 | { |
6fe7ccc8 | 238 | this[argumentOffset(argument)] = value; |
14957cd0 | 239 | } |
9dae56ea | 240 | |
ed1e77d3 A |
241 | JSValue getArgumentUnsafe(size_t argIndex) |
242 | { | |
243 | // User beware! This method does not verify that there is a valid | |
244 | // argument at the specified argIndex. This is used for debugging | |
245 | // and verification code only. The caller is expected to know what | |
246 | // he/she is doing when calling this method. | |
247 | return this[argumentOffset(argIndex)].jsValue(); | |
248 | } | |
249 | ||
6fe7ccc8 A |
250 | static int thisArgumentOffset() { return argumentOffsetIncludingThis(0); } |
251 | JSValue thisValue() { return this[thisArgumentOffset()].jsValue(); } | |
252 | void setThisValue(JSValue value) { this[thisArgumentOffset()] = value; } | |
253 | ||
93a37866 A |
254 | JSValue argumentAfterCapture(size_t argument); |
255 | ||
81345200 | 256 | static int offsetFor(size_t argumentCountIncludingThis) { return argumentCountIncludingThis + JSStack::ThisArgument - 1; } |
6fe7ccc8 | 257 | |
81345200 | 258 | static CallFrame* noCaller() { return 0; } |
6fe7ccc8 | 259 | |
93a37866 | 260 | void setArgumentCountIncludingThis(int count) { static_cast<Register*>(this)[JSStack::ArgumentCount].payload() = count; } |
ed1e77d3 | 261 | void setCallee(JSObject* callee) { static_cast<Register*>(this)[JSStack::Callee] = callee; } |
93a37866 | 262 | void setCodeBlock(CodeBlock* codeBlock) { static_cast<Register*>(this)[JSStack::CodeBlock] = codeBlock; } |
81345200 A |
263 | void setReturnPC(void* value) { callerFrameAndPC().pc = reinterpret_cast<Instruction*>(value); } |
264 | ||
265 | // CallFrame::iterate() expects a Functor that implements the following method: | |
266 | // StackVisitor::Status operator()(StackVisitor&); | |
267 | ||
268 | template <typename Functor> void iterate(Functor& functor) | |
269 | { | |
270 | StackVisitor::visit<Functor>(this, functor); | |
271 | } | |
272 | ||
273 | void dump(PrintStream&); | |
274 | JS_EXPORT_PRIVATE const char* describeFrame(); | |
ba379fdc | 275 | |
14957cd0 | 276 | private: |
6fe7ccc8 | 277 | |
14957cd0 | 278 | #ifndef NDEBUG |
93a37866 | 279 | JSStack* stack(); |
14957cd0 | 280 | #endif |
9dae56ea A |
281 | ExecState(); |
282 | ~ExecState(); | |
93a37866 | 283 | |
81345200 A |
284 | Register* topOfFrameInternal(); |
285 | ||
93a37866 A |
286 | // The following are for internal use in debugging and verification |
287 | // code only and not meant as an API for general usage: | |
288 | ||
289 | size_t argIndexForRegister(Register* reg) | |
290 | { | |
291 | // The register at 'offset' number of slots from the frame pointer | |
292 | // i.e. | |
293 | // reg = frame[offset]; | |
294 | // ==> reg = frame + offset; | |
295 | // ==> offset = reg - frame; | |
296 | int offset = reg - this->registers(); | |
297 | ||
298 | // The offset is defined (based on argumentOffset()) to be: | |
81345200 | 299 | // offset = JSStack::FirstArgument - argIndex; |
93a37866 | 300 | // Hence: |
81345200 A |
301 | // argIndex = JSStack::FirstArgument - offset; |
302 | size_t argIndex = offset - JSStack::FirstArgument; | |
93a37866 A |
303 | return argIndex; |
304 | } | |
305 | ||
ed1e77d3 | 306 | void* callerFrameOrVMEntryFrame() const { return callerFrameAndPC().callerFrame; } |
93a37866 | 307 | |
81345200 A |
308 | CallerFrameAndPC& callerFrameAndPC() { return *reinterpret_cast<CallerFrameAndPC*>(this); } |
309 | const CallerFrameAndPC& callerFrameAndPC() const { return *reinterpret_cast<const CallerFrameAndPC*>(this); } | |
310 | ||
93a37866 | 311 | friend class JSStack; |
9dae56ea A |
312 | }; |
313 | ||
314 | } // namespace JSC | |
315 | ||
316 | #endif // CallFrame_h |