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
37namespace 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