1 | /* |
2 | * This file is part of the KDE libraries |
3 | * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) |
4 | * Copyright (C) 2001 Peter Kelly (pmk@post.com) |
5 | * Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved. |
6 | * Copyright (C) 2008 Maksim Orlovich (maksim@kde.org) |
7 | * |
8 | * This library is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU Library General Public |
10 | * License as published by the Free Software Foundation; either |
11 | * version 2 of the License, or (at your option) any later version. |
12 | * |
13 | * This library is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * Library General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU Library General Public License |
19 | * along with this library; see the file COPYING.LIB. If not, write to |
20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
21 | * Boston, MA 02110-1301, USA. |
22 | * |
23 | */ |
24 | |
25 | #ifndef ExecState_H |
26 | #define ExecState_H |
27 | |
28 | #include "completion.h" |
29 | #include "value.h" |
30 | #include "types.h" |
31 | #include "CommonIdentifiers.h" |
32 | #include "scope_chain.h" |
33 | #include "LocalStorage.h" |
34 | #include "wtf/Vector.h" |
35 | #include "PropertyNameArray.h" |
36 | |
37 | namespace KJS { |
38 | class ActivationImp; |
39 | class Interpreter; |
40 | class FunctionImp; |
41 | class FunctionBodyNode; |
42 | class ProgramNode; |
43 | class JSGlobalObject; |
44 | |
45 | enum CodeType { GlobalCode, EvalCode, FunctionCode }; |
46 | |
47 | /** |
48 | * Represents the current state of script execution. This object allows you |
49 | * obtain a handle the interpreter that is currently executing the script, |
50 | * and also the current execution context. |
51 | */ |
52 | class KJS_EXPORT ExecState : Noncopyable { |
53 | friend class Interpreter; |
54 | friend class FunctionImp; |
55 | friend class GlobalFuncImp; |
56 | public: |
57 | /** |
58 | * Returns the interpreter associated with this execution state |
59 | * |
60 | * @return The interpreter executing the script |
61 | */ |
62 | Interpreter* dynamicInterpreter() const { return m_interpreter; } |
63 | |
64 | /** |
65 | * Returns the interpreter associated with the current scope's |
66 | * global object |
67 | * |
68 | * @return The interpreter currently in scope |
69 | */ |
70 | Interpreter* lexicalInterpreter() const; |
71 | |
72 | /** |
73 | * This describes how an exception should be handled |
74 | */ |
75 | enum HandlerType { |
76 | JumpToCatch, ///< jump to the specified address |
77 | PopScope, ///< remove a scope chain entry, and run the next handler |
78 | RemoveDeferred, ///< remove any deferred exception object, and run the next entry |
79 | Silent ///< just update the exception object. For debugger-type use only |
80 | }; |
81 | |
82 | void pushExceptionHandler(HandlerType type, Addr addr = 0); |
83 | |
84 | void popExceptionHandler(); |
85 | |
86 | // Cleanup depth entries from the stack, w/o running jumps |
87 | void quietUnwind(int depth); |
88 | |
89 | void setMachineRegisters(const unsigned char* pcBase, const unsigned char** pcLoc, LocalStorageEntry** machineLocalStoreLoc) { |
90 | m_pcBase = pcBase; |
91 | m_pc = pcLoc; |
92 | m_machineLocalStore = machineLocalStoreLoc; |
93 | } |
94 | |
95 | /** |
96 | The below methods deal with deferring of completions inside finally clauses. |
97 | Essentially, we clear any set exceptions and memorize any non-normal completion |
98 | (including the target addresses for the continue/break statements) on |
99 | the m_deferredCompletions stack. If the 'finally' finishes normally, |
100 | we will resume the previous completion. If not, finally's abnormal |
101 | termination is handled as usually; a RemoveDeferred cleanup stack |
102 | entry is added to unwind m_deferredCompletions if that happens. |
103 | */ |
104 | |
105 | void deferCompletion() { |
106 | pushExceptionHandler(RemoveDeferred); |
107 | m_deferredCompletions.append(abruptCompletion()); |
108 | clearException(); |
109 | } |
110 | |
111 | /** |
112 | This resumes dispatch of a completion that was deferred due to a try ... finally, |
113 | handling it as appropriate for whether it's inside an another try-finally. |
114 | This will handle all the cases itself except for one: return, |
115 | for which it will return the value to return (otherwise returning 0) |
116 | */ |
117 | JSValue* reactivateCompletion(bool insideTryFinally); |
118 | |
119 | /** |
120 | * Set the exception associated with this execution state, |
121 | * updating the program counter appropriately, and executing any relevant EH cleanups. |
122 | * @param e The JSValue of the exception being set |
123 | */ |
124 | void setException(JSValue* e); |
125 | |
126 | /** |
127 | * Records an abrupt completion of code, and jumps to the closest catch or finally. |
128 | * This always happens for exceptions, but can also happen for continue/break/return when |
129 | * they're inside try ... finally, since that case gets routed through the EH machinery. |
130 | */ |
131 | void setAbruptCompletion(Completion comp); |
132 | |
133 | /** |
134 | * Clears the exception or other abnormal completion set on this execution state. |
135 | */ |
136 | void clearException() { m_completion = Completion(); } |
137 | |
138 | /** |
139 | * Returns the exception associated with this execution state. |
140 | * @return The current execution state exception |
141 | */ |
142 | JSValue* exception() const { return m_completion.complType() == Throw ? m_completion.value() : 0; } |
143 | |
144 | /** |
145 | * Use this to check if an exception was thrown in the current |
146 | * execution state. |
147 | * |
148 | * @return Whether an exception was thrown |
149 | */ |
150 | bool hadException() const { return m_completion.complType() == Throw; } |
151 | |
152 | Completion abruptCompletion() const { return m_completion; } |
153 | |
154 | /** |
155 | * Returns the scope chain for this execution context. This is used for |
156 | * variable lookup, with the list being searched from start to end until a |
157 | * variable is found. |
158 | * |
159 | * @return The execution context's scope chain |
160 | */ |
161 | const ScopeChain& scopeChain() const { return scope; } |
162 | |
163 | /** |
164 | * Returns the variable object for the execution context. This contains a |
165 | * property for each variable declared in the execution context. |
166 | * |
167 | * @return The execution context's variable object |
168 | */ |
169 | JSObject* variableObject() const { return m_variable; } |
170 | void setVariableObject(JSObject* v) { m_variable = v; } |
171 | |
172 | /** |
173 | * Returns the "this" value for the execution context. This is the value |
174 | * returned when a script references the special variable "this". It should |
175 | * always be an Object, unless application-specific code has passed in a |
176 | * different type. |
177 | * |
178 | * The object that is used as the "this" value depends on the type of |
179 | * execution context - for global contexts, the global object is used. For |
180 | * function objewcts, the value is given by the caller (e.g. in the case of |
181 | * obj.func(), obj would be the "this" value). For code executed by the |
182 | * built-in "eval" function, the this value is the same as the calling |
183 | * context. |
184 | * |
185 | * @return The execution context's "this" value |
186 | */ |
187 | JSObject* thisValue() const { return m_thisVal; } |
188 | |
189 | /** |
190 | * Returns the context from which the current context was invoked. For |
191 | * global code this will be a null context (i.e. one for which |
192 | * isNull() returns true). You should check isNull() on the returned |
193 | * value before calling any of its methods. |
194 | * |
195 | * @return The calling execution context |
196 | */ |
197 | ExecState* callingExecState() { return m_callingExec; } |
198 | |
199 | /** |
200 | * Returns the execState of a previous nested evaluation session, if any. |
201 | */ |
202 | ExecState* savedExecState() { return m_savedExec; } |
203 | |
204 | JSObject* activationObject() { |
205 | assert(m_codeType == FunctionCode); |
206 | return m_variable; |
207 | } |
208 | |
209 | CodeType codeType() { return m_codeType; } |
210 | FunctionBodyNode* currentBody() { return m_currentBody; } |
211 | FunctionImp* function() const { return m_function; } |
212 | |
213 | void pushVariableObjectScope(JSVariableObject* s) { scope.pushVariableObject(s); } |
214 | void pushScope(JSObject* s) { scope.push(s); } |
215 | void popScope() { scope.pop(); } |
216 | |
217 | void mark(); |
218 | |
219 | void initLocalStorage(LocalStorageEntry* store, size_t size) { |
220 | m_localStore = store; |
221 | m_localStoreSize = size; |
222 | } |
223 | |
224 | void updateLocalStorage(LocalStorageEntry* newStore) { |
225 | m_localStore = newStore; |
226 | *m_machineLocalStore = newStore; |
227 | } |
228 | |
229 | LocalStorageEntry* localStorage() { return m_localStore; } |
230 | |
231 | // This is a workaround to avoid accessing the global variables for these identifiers in |
232 | // important property lookup functions, to avoid taking PIC branches in Mach-O binaries |
233 | const CommonIdentifiers& propertyNames() const { return *m_propertyNames; } |
234 | |
235 | // Compatibility stuff: |
236 | ExecState* context() { return this; } |
237 | ExecState* callingContext() { return callingExecState(); } |
238 | protected: |
239 | ExecState(Interpreter* intp, ExecState* save); |
240 | ~ExecState(); |
241 | void markSelf(); |
242 | |
243 | Interpreter* m_interpreter; |
244 | Completion m_completion; |
245 | CommonIdentifiers* m_propertyNames; |
246 | ExecState* m_callingExec; |
247 | ExecState* m_savedExec; // in case of recursion of evaluation. Needed to mark things properly; |
248 | // note that this is disjoint from the above, since that's only used for |
249 | // eval/function, while this is for global. |
250 | |
251 | FunctionBodyNode* m_currentBody; |
252 | FunctionImp* m_function; |
253 | |
254 | ScopeChain scope; |
255 | JSObject* m_variable; |
256 | JSObject* m_thisVal; |
257 | |
258 | LocalStorageEntry* m_localStore; |
259 | size_t m_localStoreSize; |
260 | |
261 | struct ExceptionHandler { |
262 | ExceptionHandler() {} |
263 | ExceptionHandler(HandlerType type, Addr dest): |
264 | type(type), dest(dest) {} |
265 | |
266 | HandlerType type; |
267 | Addr dest; |
268 | }; |
269 | |
270 | const unsigned char* m_pcBase; // The address of pc = 0 |
271 | const unsigned char** m_pc; // Where the current fetch address is stored |
272 | LocalStorageEntry** m_machineLocalStore; // Machine's copy of m_localStore |
273 | WTF::Vector<ExceptionHandler, 4> m_exceptionHandlers; |
274 | WTF::Vector<Completion, 4> m_deferredCompletions; |
275 | |
276 | CodeType m_codeType; |
277 | }; |
278 | |
279 | typedef ExecState Context; // Compatibility only |
280 | |
281 | class GlobalExecState : public ExecState { |
282 | public: |
283 | GlobalExecState(Interpreter* intp, JSGlobalObject* global); |
284 | }; |
285 | |
286 | class InterpreterExecState : public ExecState { |
287 | public: |
288 | InterpreterExecState(Interpreter* intp, JSGlobalObject* global, JSObject* thisObject, ProgramNode*); |
289 | }; |
290 | |
291 | class EvalExecState : public ExecState { |
292 | public: |
293 | EvalExecState(Interpreter* intp, JSGlobalObject* global, ProgramNode* body, ExecState* callingExecState); |
294 | }; |
295 | |
296 | // Note: this does not push the activation on the scope chain, |
297 | // as the activation is not initialized at this point. |
298 | class FunctionExecState : public ExecState { |
299 | public: |
300 | FunctionExecState(Interpreter* intp, JSObject* thisObject, |
301 | FunctionBodyNode*, ExecState* callingExecState, FunctionImp*); |
302 | }; |
303 | |
304 | } // namespace KJS |
305 | |
306 | #endif // ExecState_H |
307 | |