js/src/vm/Interpreter.h

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:834fdc8b7674
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #ifndef vm_Interpreter_h
8 #define vm_Interpreter_h
9
10 /*
11 * JS interpreter interface.
12 */
13
14 #include "jsiter.h"
15 #include "jspubtd.h"
16
17 #include "vm/Stack.h"
18
19 namespace js {
20
21 class ScopeIter;
22
23 /*
24 * Announce to the debugger that the thread has entered a new JavaScript frame,
25 * |frame|. Call whatever hooks have been registered to observe new frames, and
26 * return a JSTrapStatus code indication how execution should proceed:
27 *
28 * - JSTRAP_CONTINUE: Continue execution normally.
29 *
30 * - JSTRAP_THROW: Throw an exception. ScriptDebugPrologue has set |cx|'s
31 * pending exception to the value to be thrown.
32 *
33 * - JSTRAP_ERROR: Terminate execution (as is done when a script is terminated
34 * for running too long). ScriptDebugPrologue has cleared |cx|'s pending
35 * exception.
36 *
37 * - JSTRAP_RETURN: Return from the new frame immediately. ScriptDebugPrologue
38 * has set |frame|'s return value appropriately.
39 */
40 extern JSTrapStatus
41 ScriptDebugPrologue(JSContext *cx, AbstractFramePtr frame, jsbytecode *pc);
42
43 /*
44 * Announce to the debugger that the thread has exited a JavaScript frame, |frame|.
45 * If |ok| is true, the frame is returning normally; if |ok| is false, the frame
46 * is throwing an exception or terminating.
47 *
48 * Call whatever hooks have been registered to observe frame exits. Change cx's
49 * current exception and |frame|'s return value to reflect the changes in behavior
50 * the hooks request, if any. Return the new error/success value.
51 *
52 * This function may be called twice for the same outgoing frame; only the
53 * first call has any effect. (Permitting double calls simplifies some
54 * cases where an onPop handler's resumption value changes a return to a
55 * throw, or vice versa: we can redirect to a complete copy of the
56 * alternative path, containing its own call to ScriptDebugEpilogue.)
57 */
58 extern bool
59 ScriptDebugEpilogue(JSContext *cx, AbstractFramePtr frame, jsbytecode *pc, bool ok);
60
61 /*
62 * Announce to the debugger that an exception has been thrown and propagated
63 * to |frame|. Call whatever hooks have been registered to observe this and
64 * return a JSTrapStatus code indication how execution should proceed:
65 *
66 * - JSTRAP_CONTINUE: Continue throwing the current exception.
67 *
68 * - JSTRAP_THROW: Throw another value. DebugExceptionUnwind has set |cx|'s
69 * pending exception to the new value.
70 *
71 * - JSTRAP_ERROR: Terminate execution. DebugExceptionUnwind has cleared |cx|'s
72 * pending exception.
73 *
74 * - JSTRAP_RETURN: Return from |frame|. DebugExceptionUnwind has cleared
75 * |cx|'s pending exception and set |frame|'s return value.
76 */
77 extern JSTrapStatus
78 DebugExceptionUnwind(JSContext *cx, AbstractFramePtr frame, jsbytecode *pc);
79
80 /*
81 * For a given |call|, convert null/undefined |this| into the global object for
82 * the callee and replace other primitives with boxed versions. This assumes
83 * that call.callee() is not strict mode code. This is the special/slow case of
84 * ComputeThis.
85 */
86 extern bool
87 BoxNonStrictThis(JSContext *cx, const CallReceiver &call);
88
89 extern JSObject *
90 BoxNonStrictThis(JSContext *cx, HandleValue thisv);
91
92 /*
93 * Ensure that fp->thisValue() is the correct value of |this| for the scripted
94 * call represented by |fp|. ComputeThis is necessary because fp->thisValue()
95 * may be set to 'undefined' when 'this' should really be the global object (as
96 * an optimization to avoid global-this computation).
97 */
98 inline bool
99 ComputeThis(JSContext *cx, AbstractFramePtr frame);
100
101 enum MaybeConstruct {
102 NO_CONSTRUCT = INITIAL_NONE,
103 CONSTRUCT = INITIAL_CONSTRUCT
104 };
105
106 /*
107 * numToSkip is the number of stack values the expression decompiler should skip
108 * before it reaches |v|. If it's -1, the decompiler will search the stack.
109 */
110 extern bool
111 ReportIsNotFunction(JSContext *cx, HandleValue v, int numToSkip = -1,
112 MaybeConstruct construct = NO_CONSTRUCT);
113
114 /* See ReportIsNotFunction comment for the meaning of numToSkip. */
115 extern JSObject *
116 ValueToCallable(JSContext *cx, HandleValue v, int numToSkip = -1,
117 MaybeConstruct construct = NO_CONSTRUCT);
118
119 /*
120 * Invoke assumes that the given args have been pushed on the top of the
121 * VM stack.
122 */
123 extern bool
124 Invoke(JSContext *cx, CallArgs args, MaybeConstruct construct = NO_CONSTRUCT);
125
126 /*
127 * This Invoke overload places the least requirements on the caller: it may be
128 * called at any time and it takes care of copying the given callee, this, and
129 * arguments onto the stack.
130 */
131 extern bool
132 Invoke(JSContext *cx, const Value &thisv, const Value &fval, unsigned argc, const Value *argv,
133 MutableHandleValue rval);
134
135 /*
136 * This helper takes care of the infinite-recursion check necessary for
137 * getter/setter calls.
138 */
139 extern bool
140 InvokeGetterOrSetter(JSContext *cx, JSObject *obj, Value fval, unsigned argc, Value *argv,
141 MutableHandleValue rval);
142
143 /*
144 * InvokeConstructor implement a function call from a constructor context
145 * (e.g. 'new') handling the the creation of the new 'this' object.
146 */
147 extern bool
148 InvokeConstructor(JSContext *cx, CallArgs args);
149
150 /* See the fval overload of Invoke. */
151 extern bool
152 InvokeConstructor(JSContext *cx, Value fval, unsigned argc, Value *argv, Value *rval);
153
154 /*
155 * Executes a script with the given scopeChain/this. The 'type' indicates
156 * whether this is eval code or global code. To support debugging, the
157 * evalFrame parameter can point to an arbitrary frame in the context's call
158 * stack to simulate executing an eval in that frame.
159 */
160 extern bool
161 ExecuteKernel(JSContext *cx, HandleScript script, JSObject &scopeChain, const Value &thisv,
162 ExecuteType type, AbstractFramePtr evalInFrame, Value *result);
163
164 /* Execute a script with the given scopeChain as global code. */
165 extern bool
166 Execute(JSContext *cx, HandleScript script, JSObject &scopeChain, Value *rval);
167
168 class ExecuteState;
169 class InvokeState;
170 class GeneratorState;
171
172 // RunState is passed to RunScript and RunScript then eiter passes it to the
173 // interpreter or to the JITs. RunState contains all information we need to
174 // construct an interpreter or JIT frame.
175 class RunState
176 {
177 protected:
178 enum Kind { Execute, Invoke, Generator };
179 Kind kind_;
180
181 RootedScript script_;
182
183 explicit RunState(JSContext *cx, Kind kind, JSScript *script)
184 : kind_(kind),
185 script_(cx, script)
186 { }
187
188 public:
189 bool isExecute() const { return kind_ == Execute; }
190 bool isInvoke() const { return kind_ == Invoke; }
191 bool isGenerator() const { return kind_ == Generator; }
192
193 ExecuteState *asExecute() const {
194 JS_ASSERT(isExecute());
195 return (ExecuteState *)this;
196 }
197 InvokeState *asInvoke() const {
198 JS_ASSERT(isInvoke());
199 return (InvokeState *)this;
200 }
201 GeneratorState *asGenerator() const {
202 JS_ASSERT(isGenerator());
203 return (GeneratorState *)this;
204 }
205
206 JSScript *script() const { return script_; }
207
208 virtual InterpreterFrame *pushInterpreterFrame(JSContext *cx) = 0;
209 virtual void setReturnValue(Value v) = 0;
210
211 private:
212 RunState(const RunState &other) MOZ_DELETE;
213 RunState(const ExecuteState &other) MOZ_DELETE;
214 RunState(const InvokeState &other) MOZ_DELETE;
215 RunState(const GeneratorState &other) MOZ_DELETE;
216 void operator=(const RunState &other) MOZ_DELETE;
217 };
218
219 // Eval or global script.
220 class ExecuteState : public RunState
221 {
222 ExecuteType type_;
223
224 RootedValue thisv_;
225 RootedObject scopeChain_;
226
227 AbstractFramePtr evalInFrame_;
228 Value *result_;
229
230 public:
231 ExecuteState(JSContext *cx, JSScript *script, const Value &thisv, JSObject &scopeChain,
232 ExecuteType type, AbstractFramePtr evalInFrame, Value *result)
233 : RunState(cx, Execute, script),
234 type_(type),
235 thisv_(cx, thisv),
236 scopeChain_(cx, &scopeChain),
237 evalInFrame_(evalInFrame),
238 result_(result)
239 { }
240
241 Value *addressOfThisv() { return thisv_.address(); }
242 JSObject *scopeChain() const { return scopeChain_; }
243 ExecuteType type() const { return type_; }
244
245 virtual InterpreterFrame *pushInterpreterFrame(JSContext *cx);
246
247 virtual void setReturnValue(Value v) {
248 if (result_)
249 *result_ = v;
250 }
251 };
252
253 // Data to invoke a function.
254 class InvokeState : public RunState
255 {
256 CallArgs &args_;
257 InitialFrameFlags initial_;
258 bool useNewType_;
259
260 public:
261 InvokeState(JSContext *cx, CallArgs &args, InitialFrameFlags initial)
262 : RunState(cx, Invoke, args.callee().as<JSFunction>().nonLazyScript()),
263 args_(args),
264 initial_(initial),
265 useNewType_(false)
266 { }
267
268 bool useNewType() const { return useNewType_; }
269 void setUseNewType() { useNewType_ = true; }
270
271 bool constructing() const { return InitialFrameFlagsAreConstructing(initial_); }
272 CallArgs &args() const { return args_; }
273
274 virtual InterpreterFrame *pushInterpreterFrame(JSContext *cx);
275
276 virtual void setReturnValue(Value v) {
277 args_.rval().set(v);
278 }
279 };
280
281 // Generator script.
282 class GeneratorState : public RunState
283 {
284 JSContext *cx_;
285 JSGenerator *gen_;
286 JSGeneratorState futureState_;
287 bool entered_;
288
289 public:
290 GeneratorState(JSContext *cx, JSGenerator *gen, JSGeneratorState futureState);
291 ~GeneratorState();
292
293 virtual InterpreterFrame *pushInterpreterFrame(JSContext *cx);
294 virtual void setReturnValue(Value) { }
295
296 JSGenerator *gen() const { return gen_; }
297 };
298
299 extern bool
300 RunScript(JSContext *cx, RunState &state);
301
302 extern bool
303 StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *equal);
304
305 extern bool
306 LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *equal);
307
308 /* === except that NaN is the same as NaN and -0 is not the same as +0. */
309 extern bool
310 SameValue(JSContext *cx, const Value &v1, const Value &v2, bool *same);
311
312 extern JSType
313 TypeOfObject(JSObject *obj);
314
315 extern JSType
316 TypeOfValue(const Value &v);
317
318 extern bool
319 HasInstance(JSContext *cx, HandleObject obj, HandleValue v, bool *bp);
320
321 // Unwind scope chain and iterator to match the static scope corresponding to
322 // the given bytecode position.
323 extern void
324 UnwindScope(JSContext *cx, ScopeIter &si, jsbytecode *pc);
325
326 /*
327 * Unwind for an uncatchable exception. This means not running finalizers, etc;
328 * just preserving the basic engine stack invariants.
329 */
330 extern void
331 UnwindForUncatchableException(JSContext *cx, const InterpreterRegs &regs);
332
333 extern bool
334 OnUnknownMethod(JSContext *cx, HandleObject obj, Value idval, MutableHandleValue vp);
335
336 class TryNoteIter
337 {
338 const InterpreterRegs &regs;
339 RootedScript script; /* TryNotIter is always stack allocated. */
340 uint32_t pcOffset;
341 JSTryNote *tn, *tnEnd;
342
343 void settle();
344
345 public:
346 explicit TryNoteIter(JSContext *cx, const InterpreterRegs &regs);
347 bool done() const;
348 void operator++();
349 JSTryNote *operator*() const { return tn; }
350 };
351
352 /************************************************************************/
353
354 bool
355 Throw(JSContext *cx, HandleValue v);
356
357 bool
358 GetProperty(JSContext *cx, HandleValue value, HandlePropertyName name, MutableHandleValue vp);
359
360 bool
361 CallProperty(JSContext *cx, HandleValue value, HandlePropertyName name, MutableHandleValue vp);
362
363 bool
364 GetScopeName(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHandleValue vp);
365
366 bool
367 GetScopeNameForTypeOf(JSContext *cx, HandleObject obj, HandlePropertyName name,
368 MutableHandleValue vp);
369
370 JSObject *
371 Lambda(JSContext *cx, HandleFunction fun, HandleObject parent);
372
373 JSObject *
374 LambdaArrow(JSContext *cx, HandleFunction fun, HandleObject parent, HandleValue thisv);
375
376 bool
377 GetElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res);
378
379 bool
380 CallElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res);
381
382 bool
383 SetObjectElement(JSContext *cx, HandleObject obj, HandleValue index, HandleValue value,
384 bool strict);
385 bool
386 SetObjectElement(JSContext *cx, HandleObject obj, HandleValue index, HandleValue value,
387 bool strict, HandleScript script, jsbytecode *pc);
388
389 bool
390 InitElementArray(JSContext *cx, jsbytecode *pc,
391 HandleObject obj, uint32_t index, HandleValue value);
392
393 bool
394 AddValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res);
395
396 bool
397 SubValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res);
398
399 bool
400 MulValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res);
401
402 bool
403 DivValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res);
404
405 bool
406 ModValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res);
407
408 bool
409 UrshValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res);
410
411 template <bool strict>
412 bool
413 SetProperty(JSContext *cx, HandleObject obj, HandleId id, const Value &value);
414
415 template <bool strict>
416 bool
417 DeleteProperty(JSContext *ctx, HandleValue val, HandlePropertyName name, bool *bv);
418
419 template <bool strict>
420 bool
421 DeleteElement(JSContext *cx, HandleValue val, HandleValue index, bool *bv);
422
423 bool
424 DefFunOperation(JSContext *cx, HandleScript script, HandleObject scopeChain, HandleFunction funArg);
425
426 bool
427 SetCallOperation(JSContext *cx);
428
429 bool
430 GetAndClearException(JSContext *cx, MutableHandleValue res);
431
432 bool
433 DeleteNameOperation(JSContext *cx, HandlePropertyName name, HandleObject scopeObj,
434 MutableHandleValue res);
435
436 bool
437 ImplicitThisOperation(JSContext *cx, HandleObject scopeObj, HandlePropertyName name,
438 MutableHandleValue res);
439
440 bool
441 IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, MutableHandleValue rval);
442
443 bool
444 IteratorNext(JSContext *cx, HandleObject iterobj, MutableHandleValue rval);
445
446 bool
447 RunOnceScriptPrologue(JSContext *cx, HandleScript script);
448
449 bool
450 InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleId id,
451 HandleObject val);
452
453 bool
454 InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandlePropertyName name,
455 HandleObject val);
456
457 bool
458 EnterWithOperation(JSContext *cx, AbstractFramePtr frame, HandleValue val, HandleObject staticWith);
459
460
461 bool
462 InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleValue idval,
463 HandleObject val);
464
465 inline bool
466 SetConstOperation(JSContext *cx, HandleObject varobj, HandlePropertyName name, HandleValue rval)
467 {
468 return JSObject::defineProperty(cx, varobj, name, rval,
469 JS_PropertyStub, JS_StrictPropertyStub,
470 JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY);
471 }
472
473 } /* namespace js */
474
475 #endif /* vm_Interpreter_h */

mercurial