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 {
39 class ActivationImp;
40 class Interpreter;
41 class FunctionImp;
42 class FunctionBodyNode;
43 class ProgramNode;
44 class JSGlobalObject;
45 
46 enum CodeType { GlobalCode, EvalCode, FunctionCode };
47 
48 /**
49  * Represents the current state of script execution. This object allows you
50  * obtain a handle the interpreter that is currently executing the script,
51  * and also the current execution context.
52  */
53 class KJS_EXPORT ExecState : Noncopyable
54 {
55     friend class Interpreter;
56     friend class FunctionImp;
57     friend class GlobalFuncImp;
58 public:
59     /**
60      * Returns the interpreter associated with this execution state
61      *
62      * @return The interpreter executing the script
63      */
dynamicInterpreter()64     Interpreter *dynamicInterpreter() const
65     {
66         return m_interpreter;
67     }
68 
69     /**
70      * Returns the interpreter associated with the current scope's
71      * global object
72      *
73      * @return The interpreter currently in scope
74      */
75     Interpreter *lexicalInterpreter() const;
76 
77     /**
78      * This describes how an exception should be handled
79      */
80     enum HandlerType {
81         JumpToCatch,     ///< jump to the specified address
82         PopScope,        ///< remove a scope chain entry, and run the next handler
83         RemoveDeferred,  ///< remove any deferred exception object, and run the next entry
84         Silent           ///< just update the exception object. For debugger-type use only
85     };
86 
87     void pushExceptionHandler(HandlerType type, Addr addr = 0);
88 
89     void popExceptionHandler();
90 
91     // Cleanup depth entries from the stack, w/o running jumps
92     void quietUnwind(int depth);
93 
setMachineRegisters(const unsigned char * pcBase,const unsigned char ** pcLoc,LocalStorageEntry ** machineLocalStoreLoc)94     void setMachineRegisters(const unsigned char *pcBase, const unsigned char **pcLoc, LocalStorageEntry **machineLocalStoreLoc)
95     {
96         m_pcBase            = pcBase;
97         m_pc                = pcLoc;
98         m_machineLocalStore = machineLocalStoreLoc;
99     }
100 
101     /**
102      The below methods deal with deferring of completions inside finally clauses.
103      Essentially, we clear any set exceptions and memorize any non-normal completion
104      (including the target addresses for the continue/break statements) on
105      the m_deferredCompletions stack. If the 'finally' finishes normally,
106      we will resume the previous completion. If not, finally's abnormal
107      termination is handled as usually; a RemoveDeferred cleanup stack
108      entry is added to unwind m_deferredCompletions if that happens.
109     */
110 
deferCompletion()111     void deferCompletion()
112     {
113         pushExceptionHandler(RemoveDeferred);
114         m_deferredCompletions.append(abruptCompletion());
115         clearException();
116     }
117 
118     /**
119      This resumes dispatch of a completion that was deferred due to a try ... finally,
120      handling it as appropriate for whether it's inside an another try-finally.
121      This will handle all the cases itself except for one: return,
122      for which it will return the value to return (otherwise returning 0)
123     */
124     JSValue *reactivateCompletion(bool insideTryFinally);
125 
126     /**
127      * Set the exception associated with this execution state,
128      * updating the program counter appropriately, and executing any relevant EH cleanups.
129      * @param e The JSValue of the exception being set
130      */
131     void setException(JSValue *e);
132 
133     /**
134      * Records an abrupt completion of code, and jumps to the closest catch or finally.
135      * This always happens for exceptions, but can also happen for continue/break/return when
136      * they're inside try ... finally, since that case gets routed through the EH machinery.
137      */
138     void setAbruptCompletion(Completion comp);
139 
140     /**
141      * Clears the exception or other abnormal completion set on this execution state.
142      */
clearException()143     void clearException()
144     {
145         m_completion = Completion();
146     }
147 
148     /**
149      * Returns the exception associated with this execution state.
150      * @return The current execution state exception
151      */
exception()152     JSValue *exception() const
153     {
154         return m_completion.complType() == Throw ? m_completion.value() : nullptr;
155     }
156 
157     /**
158      * Use this to check if an exception was thrown in the current
159      * execution state.
160      *
161      * @return Whether an exception was thrown
162      */
hadException()163     bool hadException() const
164     {
165         return m_completion.complType() == Throw;
166     }
167 
abruptCompletion()168     Completion abruptCompletion() const
169     {
170         return m_completion;
171     }
172 
173     /**
174      * Returns the scope chain for this execution context. This is used for
175      * variable lookup, with the list being searched from start to end until a
176      * variable is found.
177      *
178      * @return The execution context's scope chain
179      */
scopeChain()180     const ScopeChain &scopeChain() const
181     {
182         return scope;
183     }
184 
185     /**
186      * Returns the variable object for the execution context. This contains a
187      * property for each variable declared in the execution context.
188      *
189      * @return The execution context's variable object
190      */
variableObject()191     JSObject *variableObject() const
192     {
193         return m_variable;
194     }
setVariableObject(JSObject * v)195     void setVariableObject(JSObject *v)
196     {
197         m_variable = v;
198     }
199 
200     /**
201      * Returns the "this" value for the execution context. This is the value
202      * returned when a script references the special variable "this". It should
203      * always be an Object, unless application-specific code has passed in a
204      * different type.
205      *
206      * The object that is used as the "this" value depends on the type of
207      * execution context - for global contexts, the global object is used. For
208      * function objewcts, the value is given by the caller (e.g. in the case of
209      * obj.func(), obj would be the "this" value). For code executed by the
210      * built-in "eval" function, the this value is the same as the calling
211      * context.
212      *
213      * @return The execution context's "this" value
214      */
thisValue()215     JSObject *thisValue() const
216     {
217         return m_thisVal;
218     }
219 
220     /**
221      * Returns the context from which the current context was invoked. For
222      * global code this will be a null context (i.e. one for which
223      * isNull() returns true). You should check isNull() on the returned
224      * value before calling any of its methods.
225      *
226      * @return The calling execution context
227      */
callingExecState()228     ExecState *callingExecState()
229     {
230         return m_callingExec;
231     }
232 
233     /**
234      * Returns the execState of a previous nested evaluation session, if any.
235      */
savedExecState()236     ExecState *savedExecState()
237     {
238         return m_savedExec;
239     }
240 
activationObject()241     JSObject *activationObject()
242     {
243         assert(m_codeType == FunctionCode);
244         return m_variable;
245     }
246 
codeType()247     CodeType codeType()
248     {
249         return m_codeType;
250     }
currentBody()251     FunctionBodyNode *currentBody()
252     {
253         return m_currentBody;
254     }
function()255     FunctionImp *function() const
256     {
257         return m_function;
258     }
259 
pushVariableObjectScope(JSVariableObject * s)260     void pushVariableObjectScope(JSVariableObject *s)
261     {
262         scope.pushVariableObject(s);
263     }
pushScope(JSObject * s)264     void pushScope(JSObject *s)
265     {
266         scope.push(s);
267     }
popScope()268     void popScope()
269     {
270         scope.pop();
271     }
272 
273     void mark();
274 
initLocalStorage(LocalStorageEntry * store,size_t size)275     void initLocalStorage(LocalStorageEntry *store, size_t size)
276     {
277         m_localStore = store;
278         m_localStoreSize = size;
279     }
280 
updateLocalStorage(LocalStorageEntry * newStore)281     void updateLocalStorage(LocalStorageEntry *newStore)
282     {
283         m_localStore         = newStore;
284         *m_machineLocalStore = newStore;
285     }
286 
localStorage()287     LocalStorageEntry *localStorage()
288     {
289         return m_localStore;
290     }
291 
292     // This is a workaround to avoid accessing the global variables for these identifiers in
293     // important property lookup functions, to avoid taking PIC branches in Mach-O binaries
propertyNames()294     const CommonIdentifiers &propertyNames() const
295     {
296         return *m_propertyNames;
297     }
298 
299     // Compatibility stuff:
context()300     ExecState *context()
301     {
302         return this;
303     }
callingContext()304     ExecState *callingContext()
305     {
306         return callingExecState();
307     }
308 protected:
309     ExecState(Interpreter *intp, ExecState *save);
310     ~ExecState();
311     void markSelf();
312 
313     Interpreter *m_interpreter;
314     Completion   m_completion;
315     CommonIdentifiers *m_propertyNames;
316     ExecState *m_callingExec;
317     ExecState *m_savedExec; // in case of recursion of evaluation. Needed to mark things properly;
318     // note that this is disjoint from the above, since that's only used for
319     // eval/function, while this is for global.
320 
321     FunctionBodyNode *m_currentBody;
322     FunctionImp *m_function;
323 
324     ScopeChain scope;
325     JSObject *m_variable;
326     JSObject *m_thisVal;
327 
328     LocalStorageEntry      *m_localStore;
329     size_t                  m_localStoreSize;
330 
331     struct ExceptionHandler {
ExceptionHandlerExceptionHandler332         ExceptionHandler() {}
ExceptionHandlerExceptionHandler333         ExceptionHandler(HandlerType type, Addr dest):
334             type(type), dest(dest) {}
335 
336         HandlerType type;
337         Addr        dest;
338     };
339 
340     const unsigned char  *m_pcBase;  // The address of pc = 0
341     const unsigned char **m_pc;      // Where the current fetch address is stored
342     LocalStorageEntry **m_machineLocalStore; // Machine's copy of m_localStore
343     WTF::Vector<ExceptionHandler, 4> m_exceptionHandlers;
344     WTF::Vector<Completion, 4>       m_deferredCompletions;
345 
346     CodeType m_codeType;
347 };
348 
349 typedef ExecState Context; // Compatibility only
350 
351 class GlobalExecState : public ExecState
352 {
353 public:
354     GlobalExecState(Interpreter *intp, JSGlobalObject *global);
355 };
356 
357 class InterpreterExecState : public ExecState
358 {
359 public:
360     InterpreterExecState(Interpreter *intp, JSGlobalObject *global, JSObject *thisObject, ProgramNode *);
361 };
362 
363 class EvalExecState : public ExecState
364 {
365 public:
366     EvalExecState(Interpreter *intp, JSGlobalObject *global, ProgramNode *body, ExecState *callingExecState);
367 };
368 
369 // Note: this does not push the activation on the scope chain,
370 // as the activation is not initialized at this point.
371 class FunctionExecState : public ExecState
372 {
373 public:
374     FunctionExecState(Interpreter *intp, JSObject *thisObject,
375                       FunctionBodyNode *, ExecState *callingExecState, FunctionImp *);
376 };
377 
378 } // namespace KJS
379 
380 #endif // ExecState_H
381