1 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=4 sw=4 et tw=78:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is Mozilla Communicator client code, released
18 : * March 31, 1998.
19 : *
20 : * The Initial Developer of the Original Code is
21 : * Netscape Communications Corporation.
22 : * Portions created by the Initial Developer are Copyright (C) 1998
23 : * the Initial Developer. All Rights Reserved.
24 : *
25 : * Contributor(s):
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #ifndef jsinterp_h___
42 : #define jsinterp_h___
43 : /*
44 : * JS interpreter interface.
45 : */
46 : #include "jsprvtd.h"
47 : #include "jspubtd.h"
48 : #include "jsopcode.h"
49 :
50 : #include "vm/Stack.h"
51 :
52 : namespace js {
53 :
54 : /*
55 : * Refresh and return fp->scopeChain. It may be stale if block scopes are
56 : * active but not yet reflected by objects in the scope chain. If a block
57 : * scope contains a with, eval, XML filtering predicate, or similar such
58 : * dynamically scoped construct, then compile-time block scope at fp->blocks
59 : * must reflect at runtime.
60 : */
61 :
62 : extern JSObject *
63 : GetScopeChain(JSContext *cx);
64 :
65 : extern JSObject *
66 : GetScopeChain(JSContext *cx, StackFrame *fp);
67 :
68 : /*
69 : * ScriptPrologue/ScriptEpilogue must be called in pairs. ScriptPrologue
70 : * must be called before the script executes. ScriptEpilogue must be called
71 : * after the script returns or exits via exception.
72 : */
73 :
74 : inline bool
75 : ScriptPrologue(JSContext *cx, StackFrame *fp, JSScript *script);
76 :
77 : inline bool
78 : ScriptEpilogue(JSContext *cx, StackFrame *fp, bool ok);
79 :
80 : /*
81 : * It is not valid to call ScriptPrologue when a generator is resumed or to
82 : * call ScriptEpilogue when a generator yields. However, the debugger still
83 : * needs LIFO notification of generator start/stop. This pair of functions does
84 : * the right thing based on the state of 'fp'.
85 : */
86 :
87 : inline bool
88 : ScriptPrologueOrGeneratorResume(JSContext *cx, StackFrame *fp);
89 :
90 : inline bool
91 : ScriptEpilogueOrGeneratorYield(JSContext *cx, StackFrame *fp, bool ok);
92 :
93 : /* Implemented in jsdbgapi: */
94 :
95 : /*
96 : * Announce to the debugger that the thread has entered a new JavaScript frame,
97 : * |fp|. Call whatever hooks have been registered to observe new frames, and
98 : * return a JSTrapStatus code indication how execution should proceed:
99 : *
100 : * - JSTRAP_CONTINUE: Continue execution normally.
101 : *
102 : * - JSTRAP_THROW: Throw an exception. ScriptDebugPrologue has set |cx|'s
103 : * pending exception to the value to be thrown.
104 : *
105 : * - JSTRAP_ERROR: Terminate execution (as is done when a script is terminated
106 : * for running too long). ScriptDebugPrologue has cleared |cx|'s pending
107 : * exception.
108 : *
109 : * - JSTRAP_RETURN: Return from the new frame immediately. ScriptDebugPrologue
110 : * has set |cx->fp()|'s return value appropriately.
111 : */
112 : extern JSTrapStatus
113 : ScriptDebugPrologue(JSContext *cx, StackFrame *fp);
114 :
115 : /*
116 : * Announce to the debugger that the thread has exited a JavaScript frame, |fp|.
117 : * If |ok| is true, the frame is returning normally; if |ok| is false, the frame
118 : * is throwing an exception or terminating.
119 : *
120 : * Call whatever hooks have been registered to observe frame exits. Change cx's
121 : * current exception and |fp|'s return value to reflect the changes in behavior
122 : * the hooks request, if any. Return the new error/success value.
123 : *
124 : * This function may be called twice for the same outgoing frame; only the
125 : * first call has any effect. (Permitting double calls simplifies some
126 : * cases where an onPop handler's resumption value changes a return to a
127 : * throw, or vice versa: we can redirect to a complete copy of the
128 : * alternative path, containing its own call to ScriptDebugEpilogue.)
129 : */
130 : extern bool
131 : ScriptDebugEpilogue(JSContext *cx, StackFrame *fp, bool ok);
132 :
133 : /*
134 : * For a given |call|, convert null/undefined |this| into the global object for
135 : * the callee and replace other primitives with boxed versions. This assumes
136 : * that call.callee() is not strict mode code. This is the special/slow case of
137 : * ComputeThis.
138 : */
139 : extern bool
140 : BoxNonStrictThis(JSContext *cx, const CallReceiver &call);
141 :
142 : /*
143 : * Ensure that fp->thisValue() is the correct value of |this| for the scripted
144 : * call represented by |fp|. ComputeThis is necessary because fp->thisValue()
145 : * may be set to 'undefined' when 'this' should really be the global object (as
146 : * an optimization to avoid global-this computation).
147 : */
148 : inline bool
149 : ComputeThis(JSContext *cx, StackFrame *fp);
150 :
151 : enum MaybeConstruct {
152 : NO_CONSTRUCT = INITIAL_NONE,
153 : CONSTRUCT = INITIAL_CONSTRUCT
154 : };
155 :
156 : /*
157 : * InvokeKernel assumes that the given args have been pushed on the top of the
158 : * VM stack. Additionally, if 'args' is contained in a CallArgsList, that they
159 : * have already been marked 'active'.
160 : */
161 : extern bool
162 : InvokeKernel(JSContext *cx, CallArgs args, MaybeConstruct construct = NO_CONSTRUCT);
163 :
164 : /*
165 : * Invoke assumes that 'args' has been pushed (via ContextStack::pushInvokeArgs)
166 : * and is currently at the top of the VM stack.
167 : */
168 : inline bool
169 8710107 : Invoke(JSContext *cx, InvokeArgsGuard &args, MaybeConstruct construct = NO_CONSTRUCT)
170 : {
171 8710107 : args.setActive();
172 8710107 : bool ok = InvokeKernel(cx, args, construct);
173 8710107 : args.setInactive();
174 8710107 : return ok;
175 : }
176 :
177 : /*
178 : * This Invoke overload places the least requirements on the caller: it may be
179 : * called at any time and it takes care of copying the given callee, this, and
180 : * arguments onto the stack.
181 : */
182 : extern bool
183 : Invoke(JSContext *cx, const Value &thisv, const Value &fval, unsigned argc, Value *argv,
184 : Value *rval);
185 :
186 : /*
187 : * This helper takes care of the infinite-recursion check necessary for
188 : * getter/setter calls.
189 : */
190 : extern bool
191 : InvokeGetterOrSetter(JSContext *cx, JSObject *obj, const Value &fval, unsigned argc, Value *argv,
192 : Value *rval);
193 :
194 : /*
195 : * InvokeConstructor* implement a function call from a constructor context
196 : * (e.g. 'new') handling the the creation of the new 'this' object.
197 : */
198 : extern bool
199 : InvokeConstructorKernel(JSContext *cx, const CallArgs &args);
200 :
201 : /* See the InvokeArgsGuard overload of Invoke. */
202 : inline bool
203 8237 : InvokeConstructor(JSContext *cx, InvokeArgsGuard &args)
204 : {
205 8237 : args.setActive();
206 8237 : bool ok = InvokeConstructorKernel(cx, ImplicitCast<CallArgs>(args));
207 8237 : args.setInactive();
208 8237 : return ok;
209 : }
210 :
211 : /* See the fval overload of Invoke. */
212 : extern bool
213 : InvokeConstructor(JSContext *cx, const Value &fval, unsigned argc, Value *argv, Value *rval);
214 :
215 : /*
216 : * Executes a script with the given scopeChain/this. The 'type' indicates
217 : * whether this is eval code or global code. To support debugging, the
218 : * evalFrame parameter can point to an arbitrary frame in the context's call
219 : * stack to simulate executing an eval in that frame.
220 : */
221 : extern bool
222 : ExecuteKernel(JSContext *cx, JSScript *script, JSObject &scopeChain, const Value &thisv,
223 : ExecuteType type, StackFrame *evalInFrame, Value *result);
224 :
225 : /* Execute a script with the given scopeChain as global code. */
226 : extern bool
227 : Execute(JSContext *cx, JSScript *script, JSObject &scopeChain, Value *rval);
228 :
229 : /* Flags to toggle js::Interpret() execution. */
230 : enum InterpMode
231 : {
232 : JSINTERP_NORMAL = 0, /* interpreter is running normally */
233 : JSINTERP_REJOIN = 1, /* as normal, but the frame has already started */
234 : JSINTERP_SKIP_TRAP = 2 /* as REJOIN, but skip trap at first opcode */
235 : };
236 :
237 : /*
238 : * Execute the caller-initialized frame for a user-defined script or function
239 : * pointed to by cx->fp until completion or error.
240 : */
241 : extern JS_NEVER_INLINE bool
242 : Interpret(JSContext *cx, StackFrame *stopFp, InterpMode mode = JSINTERP_NORMAL);
243 :
244 : extern bool
245 : RunScript(JSContext *cx, JSScript *script, StackFrame *fp);
246 :
247 : extern bool
248 : StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *equal);
249 :
250 : extern bool
251 : LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *equal);
252 :
253 : /* === except that NaN is the same as NaN and -0 is not the same as +0. */
254 : extern bool
255 : SameValue(JSContext *cx, const Value &v1, const Value &v2, bool *same);
256 :
257 : extern JSType
258 : TypeOfValue(JSContext *cx, const Value &v);
259 :
260 : extern JSBool
261 : HasInstance(JSContext *cx, JSObject *obj, const js::Value *v, JSBool *bp);
262 :
263 : extern bool
264 : ValueToId(JSContext *cx, const Value &v, jsid *idp);
265 :
266 : /*
267 : * @param closureLevel The static level of the closure that the cookie
268 : * pertains to.
269 : * @param cookie Level amount is a "skip" (delta) value from the
270 : * closure level.
271 : * @return The value of the upvar.
272 : */
273 : extern const Value &
274 : GetUpvar(JSContext *cx, unsigned level, UpvarCookie cookie);
275 :
276 : /* Search the call stack for the nearest frame with static level targetLevel. */
277 : extern StackFrame *
278 : FindUpvarFrame(JSContext *cx, unsigned targetLevel);
279 :
280 : /*
281 : * A linked list of the |FrameRegs regs;| variables belonging to all
282 : * js::Interpret C++ frames on this thread's stack.
283 : *
284 : * Note that this is *not* a list of all JS frames running under the
285 : * interpreter; that would include inlined frames, whose FrameRegs are
286 : * saved in various pieces in various places. Rather, this lists each
287 : * js::Interpret call's live 'regs'; when control returns to that call, it
288 : * will resume execution with this 'regs' instance.
289 : *
290 : * When Debugger puts a script in single-step mode, all js::Interpret
291 : * invocations that might be presently running that script must have
292 : * interrupts enabled. It's not practical to simply check
293 : * script->stepModeEnabled() at each point some callee could have changed
294 : * it, because there are so many places js::Interpret could possibly cause
295 : * JavaScript to run: each place an object might be coerced to a primitive
296 : * or a number, for example. So instead, we simply expose a list of the
297 : * 'regs' those frames are using, and let Debugger tweak the affected
298 : * js::Interpret frames when an onStep handler is established.
299 : *
300 : * Elements of this list are allocated within the js::Interpret stack
301 : * frames themselves; the list is headed by this thread's js::ThreadData.
302 : */
303 : class InterpreterFrames {
304 : public:
305 1977915 : class InterruptEnablerBase {
306 : public:
307 : virtual void enableInterrupts() const = 0;
308 : };
309 :
310 : InterpreterFrames(JSContext *cx, FrameRegs *regs, const InterruptEnablerBase &enabler);
311 : ~InterpreterFrames();
312 :
313 : /* If this js::Interpret frame is running |script|, enable interrupts. */
314 : inline void enableInterruptsIfRunning(JSScript *script);
315 :
316 : InterpreterFrames *older;
317 :
318 : private:
319 : JSContext *context;
320 : FrameRegs *regs;
321 : const InterruptEnablerBase &enabler;
322 : };
323 :
324 : /*
325 : * Unwind block and scope chains to match the given depth. The function sets
326 : * fp->sp on return to stackDepth.
327 : */
328 : extern void
329 : UnwindScope(JSContext *cx, uint32_t stackDepth);
330 :
331 : /*
332 : * Unwind for an uncatchable exception. This means not running finalizers, etc;
333 : * just preserving the basic engine stack invariants.
334 : */
335 : extern void
336 : UnwindForUncatchableException(JSContext *cx, const FrameRegs ®s);
337 :
338 : extern bool
339 : OnUnknownMethod(JSContext *cx, JSObject *obj, Value idval, Value *vp);
340 :
341 : extern bool
342 : IsActiveWithOrBlock(JSContext *cx, JSObject &obj, uint32_t stackDepth);
343 :
344 : class TryNoteIter
345 : {
346 : const FrameRegs ®s;
347 : JSScript *script;
348 : uint32_t pcOffset;
349 : JSTryNote *tn, *tnEnd;
350 : void settle();
351 : public:
352 : TryNoteIter(const FrameRegs ®s);
353 : bool done() const;
354 : void operator++();
355 56411 : JSTryNote *operator*() const { return tn; }
356 : };
357 :
358 : /************************************************************************/
359 :
360 : /*
361 : * To really poison a set of values, using 'magic' or 'undefined' isn't good
362 : * enough since often these will just be ignored by buggy code (see bug 629974)
363 : * in debug builds and crash in release builds. Instead, we use a safe-for-crash
364 : * pointer.
365 : */
366 : static JS_ALWAYS_INLINE void
367 7072811 : Debug_SetValueRangeToCrashOnTouch(Value *beg, Value *end)
368 : {
369 : #ifdef DEBUG
370 127401722 : for (Value *v = beg; v != end; ++v)
371 120328911 : v->setObject(*reinterpret_cast<JSObject *>(0x42));
372 : #endif
373 7072811 : }
374 :
375 : static JS_ALWAYS_INLINE void
376 7072811 : Debug_SetValueRangeToCrashOnTouch(Value *vec, size_t len)
377 : {
378 : #ifdef DEBUG
379 7072811 : Debug_SetValueRangeToCrashOnTouch(vec, vec + len);
380 : #endif
381 7072811 : }
382 :
383 : static JS_ALWAYS_INLINE void
384 : Debug_SetValueRangeToCrashOnTouch(HeapValue *vec, size_t len)
385 : {
386 : #ifdef DEBUG
387 : Debug_SetValueRangeToCrashOnTouch((Value *) vec, len);
388 : #endif
389 : }
390 :
391 : static JS_ALWAYS_INLINE void
392 6364621 : Debug_SetSlotRangeToCrashOnTouch(HeapSlot *vec, size_t len)
393 : {
394 : #ifdef DEBUG
395 6364621 : Debug_SetValueRangeToCrashOnTouch((Value *) vec, len);
396 : #endif
397 6364621 : }
398 :
399 : static JS_ALWAYS_INLINE void
400 5084 : Debug_SetSlotRangeToCrashOnTouch(HeapSlot *begin, HeapSlot *end)
401 : {
402 : #ifdef DEBUG
403 5084 : Debug_SetValueRangeToCrashOnTouch((Value *) begin, end - begin);
404 : #endif
405 5084 : }
406 :
407 : } /* namespace js */
408 :
409 : #endif /* jsinterp_h___ */
|