Bug 578272: Remove Algol-like display optimization. (r=brendan)
[mozilla-central.git] / js / src / jsinterp.h
blob1645c90b42b494df73ff951403df146d4e9b14a8
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=4 sw=4 et tw=78:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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.
17 * The Original Code is Mozilla Communicator client code, released
18 * March 31, 1998.
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.
25 * Contributor(s):
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.
39 * ***** END LICENSE BLOCK ***** */
41 #ifndef jsinterp_h___
42 #define jsinterp_h___
44 * JS interpreter interface.
46 #include "jsprvtd.h"
47 #include "jspubtd.h"
48 #include "jsfun.h"
49 #include "jsopcode.h"
50 #include "jsscript.h"
51 #include "jsvalue.h"
53 typedef struct JSFrameRegs {
54 jsbytecode *pc; /* program counter */
55 js::Value *sp; /* stack pointer */
56 } JSFrameRegs;
58 /* JS stack frame flags. */
59 enum JSFrameFlags {
60 JSFRAME_CONSTRUCTING = 0x01, /* frame is for a constructor invocation */
61 JSFRAME_COMPUTED_THIS = 0x02, /* frame.thisv was computed already and
62 JSVAL_IS_OBJECT(thisv) */
63 JSFRAME_ASSIGNING = 0x04, /* a complex (not simplex JOF_ASSIGNING) op
64 is currently assigning to a property */
65 JSFRAME_DEBUGGER = 0x08, /* frame for JS_EvaluateInStackFrame */
66 JSFRAME_EVAL = 0x10, /* frame for obj_eval */
67 JSFRAME_FLOATING_GENERATOR = 0x20, /* frame copy stored in a generator obj */
68 JSFRAME_YIELDING = 0x40, /* js_Interpret dispatched JSOP_YIELD */
69 JSFRAME_GENERATOR = 0x80, /* frame belongs to generator-iterator */
70 JSFRAME_OVERRIDE_ARGS = 0x100, /* overridden arguments local variable */
72 JSFRAME_SPECIAL = JSFRAME_DEBUGGER | JSFRAME_EVAL
76 * JS stack frame, may be allocated on the C stack by native callers. Always
77 * allocated on cx->stackPool for calls from the interpreter to an interpreted
78 * function.
80 * NB: This struct is manually initialized in jsinterp.c and jsiter.c. If you
81 * add new members, update both files.
83 struct JSStackFrame
85 jsbytecode *imacpc; /* null or interpreter macro call pc */
86 JSObject *callobj; /* lazily created Call object */
87 JSObject *argsobj; /* lazily created arguments object */
88 JSScript *script; /* script being interpreted */
89 js::Value thisv; /* "this" pointer if in method */
90 JSFunction *fun; /* function being called or null */
91 uintN argc; /* actual argument count */
92 js::Value *argv; /* base of argument stack slots */
93 void *annotation; /* used by Java security */
94 js::Value rval; /* function return value */
96 /* Maintained by StackSpace operations */
97 JSStackFrame *down; /* previous frame, part of
98 stack layout invariant */
99 jsbytecode *savedPC; /* only valid if cx->fp != this */
100 #ifdef DEBUG
101 static jsbytecode *const sInvalidPC;
102 #endif
105 * We can't determine in advance which local variables can live on
106 * the stack and be freed when their dynamic scope ends, and which
107 * will be closed over and need to live in the heap. So we place
108 * variables on the stack initially, note when they are closed
109 * over, and copy those that are out to the heap when we leave
110 * their dynamic scope.
112 * The bytecode compiler produces a tree of block objects
113 * accompanying each JSScript representing those lexical blocks in
114 * the script that have let-bound variables associated with them.
115 * These block objects are never modified, and never become part
116 * of any function's scope chain. Their parent slots point to the
117 * innermost block that encloses them, or are NULL in the
118 * outermost blocks within a function or in eval or global code.
120 * When we are in the static scope of such a block, blockChain
121 * points to its compiler-allocated block object; otherwise, it is
122 * NULL.
124 * scopeChain is the current scope chain, including 'call' and
125 * 'block' objects for those function calls and lexical blocks
126 * whose static scope we are currently executing in, and 'with'
127 * objects for with statements; the chain is typically terminated
128 * by a global object. However, as an optimization, the young end
129 * of the chain omits block objects we have not yet cloned. To
130 * create a closure, we clone the missing blocks from blockChain
131 * (which is always current), place them at the head of
132 * scopeChain, and use that for the closure's scope chain. If we
133 * never close over a lexical block, we never place a mutable
134 * clone of it on scopeChain.
136 * This lazy cloning is implemented in js_GetScopeChain, which is
137 * also used in some other cases --- entering 'with' blocks, for
138 * example.
140 JSObject *scopeChain;
141 JSObject *blockChain;
143 uint32 flags; /* frame flags -- see below */
144 JSStackFrame *displaySave; /* previous value of display entry for
145 script->staticLevel */
147 /* Members only needed for inline calls. */
148 void *hookData; /* debugger call hook data */
149 JSVersion callerVersion; /* dynamic version of calling script */
151 void putActivationObjects(JSContext *cx) {
153 * The order of calls here is important as js_PutCallObject needs to
154 * access argsobj.
156 if (callobj) {
157 js_PutCallObject(cx, this);
158 JS_ASSERT(!argsobj);
159 } else if (argsobj) {
160 js_PutArgsObject(cx, this);
164 /* Get the frame's current bytecode, assuming |this| is in |cx|. */
165 jsbytecode *pc(JSContext *cx) const;
167 js::Value *argEnd() const {
168 return (js::Value *)this;
171 js::Value *slots() const {
172 return (js::Value *)(this + 1);
175 js::Value *base() const {
176 return slots() + script->nfixed;
179 const js::Value &calleeValue() {
180 JS_ASSERT(argv);
181 return argv[-2];
184 JSObject *callee() {
185 return argv ? &argv[-2].toObject() : NULL;
189 * Get the object associated with the Execution Context's
190 * VariableEnvironment (ES5 10.3). The given CallStackSegment must contain
191 * this stack frame.
193 JSObject *varobj(js::CallStackSegment *css) const;
195 /* Short for: varobj(cx->activeCallStack()). */
196 JSObject *varobj(JSContext *cx) const;
198 inline JSObject *getThisObject(JSContext *cx);
200 bool isGenerator() const { return !!(flags & JSFRAME_GENERATOR); }
201 bool isFloatingGenerator() const {
202 JS_ASSERT_IF(flags & JSFRAME_FLOATING_GENERATOR, isGenerator());
203 return !!(flags & JSFRAME_FLOATING_GENERATOR);
206 bool isDummyFrame() const { return !script && !fun; }
209 namespace js {
211 JS_STATIC_ASSERT(sizeof(JSStackFrame) % sizeof(Value) == 0);
212 static const size_t VALUES_PER_STACK_FRAME = sizeof(JSStackFrame) / sizeof(Value);
214 JS_STATIC_ASSERT(offsetof(JSStackFrame, rval) % sizeof(Value) == 0);
215 JS_STATIC_ASSERT(offsetof(JSStackFrame, thisv) % sizeof(Value) == 0);
217 } /* namespace js */
219 static JS_INLINE uintN
220 GlobalVarCount(JSStackFrame *fp)
222 JS_ASSERT(!fp->fun);
223 return fp->script->nfixed;
227 * Refresh and return fp->scopeChain. It may be stale if block scopes are
228 * active but not yet reflected by objects in the scope chain. If a block
229 * scope contains a with, eval, XML filtering predicate, or similar such
230 * dynamically scoped construct, then compile-time block scope at fp->blocks
231 * must reflect at runtime.
233 extern JSObject *
234 js_GetScopeChain(JSContext *cx, JSStackFrame *fp);
237 * Given a context and a vector of [callee, this, args...] for a function that
238 * was specified with a JSFUN_THISP_PRIMITIVE flag, get the primitive value of
239 * |this| into *thisvp. In doing so, if |this| is an object, insist it is an
240 * instance of clasp and extract its private slot value to return via *thisvp.
242 * NB: this function loads and uses *vp before storing *thisvp, so the two may
243 * alias the same Value.
245 extern JSBool
246 js_GetPrimitiveThis(JSContext *cx, js::Value *vp, js::Class *clasp,
247 const js::Value **vpp);
249 namespace js {
252 * For a call with arguments argv including argv[-1] (nominal |this|) and
253 * argv[-2] (callee) replace null |this| with callee's parent, replace
254 * primitive values with the equivalent wrapper objects and censor activation
255 * objects as, per ECMA-262, they may not be referred to by |this|. argv[-1]
256 * must not be a JSVAL_VOID.
258 extern JSObject *
259 ComputeThisFromArgv(JSContext *cx, js::Value *argv);
261 JS_ALWAYS_INLINE JSObject *
262 ComputeThisFromVp(JSContext *cx, js::Value *vp)
264 return ComputeThisFromArgv(cx, vp + 2);
267 JS_ALWAYS_INLINE bool
268 PrimitiveThisTest(JSFunction *fun, const Value &v)
270 uint16 flags = fun->flags;
271 return (v.isString() && !!(flags & JSFUN_THISP_STRING)) ||
272 (v.isNumber() && !!(flags & JSFUN_THISP_NUMBER)) ||
273 (v.isBoolean() && !!(flags & JSFUN_THISP_BOOLEAN));
277 * The js::InvokeArgumentsGuard passed to js_Invoke must come from an
278 * immediately-enclosing successful call to js::StackSpace::pushInvokeArgs,
279 * i.e., there must have been no un-popped pushes to cx->stack(). Furthermore,
280 * |args.getvp()[0]| should be the callee, |args.getvp()[1]| should be |this|,
281 * and the range [args.getvp() + 2, args.getvp() + 2 + args.getArgc()) should
282 * be initialized actual arguments.
284 extern JS_REQUIRES_STACK bool
285 Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags);
287 extern JS_REQUIRES_STACK JS_FRIEND_API(bool)
288 InvokeFriendAPI(JSContext *cx, const InvokeArgsGuard &args, uintN flags);
291 * Consolidated js_Invoke flags simply rename certain JSFRAME_* flags, so that
292 * we can share bits stored in JSStackFrame.flags and passed to:
294 * js_Invoke
295 * js_InternalInvoke
296 * js_ValueToFunction
297 * js_ValueToFunctionObject
298 * js_ValueToCallableObject
299 * js_ReportIsNotFunction
301 * See jsfun.h for the latter four and flag renaming macros.
303 #define JSINVOKE_CONSTRUCT JSFRAME_CONSTRUCTING
306 * Mask to isolate construct and iterator flags for use with jsfun.h functions.
308 #define JSINVOKE_FUNFLAGS JSINVOKE_CONSTRUCT
311 * "Internal" calls may come from C or C++ code using a JSContext on which no
312 * JS is running (!cx->fp), so they may need to push a dummy JSStackFrame.
314 extern JSBool
315 InternalInvoke(JSContext *cx, const Value &thisv, const Value &fval, uintN flags,
316 uintN argc, Value *argv, Value *rval);
318 static JS_ALWAYS_INLINE bool
319 InternalCall(JSContext *cx, JSObject *obj, const Value &fval,
320 uintN argc, Value *argv, Value *rval)
322 return InternalInvoke(cx, ObjectOrNullValue(obj), fval, 0, argc, argv, rval);
325 static JS_ALWAYS_INLINE bool
326 InternalConstruct(JSContext *cx, JSObject *obj, const Value &fval,
327 uintN argc, Value *argv, Value *rval)
329 return InternalInvoke(cx, ObjectOrNullValue(obj), fval, JSINVOKE_CONSTRUCT, argc, argv, rval);
332 extern bool
333 InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, const Value &fval,
334 JSAccessMode mode, uintN argc, Value *argv, Value *rval);
336 extern JS_FORCES_STACK bool
337 Execute(JSContext *cx, JSObject *chain, JSScript *script,
338 JSStackFrame *down, uintN flags, Value *result);
340 extern JS_REQUIRES_STACK bool
341 InvokeConstructor(JSContext *cx, const InvokeArgsGuard &args);
343 extern JS_REQUIRES_STACK bool
344 Interpret(JSContext *cx);
346 #define JSPROP_INITIALIZER 0x100 /* NB: Not a valid property attribute. */
348 extern bool
349 CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs,
350 JSObject **objp, JSProperty **propp);
352 extern bool
353 StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval);
355 /* === except that NaN is the same as NaN and -0 is not the same as +0. */
356 extern bool
357 SameValue(const Value &v1, const Value &v2, JSContext *cx);
359 extern JSType
360 TypeOfValue(JSContext *cx, const Value &v);
362 inline bool
363 InstanceOf(JSContext *cx, JSObject *obj, Class *clasp, Value *argv)
365 if (obj && obj->getClass() == clasp)
366 return true;
367 extern bool InstanceOfSlow(JSContext *, JSObject *, Class *, Value *);
368 return InstanceOfSlow(cx, obj, clasp, argv);
371 extern JSBool
372 HasInstance(JSContext *cx, JSObject *obj, const js::Value *v, JSBool *bp);
374 inline void *
375 GetInstancePrivate(JSContext *cx, JSObject *obj, Class *clasp, Value *argv)
377 if (!InstanceOf(cx, obj, clasp, argv))
378 return NULL;
379 return obj->getPrivate();
382 extern bool
383 ValueToId(JSContext *cx, const Value &v, jsid *idp);
386 * @param closureLevel The static level of the closure that the cookie
387 * pertains to.
388 * @param cookie Level amount is a "skip" (delta) value from the
389 * closure level.
390 * @return The value of the upvar.
392 extern const js::Value &
393 GetUpvar(JSContext *cx, uintN level, js::UpvarCookie cookie);
395 } /* namespace js */
398 * JS_LONE_INTERPRET indicates that the compiler should see just the code for
399 * the js_Interpret function when compiling jsinterp.cpp. The rest of the code
400 * from the file should be visible only when compiling jsinvoke.cpp. It allows
401 * platform builds to optimize selectively js_Interpret when the granularity
402 * of the optimizations with the given compiler is a compilation unit.
404 * JS_STATIC_INTERPRET is the modifier for functions defined in jsinterp.cpp
405 * that only js_Interpret calls. When JS_LONE_INTERPRET is true all such
406 * functions are declared below.
408 #ifndef JS_LONE_INTERPRET
409 # ifdef _MSC_VER
410 # define JS_LONE_INTERPRET 0
411 # else
412 # define JS_LONE_INTERPRET 1
413 # endif
414 #endif
416 #define JS_MAX_INLINE_CALL_COUNT 3000
418 #if !JS_LONE_INTERPRET
419 # define JS_STATIC_INTERPRET static
420 #else
421 # define JS_STATIC_INTERPRET
423 extern JS_REQUIRES_STACK JSBool
424 js_EnterWith(JSContext *cx, jsint stackIndex);
426 extern JS_REQUIRES_STACK void
427 js_LeaveWith(JSContext *cx);
429 extern JS_REQUIRES_STACK js::Class *
430 js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth);
433 * Unwind block and scope chains to match the given depth. The function sets
434 * fp->sp on return to stackDepth.
436 extern JS_REQUIRES_STACK JSBool
437 js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind);
439 extern JSBool
440 js_OnUnknownMethod(JSContext *cx, js::Value *vp);
443 * Find the results of incrementing or decrementing *vp. For pre-increments,
444 * both *vp and *vp2 will contain the result on return. For post-increments,
445 * vp will contain the original value converted to a number and vp2 will get
446 * the result. Both vp and vp2 must be roots.
448 extern JSBool
449 js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, js::Value *vp, js::Value *vp2);
452 * Opcode tracing helper. When len is not 0, cx->fp->regs->pc[-len] gives the
453 * previous opcode.
455 extern JS_REQUIRES_STACK void
456 js_TraceOpcode(JSContext *cx);
459 * JS_OPMETER helper functions.
461 extern void
462 js_MeterOpcodePair(JSOp op1, JSOp op2);
464 extern void
465 js_MeterSlotOpcode(JSOp op, uint32 slot);
467 #endif /* JS_LONE_INTERPRET */
469 inline JSObject *
470 JSStackFrame::getThisObject(JSContext *cx)
472 if (flags & JSFRAME_COMPUTED_THIS)
473 return &thisv.toObject();
474 if (!js::ComputeThisFromArgv(cx, argv))
475 return NULL;
476 thisv = argv[-1];
477 flags |= JSFRAME_COMPUTED_THIS;
478 return &thisv.toObject();
481 #endif /* jsinterp_h___ */