1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is Mozilla Communicator client code, released
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1998
22 * the Initial Developer. All Rights Reserved.
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 /* build on macs with low memory */
41 #if defined(XP_MAC) && defined(MOZ_MAC_LOWMEM)
42 #pragma optimization_level 1
46 * JavaScript bytecode interpreter.
53 #include "jsarena.h" /* Added by JSIFY */
54 #include "jsutil.h" /* Added by JSIFY */
79 #define ASSERT_CACHE_IS_EMPTY(cache) \
81 JSPropertyCacheEntry *end_, *pce_, entry_; \
82 JSPropertyCache *cache_ = (cache); \
83 JS_ASSERT(cache_->empty); \
84 end_ = &cache_->table[PROPERTY_CACHE_SIZE]; \
85 for (pce_ = &cache_->table[0]; pce_ < end_; pce_++) { \
86 PCE_LOAD(cache_, pce_, entry_); \
87 JS_ASSERT(!PCE_OBJECT(entry_)); \
88 JS_ASSERT(!PCE_PROPERTY(entry_)); \
92 #define ASSERT_CACHE_IS_EMPTY(cache) ((void)0)
96 js_FlushPropertyCache(JSContext
*cx
)
98 JSPropertyCache
*cache
;
100 cache
= &cx
->runtime
->propertyCache
;
102 ASSERT_CACHE_IS_EMPTY(cache
);
105 memset(cache
->table
, 0, sizeof cache
->table
);
106 cache
->empty
= JS_TRUE
;
107 #ifdef JS_PROPERTY_CACHE_METERING
113 js_DisablePropertyCache(JSContext
*cx
)
115 JS_ASSERT(!cx
->runtime
->propertyCache
.disabled
);
116 cx
->runtime
->propertyCache
.disabled
= JS_TRUE
;
120 js_EnablePropertyCache(JSContext
*cx
)
122 JS_ASSERT(cx
->runtime
->propertyCache
.disabled
);
123 ASSERT_CACHE_IS_EMPTY(&cx
->runtime
->propertyCache
);
124 cx
->runtime
->propertyCache
.disabled
= JS_FALSE
;
128 * Class for for/in loop property iterator objects.
130 #define JSSLOT_ITER_STATE JSSLOT_PRIVATE
133 prop_iterator_finalize(JSContext
*cx
, JSObject
*obj
)
138 /* Protect against stillborn iterators. */
139 iter_state
= obj
->slots
[JSSLOT_ITER_STATE
];
140 iteratee
= obj
->slots
[JSSLOT_PARENT
];
141 if (!JSVAL_IS_NULL(iter_state
) && !JSVAL_IS_PRIMITIVE(iteratee
)) {
142 OBJ_ENUMERATE(cx
, JSVAL_TO_OBJECT(iteratee
), JSENUMERATE_DESTROY
,
145 js_RemoveRoot(cx
->runtime
, &obj
->slots
[JSSLOT_PARENT
]);
147 /* XXX force the GC to restart so we can collect iteratee, if possible,
148 during the current collector activation */
149 cx
->runtime
->gcLevel
++;
152 static JSClass prop_iterator_class
= {
155 JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
,
156 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, prop_iterator_finalize
,
157 JSCLASS_NO_OPTIONAL_MEMBERS
161 * Stack macros and functions. These all use a local variable, jsval *sp, to
162 * point to the next free stack slot. SAVE_SP must be called before any call
163 * to a function that may invoke the interpreter. RESTORE_SP must be called
164 * only after return from js_Invoke, because only js_Invoke changes fp->sp.
166 #define PUSH(v) (*sp++ = (v))
167 #define POP() (*--sp)
169 #define SAVE_SP(fp) \
170 (JS_ASSERT((fp)->script || !(fp)->spbase || (sp) == (fp)->spbase), \
173 #define SAVE_SP(fp) ((fp)->sp = sp)
175 #define RESTORE_SP(fp) (sp = (fp)->sp)
178 * Push the generating bytecode's pc onto the parallel pc stack that runs
179 * depth slots below the operands.
181 * NB: PUSH_OPND uses sp, depth, and pc from its lexical environment. See
182 * js_Interpret for these local variables' declarations and uses.
184 #define PUSH_OPND(v) (sp[-depth] = (jsval)pc, PUSH(v))
185 #define STORE_OPND(n,v) (sp[(n)-depth] = (jsval)pc, sp[n] = (v))
186 #define POP_OPND() POP()
187 #define FETCH_OPND(n) (sp[n])
190 * Push the jsdouble d using sp, depth, and pc from the lexical environment.
191 * Try to convert d to a jsint that fits in a jsval, otherwise GC-alloc space
192 * for it and push a reference.
194 #define STORE_NUMBER(cx, n, d) \
199 if (JSDOUBLE_IS_INT(d, i_) && INT_FITS_IN_JSVAL(i_)) { \
200 v_ = INT_TO_JSVAL(i_); \
202 ok = js_NewDoubleValue(cx, d, &v_); \
209 #define FETCH_NUMBER(cx, n, d) \
213 v_ = FETCH_OPND(n); \
214 VALUE_TO_NUMBER(cx, v_, d); \
217 #define FETCH_INT(cx, n, i) \
219 jsval v_ = FETCH_OPND(n); \
220 if (JSVAL_IS_INT(v_)) { \
221 i = JSVAL_TO_INT(v_); \
224 ok = js_ValueToECMAInt32(cx, v_, &i); \
230 #define FETCH_UINT(cx, n, ui) \
232 jsval v_ = FETCH_OPND(n); \
234 if (JSVAL_IS_INT(v_) && (i_ = JSVAL_TO_INT(v_)) >= 0) { \
238 ok = js_ValueToECMAUint32(cx, v_, &ui); \
245 * Optimized conversion macros that test for the desired type in v before
246 * homing sp and calling a conversion function.
248 #define VALUE_TO_NUMBER(cx, v, d) \
250 if (JSVAL_IS_INT(v)) { \
251 d = (jsdouble)JSVAL_TO_INT(v); \
252 } else if (JSVAL_IS_DOUBLE(v)) { \
253 d = *JSVAL_TO_DOUBLE(v); \
256 ok = js_ValueToNumber(cx, v, &d); \
262 #define POP_BOOLEAN(cx, v, b) \
264 v = FETCH_OPND(-1); \
265 if (v == JSVAL_NULL) { \
267 } else if (JSVAL_IS_BOOLEAN(v)) { \
268 b = JSVAL_TO_BOOLEAN(v); \
271 ok = js_ValueToBoolean(cx, v, &b); \
278 #define VALUE_TO_OBJECT(cx, v, obj) \
280 if (JSVAL_IS_OBJECT(v) && v != JSVAL_NULL) { \
281 obj = JSVAL_TO_OBJECT(v); \
284 obj = js_ValueToNonNullObject(cx, v); \
292 #if JS_BUG_VOID_TOSTRING
293 #define CHECK_VOID_TOSTRING(cx, v) \
294 if (JSVAL_IS_VOID(v)) { \
296 str_ = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); \
297 v = STRING_TO_JSVAL(str_); \
300 #define CHECK_VOID_TOSTRING(cx, v) ((void)0)
303 #if JS_BUG_EAGER_TOSTRING
304 #define CHECK_EAGER_TOSTRING(hint) (hint = JSTYPE_STRING)
306 #define CHECK_EAGER_TOSTRING(hint) ((void)0)
309 #define VALUE_TO_PRIMITIVE(cx, v, hint, vp) \
311 if (JSVAL_IS_PRIMITIVE(v)) { \
312 CHECK_VOID_TOSTRING(cx, v); \
316 CHECK_EAGER_TOSTRING(hint); \
317 ok = OBJ_DEFAULT_VALUE(cx, JSVAL_TO_OBJECT(v), hint, vp); \
323 JS_FRIEND_API(jsval
*)
324 js_AllocRawStack(JSContext
*cx
, uintN nslots
, void **markp
)
329 *markp
= JS_ARENA_MARK(&cx
->stackPool
);
330 JS_ARENA_ALLOCATE_CAST(sp
, jsval
*, &cx
->stackPool
, nslots
* sizeof(jsval
));
332 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_STACK_OVERFLOW
,
333 (cx
->fp
&& cx
->fp
->fun
)
334 ? JS_GetFunctionName(cx
->fp
->fun
)
341 js_FreeRawStack(JSContext
*cx
, void *mark
)
343 JS_ARENA_RELEASE(&cx
->stackPool
, mark
);
346 JS_FRIEND_API(jsval
*)
347 js_AllocStack(JSContext
*cx
, uintN nslots
, void **markp
)
349 jsval
*sp
, *vp
, *end
;
354 /* Callers don't check for zero nslots: we do to avoid empty segments. */
357 return JS_ARENA_MARK(&cx
->stackPool
);
360 /* Allocate 2 extra slots for the stack segment header we'll likely need. */
361 sp
= js_AllocRawStack(cx
, 2 + nslots
, markp
);
365 /* Try to avoid another header if we can piggyback on the last segment. */
366 a
= cx
->stackPool
.current
;
367 sh
= cx
->stackHeaders
;
368 if (sh
&& JS_STACK_SEGMENT(sh
) + sh
->nslots
== sp
) {
369 /* Extend the last stack segment, give back the 2 header slots. */
370 sh
->nslots
+= nslots
;
371 a
->avail
-= 2 * sizeof(jsval
);
374 * Need a new stack segment, so we must initialize unused slots in the
375 * current frame. See js_GC, just before marking the "operand" jsvals,
376 * where we scan from fp->spbase to fp->sp or through fp->script->depth
377 * (whichever covers fewer slots).
380 if (fp
&& fp
->script
&& fp
->spbase
) {
382 jsuword depthdiff
= fp
->script
->depth
* sizeof(jsval
);
383 JS_ASSERT(JS_UPTRDIFF(fp
->sp
, fp
->spbase
) <= depthdiff
);
384 JS_ASSERT(JS_UPTRDIFF(*markp
, fp
->spbase
) >= depthdiff
);
386 end
= fp
->spbase
+ fp
->script
->depth
;
387 for (vp
= fp
->sp
; vp
< end
; vp
++)
391 /* Allocate and push a stack segment header from the 2 extra slots. */
392 sh
= (JSStackHeader
*)sp
;
394 sh
->down
= cx
->stackHeaders
;
395 cx
->stackHeaders
= sh
;
403 js_FreeStack(JSContext
*cx
, void *mark
)
408 /* Check for zero nslots allocation special case. */
412 /* We can assert because js_FreeStack always balances js_AllocStack. */
413 sh
= cx
->stackHeaders
;
416 /* If mark is in the current segment, reduce sh->nslots, else pop sh. */
417 slotdiff
= JS_UPTRDIFF(mark
, JS_STACK_SEGMENT(sh
)) / sizeof(jsval
);
418 if (slotdiff
< (jsuword
)sh
->nslots
)
419 sh
->nslots
= slotdiff
;
421 cx
->stackHeaders
= sh
->down
;
423 /* Release the stackPool space allocated since mark was set. */
424 JS_ARENA_RELEASE(&cx
->stackPool
, mark
);
428 * To economize on slots space in functions, the compiler records arguments and
429 * local variables as shared (JSPROP_SHARED) properties with well-known getters
430 * and setters: js_{Get,Set}Argument, js_{Get,Set}LocalVariable. Now, we could
431 * record args and vars in lists or hash tables in function-private data, but
432 * that means more duplication in code, and more data at runtime in the hash
433 * table case due to round-up to powers of two, just to recapitulate the scope
434 * machinery in the function object.
436 * What's more, for a long time (to the dawn of "Mocha" in 1995), these getters
437 * and setters knew how to search active stack frames in a context to find the
438 * top activation of the function f, in order to satisfy a get or set of f.a,
439 * for argument a, or f.x, for local variable x. You could use f.a instead of
440 * just a in function f(a) { return f.a }, for example, to return the actual
443 * ECMA requires that we give up on this ancient extension, because it is not
444 * compatible with the standard as used by real-world scripts. While Chapter
445 * 16 does allow for additional properties to be defined on native objects by
446 * a conforming implementation, these magic getters and setters cause f.a's
447 * meaning to vary unexpectedly. Real-world scripts set f.A = 42 to define
448 * "class static" (after Java) constants, for example, but if A also names an
449 * arg or var in f, the constant is not available while f is active, and any
450 * non-constant class-static can't be set while f is active.
452 * So, to label arg and var properties in functions without giving them magic
453 * abilities to affect active frame stack slots, while keeping the properties
454 * shared (slot-less) to save space in the common case (where no assignment
455 * sets a function property with the same name as an arg or var), the setters
456 * for args and vars must handle two special cases here.
458 * XXX functions tend to have few args and vars, so we risk O(n^2) growth here
459 * XXX ECMA *really* wants args and vars to be stored in function-private data,
460 * not as function object properties.
463 SetFunctionSlot(JSContext
*cx
, JSObject
*obj
, JSPropertyOp setter
, jsid id
,
469 JSScopeProperty
*sprop
;
473 slot
= (uintN
) JSVAL_TO_INT(id
);
474 if (OBJ_GET_CLASS(cx
, obj
) != &js_FunctionClass
) {
476 * Given a non-function object obj that has a function object in its
477 * prototype chain, where an argument or local variable property named
478 * by (setter, slot) is being set, override the shared property in the
479 * prototype with an unshared property in obj. This situation arises
480 * in real-world JS due to .prototype setting and collisions among a
481 * function's "static property" names and arg or var names, believe it
486 obj
= OBJ_GET_PROTO(cx
, obj
);
489 } while (OBJ_GET_CLASS(cx
, obj
) != &js_FunctionClass
);
491 JS_LOCK_OBJ(cx
, obj
);
492 scope
= OBJ_SCOPE(obj
);
493 for (sprop
= SCOPE_LAST_PROP(scope
); sprop
; sprop
= sprop
->parent
) {
494 if (sprop
->setter
== setter
) {
495 JS_ASSERT(!JSVAL_IS_INT(sprop
->id
) &&
496 ATOM_IS_STRING((JSAtom
*)sprop
->id
) &&
497 (sprop
->flags
& SPROP_HAS_SHORTID
));
499 if ((uintN
) sprop
->shortid
== slot
) {
500 str
= ATOM_TO_STRING((JSAtom
*)sprop
->id
);
501 JS_UNLOCK_SCOPE(cx
, scope
);
503 return JS_DefineUCProperty(cx
, origobj
,
505 JSSTRING_LENGTH(str
),
511 JS_UNLOCK_SCOPE(cx
, scope
);
516 * Argument and local variable properties of function objects are shared
517 * by default (JSPROP_SHARED), therefore slot-less. But if for function
518 * f(a) {}, f.a = 42 is evaluated, f.a should be 42 after the assignment,
519 * whether or not f is active. So js_SetArgument and js_SetLocalVariable
520 * must be prepared to change an arg or var from shared to unshared status,
521 * allocating a slot in obj to hold v.
524 JS_LOCK_OBJ(cx
, obj
);
525 scope
= OBJ_SCOPE(obj
);
526 for (sprop
= SCOPE_LAST_PROP(scope
); sprop
; sprop
= sprop
->parent
) {
527 if (sprop
->setter
== setter
&& (uintN
) sprop
->shortid
== slot
) {
528 if (sprop
->attrs
& JSPROP_SHARED
) {
529 sprop
= js_ChangeScopePropertyAttrs(cx
, scope
, sprop
,
531 sprop
->getter
, setter
);
535 /* See js_SetProperty, near the bottom. */
537 LOCKED_OBJ_SET_SLOT(obj
, sprop
->slot
, v
);
543 JS_UNLOCK_SCOPE(cx
, scope
);
548 js_GetArgument(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
554 js_SetArgument(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
556 return SetFunctionSlot(cx
, obj
, js_SetArgument
, id
, *vp
);
560 js_GetLocalVariable(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
566 js_SetLocalVariable(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
568 return SetFunctionSlot(cx
, obj
, js_SetLocalVariable
, id
, *vp
);
572 * Compute the 'this' parameter and store it in frame as frame.thisp.
573 * Activation objects ("Call" objects not created with "new Call()", i.e.,
574 * "Call" objects that have private data) may not be referred to by 'this',
575 * as dictated by ECMA.
577 * N.B.: fp->argv must be set, fp->argv[-1] the nominal 'this' paramter as
578 * a jsval, and fp->argv[-2] must be the callee object reference, usually a
579 * function object. Also, fp->flags must contain JSFRAME_CONSTRUCTING if we
580 * are preparing for a constructor call.
583 ComputeThis(JSContext
*cx
, JSObject
*thisp
, JSStackFrame
*fp
)
587 if (thisp
&& OBJ_GET_CLASS(cx
, thisp
) != &js_CallClass
) {
588 /* Some objects (e.g., With) delegate 'this' to another object. */
589 thisp
= OBJ_THIS_OBJECT(cx
, thisp
);
593 /* Default return value for a constructor is the new object. */
594 if (fp
->flags
& JSFRAME_CONSTRUCTING
)
595 fp
->rval
= OBJECT_TO_JSVAL(thisp
);
598 * ECMA requires "the global object", but in the presence of multiple
599 * top-level objects (windows, frames, or certain layers in the client
600 * object model), we prefer fun's parent. An example that causes this
604 * function f() { return this }
605 * function g() { return f }
611 * The alert should display "true".
613 JS_ASSERT(!(fp
->flags
& JSFRAME_CONSTRUCTING
));
614 if (JSVAL_IS_PRIMITIVE(fp
->argv
[-2]) ||
615 !(parent
= OBJ_GET_PARENT(cx
, JSVAL_TO_OBJECT(fp
->argv
[-2])))) {
616 thisp
= cx
->globalObject
;
618 /* walk up to find the top-level object */
620 while ((parent
= OBJ_GET_PARENT(cx
, thisp
)) != NULL
)
625 fp
->argv
[-1] = OBJECT_TO_JSVAL(thisp
);
630 * Find a function reference and its 'this' object implicit first parameter
631 * under argc arguments on cx's stack, and call the function. Push missing
632 * required arguments, allocate declared local variables, and pop everything
633 * when done. Then push the return value.
635 JS_FRIEND_API(JSBool
)
636 js_Invoke(JSContext
*cx
, uintN argc
, uintN flags
)
639 JSStackFrame
*fp
, frame
;
640 jsval
*sp
, *newsp
, *limit
;
642 JSObject
*funobj
, *parent
, *thisp
;
649 uintN minargs
, nvars
;
650 intN nslots
, nalloc
, surplus
;
651 JSInterpreterHook hook
;
654 /* Mark the top of stack and load frequently-used registers. */
655 mark
= JS_ARENA_MARK(&cx
->stackPool
);
660 * Set vp to the callee value's stack slot (it's where rval goes).
661 * Once vp is set, control should flow through label out2: to return.
662 * Set frame.rval early so native class and object ops can throw and
663 * return false, causing a goto out2 with ok set to false. Also set
664 * frame.flags to flags so that ComputeThis can test bits in it.
666 vp
= sp
- (2 + argc
);
668 frame
.rval
= JSVAL_VOID
;
670 thisp
= JSVAL_TO_OBJECT(vp
[1]);
673 * A callee must be an object reference, unless its |this| parameter
674 * implements the __noSuchMethod__ method, in which case that method will
677 * thisp.__noSuchMethod__(id, args)
679 * where id is the name of the method that this invocation attempted to
680 * call by name, and args is an Array containing this invocation's actual
683 if (JSVAL_IS_PRIMITIVE(v
)) {
684 #if JS_HAS_NO_SUCH_METHOD
691 if (!fp
->script
|| (flags
& JSINVOKE_INTERNAL
))
695 * We must ComputeThis here to censor Call objects; performance hit,
696 * but at least it's idempotent.
698 * Normally, we call ComputeThis after all frame members have been
699 * set, and in particular, after any revision of the callee value at
700 * *vp due to clasp->convert (see below). This matters because
701 * ComputeThis may access *vp via fp->argv[-2], to follow the parent
702 * chain to a global object to use as the |this| parameter.
704 * Obviously, here in the JSVAL_IS_PRIMITIVE(v) case, there can't be
705 * any such defaulting of |this| to callee (v, *vp) ancestor.
708 ok
= ComputeThis(cx
, thisp
, &frame
);
713 ok
= OBJ_GET_PROPERTY(cx
, thisp
,
714 (jsid
)cx
->runtime
->atomState
.noSuchMethodAtom
,
718 if (JSVAL_IS_PRIMITIVE(v
))
721 pc
= (jsbytecode
*) vp
[-(intN
)fp
->script
->depth
];
722 switch ((JSOp
) *pc
) {
725 atomIndex
= GET_ATOM_INDEX(pc
);
726 atom
= js_GetAtom(cx
, &fp
->script
->atomMap
, atomIndex
);
727 argsobj
= js_NewArrayObject(cx
, argc
, vp
+ 2);
735 a
= cx
->stackPool
.current
;
736 if ((jsuword
)sp
> a
->limit
) {
738 * Arguments must be contiguous, and must include argv[-1]
739 * and argv[-2], so allocate more stack, advance sp, and
740 * set newsp[1] to thisp (vp[1]). The other argv elements
741 * will be set below, using negative indexing from sp.
743 newsp
= js_AllocRawStack(cx
, 4, NULL
);
748 newsp
[1] = OBJECT_TO_JSVAL(thisp
);
750 } else if ((jsuword
)sp
> a
->avail
) {
752 * Inline, optimized version of JS_ARENA_ALLOCATE to claim
753 * the small number of words not already allocated as part
754 * of the caller's operand stack.
756 JS_ArenaCountAllocation(pool
, (jsuword
)sp
- a
->avail
);
757 a
->avail
= (jsuword
)sp
;
762 JS_ASSERT(sp
[-3] == OBJECT_TO_JSVAL(thisp
));
763 sp
[-2] = ATOM_KEY(atom
);
764 sp
[-1] = OBJECT_TO_JSVAL(argsobj
);
777 funobj
= JSVAL_TO_OBJECT(v
);
778 parent
= OBJ_GET_PARENT(cx
, funobj
);
779 clasp
= OBJ_GET_CLASS(cx
, funobj
);
780 if (clasp
!= &js_FunctionClass
) {
781 /* Function is inlined, all other classes use object ops. */
782 ops
= funobj
->map
->ops
;
786 * Try converting to function, for closure and API compatibility.
787 * We attempt the conversion under all circumstances for 1.2, but
788 * only if there is a call op defined otherwise.
790 if (cx
->version
== JSVERSION_1_2
||
791 ((ops
== &js_ObjectOps
) ? clasp
->call
: ops
->call
)) {
792 ok
= clasp
->convert(cx
, funobj
, JSTYPE_FUNCTION
, &v
);
796 if (JSVAL_IS_FUNCTION(cx
, v
)) {
797 /* Make vp refer to funobj to keep it available as argv[-2]. */
799 funobj
= JSVAL_TO_OBJECT(v
);
800 parent
= OBJ_GET_PARENT(cx
, funobj
);
808 /* Try a call or construct native object op. */
809 native
= (flags
& JSINVOKE_CONSTRUCT
) ? ops
->construct
: ops
->call
;
814 /* Get private data and set derived locals from it. */
815 fun
= (JSFunction
*) JS_GetPrivate(cx
, funobj
);
816 native
= fun
->native
;
817 script
= fun
->script
;
818 minargs
= fun
->nargs
+ fun
->extra
;
821 /* Handle bound method special case. */
822 if (fun
->flags
& JSFUN_BOUND_METHOD
)
826 /* Initialize the rest of frame, except for sp (set by SAVE_SP later). */
828 frame
.callobj
= frame
.argsobj
= NULL
;
829 frame
.script
= script
;
832 frame
.argv
= sp
- argc
;
836 frame
.annotation
= NULL
;
837 frame
.scopeChain
= NULL
; /* set below for real, after cx->fp is set */
840 frame
.sharpDepth
= 0;
841 frame
.sharpArray
= NULL
;
842 frame
.dormantNext
= NULL
;
843 frame
.objAtomMap
= NULL
;
845 /* Compute the 'this' parameter and store it in frame as frame.thisp. */
846 ok
= ComputeThis(cx
, thisp
, &frame
);
850 /* From here on, control must flow through label out: to return. */
853 /* Init these now in case we goto out before first hook call. */
854 hook
= cx
->runtime
->callHook
;
857 /* Check for missing arguments expected by the function. */
858 nslots
= (intN
)((argc
< minargs
) ? minargs
- argc
: 0);
860 /* All arguments must be contiguous, so we may have to copy actuals. */
862 limit
= (jsval
*) cx
->stackPool
.current
->limit
;
863 if (sp
+ nslots
> limit
) {
864 /* Hit end of arena: we have to copy argv[-2..(argc+nslots-1)]. */
867 /* Take advantage of surplus slots in the caller's frame depth. */
868 surplus
= (jsval
*)mark
- sp
;
869 JS_ASSERT(surplus
>= 0);
873 /* Check whether we have enough space in the caller's frame. */
875 /* Need space for actuals plus missing formals minus surplus. */
876 newsp
= js_AllocRawStack(cx
, (uintN
)nalloc
, NULL
);
882 /* If we couldn't allocate contiguous args, copy actuals now. */
884 JS_ASSERT(sp
+ nslots
> limit
);
885 JS_ASSERT(2 + argc
+ nslots
== (uintN
)nalloc
);
889 memcpy(newsp
, frame
.argv
, argc
* sizeof(jsval
));
891 sp
= frame
.vars
= newsp
+ argc
;
895 /* Advance frame.vars to make room for the missing args. */
896 frame
.vars
+= nslots
;
898 /* Push void to initialize missing args. */
899 while (--nslots
>= 0)
903 /* Now allocate stack space for local variables. */
904 nslots
= (intN
)frame
.nvars
;
906 surplus
= (intN
)((jsval
*)cx
->stackPool
.current
->avail
- frame
.vars
);
907 if (surplus
< nslots
) {
908 newsp
= js_AllocRawStack(cx
, (uintN
)nslots
, NULL
);
914 /* NB: Discontinuity between argv and vars. */
915 sp
= frame
.vars
= newsp
;
919 /* Push void to initialize local variables. */
920 while (--nslots
>= 0)
924 /* Store the current sp in frame before calling fun. */
927 /* call the hook if present */
928 if (hook
&& (native
|| script
))
929 hookData
= hook(cx
, &frame
, JS_TRUE
, 0, cx
->runtime
->callHookData
);
931 /* Call the function, either a native method or an interpreted script. */
933 #if JS_HAS_LVALUE_RETURN
934 /* Set by JS_SetCallReturnValue2, used to return reference types. */
935 cx
->rval2set
= JS_FALSE
;
938 /* If native, use caller varobj and scopeChain for eval. */
939 frame
.varobj
= fp
->varobj
;
940 frame
.scopeChain
= fp
->scopeChain
;
941 ok
= native(cx
, frame
.thisp
, argc
, frame
.argv
, &frame
.rval
);
942 JS_RUNTIME_METER(cx
->runtime
, nativeCalls
);
944 /* Use parent scope so js_GetCallObject can find the right "Call". */
945 frame
.scopeChain
= parent
;
946 if (fun
->flags
& JSFUN_HEAVYWEIGHT
) {
947 #if JS_HAS_CALL_OBJECT
948 /* Scope with a call object parented by the callee's parent. */
949 if (!js_GetCallObject(cx
, &frame
, parent
)) {
954 /* Bad old code used the function as a proxy for all calls to it. */
955 frame
.scopeChain
= funobj
;
958 ok
= js_Interpret(cx
, &v
);
960 /* fun might be onerror trying to report a syntax error in itself. */
961 frame
.scopeChain
= NULL
;
967 hook
= cx
->runtime
->callHook
;
969 hook(cx
, &frame
, JS_FALSE
, &ok
, hookData
);
971 #if JS_HAS_CALL_OBJECT
972 /* If frame has a call object, sync values and clear back-pointer. */
974 ok
&= js_PutCallObject(cx
, &frame
);
976 #if JS_HAS_ARGS_OBJECT
977 /* If frame has an arguments object, sync values and clear back-pointer. */
979 ok
&= js_PutArgsObject(cx
, &frame
);
982 /* Restore cx->fp now that we're done releasing frame objects. */
986 /* Pop everything we may have allocated off the stack. */
987 JS_ARENA_RELEASE(&cx
->stackPool
, mark
);
989 /* Store the return value and restore sp just above it. */
994 * Store the location of the JSOP_CALL or JSOP_EVAL that generated the
995 * return value, but only if this is an external (compiled from script
996 * source) call that has stack budget for the generating pc.
998 if (fp
->script
&& !(flags
& JSINVOKE_INTERNAL
))
999 vp
[-(intN
)fp
->script
->depth
] = (jsval
)fp
->pc
;
1003 js_ReportIsNotFunction(cx
, vp
, flags
& JSINVOKE_CONSTRUCT
);
1009 js_InternalInvoke(JSContext
*cx
, JSObject
*obj
, jsval fval
, uintN flags
,
1010 uintN argc
, jsval
*argv
, jsval
*rval
)
1012 JSStackFrame
*fp
, *oldfp
, frame
;
1018 fp
= oldfp
= cx
->fp
;
1020 memset(&frame
, 0, sizeof frame
);
1021 cx
->fp
= fp
= &frame
;
1024 sp
= js_AllocStack(cx
, 2 + argc
, &mark
);
1031 PUSH(OBJECT_TO_JSVAL(obj
));
1032 for (i
= 0; i
< argc
; i
++)
1035 ok
= js_Invoke(cx
, argc
, flags
| JSINVOKE_INTERNAL
);
1041 js_FreeStack(cx
, mark
);
1051 js_InternalGetOrSet(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval fval
,
1052 JSAccessMode mode
, uintN argc
, jsval
*argv
, jsval
*rval
)
1055 * Check general (not object-ops/class-specific) access from the running
1056 * script to obj.id only if id has a scripted getter or setter that we're
1057 * about to invoke. If we don't check this case, nothing else will -- no
1058 * other native code has the chance to check.
1060 * Contrast this non-native (scripted) case with native getter and setter
1061 * accesses, where the native itself must do an access check, if security
1062 * policies requires it. We make a checkAccess or checkObjectAccess call
1063 * back to the embedding program only in those cases where we're not going
1064 * to call an embedding-defined native function, getter, setter, or class
1065 * hook anyway. Where we do call such a native, there's no need for the
1066 * engine to impose a separate access check callback on all embeddings --
1067 * many embeddings have no security policy at all.
1069 JS_ASSERT(mode
== JSACC_READ
|| mode
== JSACC_WRITE
);
1070 if (cx
->runtime
->checkObjectAccess
&&
1071 JSVAL_IS_FUNCTION(cx
, fval
) &&
1072 ((JSFunction
*) JS_GetPrivate(cx
, JSVAL_TO_OBJECT(fval
)))->script
&&
1073 !cx
->runtime
->checkObjectAccess(cx
, obj
, ID_TO_VALUE(id
), mode
,
1078 return js_InternalCall(cx
, obj
, fval
, argc
, argv
, rval
);
1082 js_Execute(JSContext
*cx
, JSObject
*chain
, JSScript
*script
,
1083 JSStackFrame
*down
, uintN special
, jsval
*result
)
1085 JSStackFrame
*oldfp
, frame
;
1086 JSObject
*obj
, *tmp
;
1088 JSInterpreterHook hook
;
1091 hook
= cx
->runtime
->executeHook
;
1094 frame
.callobj
= frame
.argsobj
= NULL
;
1095 frame
.script
= script
;
1097 /* Propagate arg/var state for eval and the debugger API. */
1098 frame
.varobj
= down
->varobj
;
1099 frame
.fun
= down
->fun
;
1100 frame
.thisp
= down
->thisp
;
1101 frame
.argc
= down
->argc
;
1102 frame
.argv
= down
->argv
;
1103 frame
.nvars
= down
->nvars
;
1104 frame
.vars
= down
->vars
;
1105 frame
.annotation
= down
->annotation
;
1106 frame
.sharpArray
= down
->sharpArray
;
1109 if (cx
->options
& JSOPTION_VAROBJFIX
) {
1110 while ((tmp
= OBJ_GET_PARENT(cx
, obj
)) != NULL
)
1115 frame
.thisp
= chain
;
1116 frame
.argc
= frame
.nvars
= 0;
1117 frame
.argv
= frame
.vars
= NULL
;
1118 frame
.annotation
= NULL
;
1119 frame
.sharpArray
= NULL
;
1121 frame
.rval
= JSVAL_VOID
;
1123 frame
.scopeChain
= chain
;
1125 frame
.sp
= oldfp
? oldfp
->sp
: NULL
;
1126 frame
.spbase
= NULL
;
1127 frame
.sharpDepth
= 0;
1128 frame
.flags
= special
;
1129 frame
.dormantNext
= NULL
;
1130 frame
.objAtomMap
= NULL
;
1133 * Here we wrap the call to js_Interpret with code to (conditionally)
1134 * save and restore the old stack frame chain into a chain of 'dormant'
1135 * frame chains. Since we are replacing cx->fp, we were running into
1136 * the problem that if GC was called under this frame, some of the GC
1137 * things associated with the old frame chain (available here only in
1138 * the C variable 'oldfp') were not rooted and were being collected.
1140 * So, now we preserve the links to these 'dormant' frame chains in cx
1141 * before calling js_Interpret and cleanup afterwards. The GC walks
1142 * these dormant chains and marks objects in the same way that it marks
1143 * objects in the primary cx->fp chain.
1145 if (oldfp
&& oldfp
!= down
) {
1146 JS_ASSERT(!oldfp
->dormantNext
);
1147 oldfp
->dormantNext
= cx
->dormantFrameChain
;
1148 cx
->dormantFrameChain
= oldfp
;
1153 hookData
= hook(cx
, &frame
, JS_TRUE
, 0, cx
->runtime
->executeHookData
);
1156 * Use frame.rval, not result, so the last result stays rooted across any
1157 * GC activations nested within this js_Interpret.
1159 ok
= js_Interpret(cx
, &frame
.rval
);
1160 *result
= frame
.rval
;
1163 hook
= cx
->runtime
->executeHook
;
1165 hook(cx
, &frame
, JS_FALSE
, &ok
, hookData
);
1169 if (oldfp
&& oldfp
!= down
) {
1170 JS_ASSERT(cx
->dormantFrameChain
== oldfp
);
1171 cx
->dormantFrameChain
= oldfp
->dormantNext
;
1172 oldfp
->dormantNext
= NULL
;
1178 #if JS_HAS_EXPORT_IMPORT
1180 * If id is JSVAL_VOID, import all exported properties from obj.
1183 ImportProperty(JSContext
*cx
, JSObject
*obj
, jsid id
)
1188 JSObject
*obj2
, *target
, *funobj
, *closure
;
1194 if (JSVAL_IS_VOID(id
)) {
1195 ida
= JS_Enumerate(cx
, obj
);
1199 if (ida
->length
== 0)
1203 if (!OBJ_LOOKUP_PROPERTY(cx
, obj
, id
, &obj2
, &prop
))
1206 str
= js_DecompileValueGenerator(cx
, JSDVG_IGNORE_STACK
,
1207 ID_TO_VALUE(id
), NULL
);
1209 js_ReportIsNotDefined(cx
, JS_GetStringBytes(str
));
1212 ok
= OBJ_GET_ATTRIBUTES(cx
, obj
, id
, prop
, &attrs
);
1213 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
1216 if (!(attrs
& JSPROP_EXPORTED
)) {
1217 str
= js_DecompileValueGenerator(cx
, JSDVG_IGNORE_STACK
,
1218 ID_TO_VALUE(id
), NULL
);
1220 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1222 JS_GetStringBytes(str
));
1228 target
= cx
->fp
->varobj
;
1232 id
= ida
->vector
[i
];
1233 ok
= OBJ_GET_ATTRIBUTES(cx
, obj
, id
, NULL
, &attrs
);
1236 if (!(attrs
& JSPROP_EXPORTED
))
1239 ok
= OBJ_CHECK_ACCESS(cx
, obj
, id
, JSACC_IMPORT
, &value
, &attrs
);
1242 if (JSVAL_IS_FUNCTION(cx
, value
)) {
1243 funobj
= JSVAL_TO_OBJECT(value
);
1244 closure
= js_CloneFunctionObject(cx
, funobj
, obj
);
1249 value
= OBJECT_TO_JSVAL(closure
);
1253 * Handle the case of importing a property that refers to a local
1254 * variable or formal parameter of a function activation. These
1255 * properties are accessed by opcodes using stack slot numbers
1256 * generated by the compiler rather than runtime name-lookup. These
1257 * local references, therefore, bypass the normal scope chain lookup.
1258 * So, instead of defining a new property in the activation object,
1259 * modify the existing value in the stack slot.
1261 if (OBJ_GET_CLASS(cx
, target
) == &js_CallClass
) {
1262 ok
= OBJ_LOOKUP_PROPERTY(cx
, target
, id
, &obj2
, &prop
);
1268 if (prop
&& target
== obj2
) {
1269 ok
= OBJ_SET_PROPERTY(cx
, target
, id
, &value
);
1271 ok
= OBJ_DEFINE_PROPERTY(cx
, target
, id
, value
, NULL
, NULL
,
1272 attrs
& ~JSPROP_EXPORTED
,
1276 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
1279 } while (ida
&& ++i
< ida
->length
);
1283 JS_DestroyIdArray(cx
, ida
);
1286 #endif /* JS_HAS_EXPORT_IMPORT */
1289 js_CheckRedeclaration(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN attrs
,
1295 uintN oldAttrs
, report
;
1298 const char *type
, *name
;
1300 if (!OBJ_LOOKUP_PROPERTY(cx
, obj
, id
, &obj2
, &prop
))
1302 *foundp
= (prop
!= NULL
);
1305 ok
= OBJ_GET_ATTRIBUTES(cx
, obj2
, id
, prop
, &oldAttrs
);
1306 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
1310 /* If either property is readonly, we have an error. */
1311 report
= ((oldAttrs
| attrs
) & JSPROP_READONLY
)
1313 : JSREPORT_WARNING
| JSREPORT_STRICT
;
1315 if (report
!= JSREPORT_ERROR
) {
1317 * Allow redeclaration of variables and functions, but insist that the
1318 * new value is not a getter if the old value was, ditto for setters --
1319 * unless prop is impermanent (in which case anyone could delete it and
1320 * redefine it, willy-nilly).
1322 if (!(attrs
& (JSPROP_GETTER
| JSPROP_SETTER
)))
1324 if ((~(oldAttrs
^ attrs
) & (JSPROP_GETTER
| JSPROP_SETTER
)) == 0)
1326 if (!(oldAttrs
& JSPROP_PERMANENT
))
1328 report
= JSREPORT_ERROR
;
1331 isFunction
= (oldAttrs
& (JSPROP_GETTER
| JSPROP_SETTER
)) != 0;
1333 if (!OBJ_GET_PROPERTY(cx
, obj
, id
, &value
))
1335 isFunction
= JSVAL_IS_FUNCTION(cx
, value
);
1337 type
= (oldAttrs
& attrs
& JSPROP_GETTER
)
1339 : (oldAttrs
& attrs
& JSPROP_SETTER
)
1341 : (oldAttrs
& JSPROP_READONLY
)
1346 name
= js_AtomToPrintableString(cx
, (JSAtom
*)id
);
1349 return JS_ReportErrorFlagsAndNumber(cx
, report
,
1350 js_GetErrorMessage
, NULL
,
1351 JSMSG_REDECLARED_VAR
,
1355 #ifndef MAX_INTERP_LEVEL
1357 #define MAX_INTERP_LEVEL 250
1358 #elif defined _MSC_VER && _MSC_VER <= 800
1359 #define MAX_INTERP_LEVEL 30
1361 #define MAX_INTERP_LEVEL 1000
1365 #define MAX_INLINE_CALL_COUNT 1000
1368 js_Interpret(JSContext
*cx
, jsval
*result
)
1373 uintN inlineCallCount
;
1374 JSObject
*obj
, *obj2
, *proto
, *parent
;
1375 JSVersion currentVersion
, originalVersion
;
1376 JSBranchCallback onbranch
;
1378 JSTrapHandler interruptHandler
;
1380 jsval
*sp
= NULL
, *newsp
;
1382 jsbytecode
*pc
, *pc2
, *endpc
;
1384 const JSCodeSpec
*cs
= NULL
;
1386 uintN argc
, slot
, attrs
;
1387 jsval
*vp
, lval
, rval
, ltmp
, rtmp
;
1389 JSObject
*withobj
, *origobj
, *propobj
;
1392 JSScopeProperty
*sprop
;
1393 JSString
*str
, *str2
;
1396 JSClass
*clasp
, *funclasp
;
1400 FILE *tracefp
= NULL
;
1402 #if JS_HAS_EXPORT_IMPORT
1405 #if JS_HAS_SWITCH_STATEMENT
1406 jsint low
, high
, off
, npairs
;
1409 #if JS_HAS_GETTER_SETTER
1410 JSPropertyOp getter
, setter
;
1414 *result
= JSVAL_VOID
;
1417 /* Set registerized frame pointer and derived script pointer. */
1419 script
= fp
->script
;
1421 /* Count of JS function calls that nest in this C js_Interpret frame. */
1422 inlineCallCount
= 0;
1425 * Optimized Get and SetVersion for proper script language versioning.
1427 * If any native method or JSClass/JSObjectOps hook calls JS_SetVersion
1428 * and changes cx->version, the effect will "stick" and we will stop
1429 * maintaining currentVersion. This is relied upon by testsuites, for
1430 * the most part -- web browsers select version before compiling and not
1433 currentVersion
= script
->version
;
1434 originalVersion
= cx
->version
;
1435 if (currentVersion
!= originalVersion
)
1436 JS_SetVersion(cx
, currentVersion
);
1439 * Prepare to call a user-supplied branch handler, and abort the script
1440 * if it returns false. We reload onbranch after calling out to native
1441 * functions (but not to getters, setters, or other native hooks).
1443 #define LOAD_BRANCH_CALLBACK(cx) (onbranch = (cx)->branchCallback)
1445 LOAD_BRANCH_CALLBACK(cx
);
1447 #define CHECK_BRANCH(len) \
1449 if (len <= 0 && onbranch) { \
1451 if (!(ok = (*onbranch)(cx, script))) \
1457 * Load the debugger's interrupt hook here and after calling out to native
1458 * functions (but not to getters, setters, or other native hooks), so we do
1459 * not have to reload it each time through the interpreter loop -- we hope
1460 * the compiler can keep it in a register.
1461 * XXX if it spills, we still lose
1463 #define LOAD_INTERRUPT_HANDLER(rt) (interruptHandler = (rt)->interruptHandler)
1465 LOAD_INTERRUPT_HANDLER(rt
);
1468 endpc
= pc
+ script
->length
;
1469 depth
= (jsint
) script
->depth
;
1472 /* Check for too much js_Interpret nesting, or too deep a C stack. */
1473 if (++cx
->interpLevel
== MAX_INTERP_LEVEL
||
1474 !JS_CHECK_STACK_SIZE(cx
, stackDummy
)) {
1475 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_OVER_RECURSED
);
1481 * Allocate operand and pc stack slots for the script's worst-case depth.
1483 newsp
= js_AllocRawStack(cx
, (uintN
)(2 * depth
), &mark
);
1492 while (pc
< endpc
) {
1496 cs
= &js_CodeSpec
[op
];
1500 tracefp
= (FILE *) cx
->tracefp
;
1504 fprintf(tracefp
, "%4u: ", js_PCToLineNumber(cx
, script
, pc
));
1505 js_Disassemble1(cx
, script
, pc
,
1506 PTRDIFF(pc
, script
->code
, jsbytecode
), JS_FALSE
,
1511 for (n
= -nuses
; n
< 0; n
++) {
1512 str
= js_DecompileValueGenerator(cx
, n
, sp
[n
], NULL
);
1514 fprintf(tracefp
, "%s %s",
1515 (n
== -nuses
) ? " inputs:" : ",",
1516 JS_GetStringBytes(str
));
1519 fprintf(tracefp
, " @ %d\n", sp
- fp
->spbase
);
1524 if (interruptHandler
) {
1526 switch (interruptHandler(cx
, script
, pc
, &rval
,
1527 rt
->interruptHandlerData
)) {
1531 case JSTRAP_CONTINUE
:
1536 #if JS_HAS_EXCEPTIONS
1538 cx
->throwing
= JS_TRUE
;
1539 cx
->exception
= rval
;
1542 #endif /* JS_HAS_EXCEPTIONS */
1545 LOAD_INTERRUPT_HANDLER(rt
);
1557 PUSH_OPND(JSVAL_VOID
);
1568 case JSOP_FLASHSWAP
:
1569 id
= pc
[1] << 8 | pc
[2];
1576 * N.B. JSOP_SWAP doesn't swap the corresponding generating pcs
1577 * for the operands it swaps.
1585 *result
= POP_OPND();
1588 case JSOP_ENTERWITH
:
1589 rval
= FETCH_OPND(-1);
1590 VALUE_TO_OBJECT(cx
, rval
, obj
);
1591 withobj
= js_NewObject(cx
, &js_WithClass
, obj
, fp
->scopeChain
);
1594 fp
->scopeChain
= withobj
;
1595 STORE_OPND(-1, OBJECT_TO_JSVAL(withobj
));
1598 case JSOP_LEAVEWITH
:
1600 JS_ASSERT(JSVAL_IS_OBJECT(rval
));
1601 withobj
= JSVAL_TO_OBJECT(rval
);
1602 JS_ASSERT(OBJ_GET_CLASS(cx
, withobj
) == &js_WithClass
);
1604 rval
= OBJ_GET_SLOT(cx
, withobj
, JSSLOT_PARENT
);
1605 JS_ASSERT(JSVAL_IS_OBJECT(rval
));
1606 fp
->scopeChain
= JSVAL_TO_OBJECT(rval
);
1610 fp
->rval
= POP_OPND();
1615 fp
->rval
= POP_OPND();
1618 case JSOP_RETRVAL
: /* fp->rval already set */
1619 if (inlineCallCount
)
1622 JSInlineFrame
*ifp
= (JSInlineFrame
*) fp
;
1623 void *hookData
= ifp
->hookData
;
1626 JSInterpreterHook hook
= cx
->runtime
->callHook
;
1628 hook(cx
, fp
, JS_FALSE
, &ok
, hookData
);
1629 LOAD_INTERRUPT_HANDLER(rt
);
1632 #if JS_HAS_ARGS_OBJECT
1634 ok
&= js_PutArgsObject(cx
, fp
);
1637 /* Restore context version only if callee hasn't set version. */
1638 if (cx
->version
== currentVersion
) {
1639 currentVersion
= ifp
->callerVersion
;
1640 if (currentVersion
!= cx
->version
)
1641 JS_SetVersion(cx
, currentVersion
);
1644 /* Store the return value in the caller's operand frame. */
1648 /* Restore cx->fp and release the inline frame's space. */
1649 cx
->fp
= fp
= fp
->down
;
1650 JS_ARENA_RELEASE(&cx
->stackPool
, ifp
->mark
);
1652 /* Restore sp to point just above the return value. */
1656 /* Restore the calling script's interpreter registers. */
1657 script
= fp
->script
;
1658 depth
= (jsint
) script
->depth
;
1660 endpc
= script
->code
+ script
->length
;
1662 /* Store the generating pc for the return value. */
1663 vp
[-depth
] = (jsval
)pc
;
1665 /* Set remaining variables for 'goto advance_pc'. */
1667 cs
= &js_CodeSpec
[op
];
1670 /* Resume execution in the calling frame. */
1677 #if JS_HAS_SWITCH_STATEMENT
1683 len
= GET_JUMP_OFFSET(pc
);
1688 POP_BOOLEAN(cx
, rval
, cond
);
1689 if (cond
== JS_FALSE
) {
1690 len
= GET_JUMP_OFFSET(pc
);
1696 POP_BOOLEAN(cx
, rval
, cond
);
1697 if (cond
!= JS_FALSE
) {
1698 len
= GET_JUMP_OFFSET(pc
);
1704 POP_BOOLEAN(cx
, rval
, cond
);
1705 if (cond
== JS_TRUE
) {
1706 len
= GET_JUMP_OFFSET(pc
);
1712 POP_BOOLEAN(cx
, rval
, cond
);
1713 if (cond
== JS_FALSE
) {
1714 len
= GET_JUMP_OFFSET(pc
);
1720 #if JS_HAS_SWITCH_STATEMENT
1726 len
= GET_JUMPX_OFFSET(pc
);
1731 POP_BOOLEAN(cx
, rval
, cond
);
1732 if (cond
== JS_FALSE
) {
1733 len
= GET_JUMPX_OFFSET(pc
);
1739 POP_BOOLEAN(cx
, rval
, cond
);
1740 if (cond
!= JS_FALSE
) {
1741 len
= GET_JUMPX_OFFSET(pc
);
1747 POP_BOOLEAN(cx
, rval
, cond
);
1748 if (cond
== JS_TRUE
) {
1749 len
= GET_JUMPX_OFFSET(pc
);
1755 POP_BOOLEAN(cx
, rval
, cond
);
1756 if (cond
== JS_FALSE
) {
1757 len
= GET_JUMPX_OFFSET(pc
);
1764 ok
= js_ValueToObject(cx
, FETCH_OPND(-1), &obj
);
1767 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
1770 #define FETCH_ELEMENT_ID(n, id) \
1772 /* If the index is not a jsint, atomize it. */ \
1773 id = (jsid) FETCH_OPND(n); \
1774 if (JSVAL_IS_INT(id)) { \
1778 atom = js_ValueToStringAtom(cx, (jsval)id); \
1787 #define POP_ELEMENT_ID(id) \
1789 FETCH_ELEMENT_ID(-1, id); \
1793 #if JS_HAS_IN_OPERATOR
1796 rval
= FETCH_OPND(-1);
1797 if (JSVAL_IS_PRIMITIVE(rval
)) {
1798 str
= js_DecompileValueGenerator(cx
, -1, rval
, NULL
);
1800 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1801 JSMSG_IN_NOT_OBJECT
,
1802 JS_GetStringBytes(str
));
1807 obj
= JSVAL_TO_OBJECT(rval
);
1808 FETCH_ELEMENT_ID(-2, id
);
1809 ok
= OBJ_LOOKUP_PROPERTY(cx
, obj
, id
, &obj2
, &prop
);
1813 STORE_OPND(-1, BOOLEAN_TO_JSVAL(prop
!= NULL
));
1815 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
1817 #endif /* JS_HAS_IN_OPERATOR */
1821 * Handle JSOP_FORPROP first, so the cost of the goto do_forinloop
1822 * is not paid for the more common cases.
1824 lval
= FETCH_OPND(-1);
1825 atom
= GET_ATOM(cx
, script
, pc
);
1831 atom
= GET_ATOM(cx
, script
, pc
);
1835 * ECMA 12.6.3 says to eval the LHS after looking for properties
1836 * to enumerate, and bail without LHS eval if there are no props.
1837 * We do Find here to share the most code at label do_forinloop.
1838 * If looking for enumerable properties could have side effects,
1839 * then we'd have to move this into the common code and condition
1840 * it on op == JSOP_FORNAME.
1843 ok
= js_FindProperty(cx
, id
, &obj
, &obj2
, &prop
);
1847 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
1848 lval
= OBJECT_TO_JSVAL(obj
);
1854 * JSOP_FORARG and JSOP_FORVAR don't require any lval computation
1855 * here, because they address slots on the stack (in fp->args and
1856 * fp->vars, respectively).
1862 * JSOP_FORELEM simply initializes or updates the iteration state
1863 * and leaves the index expression evaluation and assignment to the
1864 * enumerator until after the next property has been acquired, via
1865 * a JSOP_ENUMELEM bytecode.
1871 * ECMA-compatible for/in evals the object just once, before loop.
1872 * Bad old bytecodes (since removed) did it on every iteration.
1874 obj
= JSVAL_TO_OBJECT(sp
[i
]);
1876 /* If the thing to the right of 'in' has no properties, break. */
1883 * Save the thing to the right of 'in' as origobj. Later on, we
1884 * use this variable to suppress enumeration of shadowed prototype
1890 * Reach under the top of stack to find our property iterator, a
1891 * JSObject that contains the iteration state. (An object is used
1892 * rather than a native struct so that the iteration state is
1893 * cleaned up via GC if the for-in loop terminates abruptly.)
1899 * Save sp in fp now, before any OBJ_* call-outs that might nest
1900 * an interpreter or GC activation on this context.
1904 /* Is this the first iteration ? */
1905 if (JSVAL_IS_VOID(rval
)) {
1906 /* Yes, create a new JSObject to hold the iterator state */
1907 propobj
= js_NewObject(cx
, &prop_iterator_class
, NULL
, obj
);
1912 propobj
->slots
[JSSLOT_ITER_STATE
] = JSVAL_NULL
;
1915 * Root the parent slot so we can get it even in our finalizer
1916 * (otherwise, it would live as long as we do, but it might be
1919 ok
= js_AddRoot(cx
, &propobj
->slots
[JSSLOT_PARENT
],
1925 * Rewrite the iterator so we know to do the next case.
1926 * Do this before calling the enumerator, which could
1927 * displace cx->newborn and cause GC.
1929 *vp
= OBJECT_TO_JSVAL(propobj
);
1931 ok
= OBJ_ENUMERATE(cx
, obj
, JSENUMERATE_INIT
, &iter_state
, 0);
1934 * Stash private iteration state into property iterator object.
1935 * We do this before checking 'ok' to ensure that propobj is
1936 * in a valid state even if OBJ_ENUMERATE returned JS_FALSE.
1937 * NB: This code knows that the first slots are pre-allocated.
1939 #if JS_INITIAL_NSLOTS < 5
1940 #error JS_INITIAL_NSLOTS must be greater than or equal to 5.
1942 propobj
->slots
[JSSLOT_ITER_STATE
] = iter_state
;
1946 /* This is not the first iteration. Recover iterator state. */
1947 propobj
= JSVAL_TO_OBJECT(rval
);
1948 JS_ASSERT(OBJ_GET_CLASS(cx
, propobj
) == &prop_iterator_class
);
1949 obj
= JSVAL_TO_OBJECT(propobj
->slots
[JSSLOT_PARENT
]);
1950 iter_state
= propobj
->slots
[JSSLOT_ITER_STATE
];
1954 /* Get the next jsid to be enumerated and store it in rval. */
1955 OBJ_ENUMERATE(cx
, obj
, JSENUMERATE_NEXT
, &iter_state
, &rval
);
1956 propobj
->slots
[JSSLOT_ITER_STATE
] = iter_state
;
1958 /* No more jsids to iterate in obj? */
1959 if (iter_state
== JSVAL_NULL
) {
1960 /* Enumerate the properties on obj's prototype chain. */
1961 obj
= OBJ_GET_PROTO(cx
, obj
);
1963 /* End of property list -- terminate loop. */
1968 ok
= OBJ_ENUMERATE(cx
, obj
, JSENUMERATE_INIT
, &iter_state
, 0);
1971 * Stash private iteration state into property iterator object.
1972 * We do this before checking 'ok' to ensure that propobj is
1973 * in a valid state even if OBJ_ENUMERATE returned JS_FALSE.
1974 * NB: This code knows that the first slots are pre-allocated.
1976 propobj
->slots
[JSSLOT_ITER_STATE
] = iter_state
;
1981 * Update the iterator JSObject's parent link to refer to the
1982 * current object. This is used in the iterator JSObject's
1985 propobj
->slots
[JSSLOT_PARENT
] = OBJECT_TO_JSVAL(obj
);
1986 goto enum_next_property
;
1989 /* Skip properties not owned by obj, and leave next id in rval. */
1990 ok
= OBJ_LOOKUP_PROPERTY(cx
, origobj
, rval
, &obj2
, &prop
);
1994 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
1996 /* If the id was deleted, or found in a prototype, skip it. */
1997 if (!prop
|| obj2
!= obj
)
1998 goto enum_next_property
;
2000 /* Make sure rval is a string for uniformity and compatibility. */
2001 if (!JSVAL_IS_INT(rval
)) {
2002 rval
= ATOM_KEY((JSAtom
*)rval
);
2003 } else if (cx
->version
!= JSVERSION_1_2
) {
2004 str
= js_NumberToString(cx
, (jsdouble
) JSVAL_TO_INT(rval
));
2010 rval
= STRING_TO_JSVAL(str
);
2015 slot
= GET_ARGNO(pc
);
2016 JS_ASSERT(slot
< fp
->fun
->nargs
);
2017 fp
->argv
[slot
] = rval
;
2021 slot
= GET_VARNO(pc
);
2022 JS_ASSERT(slot
< fp
->fun
->nvars
);
2023 fp
->vars
[slot
] = rval
;
2027 /* FORELEM is not a SET operation, it's more like BINDNAME. */
2032 /* Convert lval to a non-null object containing id. */
2033 VALUE_TO_OBJECT(cx
, lval
, obj
);
2035 /* Set the variable obj[id] to refer to rval. */
2036 fp
->flags
|= JSFRAME_ASSIGNING
;
2037 ok
= OBJ_SET_PROPERTY(cx
, obj
, id
, &rval
);
2038 fp
->flags
&= ~JSFRAME_ASSIGNING
;
2044 /* Push true to keep looping through properties. */
2053 JS_ASSERT(sp
> fp
->spbase
);
2059 JS_ASSERT(sp
- 1 > fp
->spbase
);
2060 lval
= FETCH_OPND(-2);
2061 rval
= FETCH_OPND(-1);
2066 #define PROPERTY_OP(n, call) \
2068 /* Pop the left part and resolve it to a non-null object. */ \
2069 lval = FETCH_OPND(n); \
2070 VALUE_TO_OBJECT(cx, lval, obj); \
2072 /* Get or set the property, set ok false if error, true if success. */\
2079 #define ELEMENT_OP(n, call) \
2081 FETCH_ELEMENT_ID(n, id); \
2082 PROPERTY_OP(n-1, call); \
2086 * Direct callers, i.e. those who do not wrap CACHED_GET and CACHED_SET calls
2087 * in PROPERTY_OP or ELEMENT_OP macro calls must SAVE_SP(fp); beforehand, just
2088 * in case a getter or setter function is invoked.
2090 #define CACHED_GET(call) \
2092 if (!OBJ_IS_NATIVE(obj)) { \
2095 JS_LOCK_OBJ(cx, obj); \
2096 PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, sprop); \
2098 JSScope *scope_ = OBJ_SCOPE(obj); \
2099 slot = (uintN)sprop->slot; \
2100 rval = (slot != SPROP_INVALID_SLOT) \
2101 ? LOCKED_OBJ_GET_SLOT(obj, slot) \
2103 JS_UNLOCK_SCOPE(cx, scope_); \
2104 ok = SPROP_GET(cx, sprop, obj, obj, &rval); \
2105 JS_LOCK_SCOPE(cx, scope_); \
2106 if (ok && SPROP_HAS_VALID_SLOT(sprop, scope_)) \
2107 LOCKED_OBJ_SET_SLOT(obj, slot, rval); \
2108 JS_UNLOCK_SCOPE(cx, scope_); \
2110 JS_UNLOCK_OBJ(cx, obj); \
2112 /* No fill here: js_GetProperty fills the cache. */ \
2117 #define CACHED_SET(call) \
2119 if (!OBJ_IS_NATIVE(obj)) { \
2123 JS_LOCK_OBJ(cx, obj); \
2124 PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, sprop); \
2126 !(sprop->attrs & JSPROP_READONLY) && \
2127 (scope_ = OBJ_SCOPE(obj), !SCOPE_IS_SEALED(scope_))) { \
2128 JS_UNLOCK_SCOPE(cx, scope_); \
2129 ok = SPROP_SET(cx, sprop, obj, obj, &rval); \
2130 JS_LOCK_SCOPE(cx, scope_); \
2131 if (ok && SPROP_HAS_VALID_SLOT(sprop, scope_)) { \
2132 LOCKED_OBJ_SET_SLOT(obj, sprop->slot, rval); \
2133 GC_POKE(cx, JSVAL_NULL); /* XXX second arg ignored */ \
2135 JS_UNLOCK_SCOPE(cx, scope_); \
2137 JS_UNLOCK_OBJ(cx, obj); \
2139 /* No fill here: js_SetProperty writes through the cache. */ \
2146 atom
= GET_ATOM(cx
, script
, pc
);
2147 rval
= FETCH_OPND(-1);
2149 ok
= OBJ_DEFINE_PROPERTY(cx
, obj
, (jsid
)atom
, rval
, NULL
, NULL
,
2150 JSPROP_ENUMERATE
| JSPROP_PERMANENT
|
2155 STORE_OPND(-1, rval
);
2159 atom
= GET_ATOM(cx
, script
, pc
);
2161 obj
= js_FindIdentifierBase(cx
, (jsid
)atom
);
2166 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
2170 atom
= GET_ATOM(cx
, script
, pc
);
2172 rval
= FETCH_OPND(-1);
2173 lval
= FETCH_OPND(-2);
2174 JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval
));
2175 obj
= JSVAL_TO_OBJECT(lval
);
2177 CACHED_SET(OBJ_SET_PROPERTY(cx
, obj
, id
, &rval
));
2181 STORE_OPND(-1, rval
);
2184 #define INTEGER_OP(OP, EXTRA_CODE) \
2186 FETCH_INT(cx, -1, j); \
2187 FETCH_INT(cx, -2, i); \
2193 STORE_NUMBER(cx, -1, d); \
2196 #define BITWISE_OP(OP) INTEGER_OP(OP, (void) 0;)
2197 #define SIGNED_SHIFT_OP(OP) INTEGER_OP(OP, j &= 31;)
2212 #define COMPARE_DOUBLES(LVAL, OP, RVAL, IFNAN) \
2213 ((JSDOUBLE_IS_NaN(LVAL) || JSDOUBLE_IS_NaN(RVAL)) \
2217 #define COMPARE_DOUBLES(LVAL, OP, RVAL, IFNAN) ((LVAL) OP (RVAL))
2220 #define RELATIONAL_OP(OP) \
2222 rval = FETCH_OPND(-1); \
2223 lval = FETCH_OPND(-2); \
2224 /* Optimize for two int-tagged operands (typical loop control). */ \
2225 if ((lval & rval) & JSVAL_INT) { \
2226 ltmp = lval ^ JSVAL_VOID; \
2227 rtmp = rval ^ JSVAL_VOID; \
2228 if (ltmp && rtmp) { \
2229 cond = JSVAL_TO_INT(lval) OP JSVAL_TO_INT(rval); \
2231 d = ltmp ? JSVAL_TO_INT(lval) : *rt->jsNaN; \
2232 d2 = rtmp ? JSVAL_TO_INT(rval) : *rt->jsNaN; \
2233 cond = COMPARE_DOUBLES(d, OP, d2, JS_FALSE); \
2236 VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_NUMBER, &lval); \
2237 VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_NUMBER, &rval); \
2238 if (JSVAL_IS_STRING(lval) && JSVAL_IS_STRING(rval)) { \
2239 str = JSVAL_TO_STRING(lval); \
2240 str2 = JSVAL_TO_STRING(rval); \
2241 cond = js_CompareStrings(str, str2) OP 0; \
2243 VALUE_TO_NUMBER(cx, lval, d); \
2244 VALUE_TO_NUMBER(cx, rval, d2); \
2245 cond = COMPARE_DOUBLES(d, OP, d2, JS_FALSE); \
2249 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
2252 #define EQUALITY_OP(OP, IFNAN) \
2254 rval = FETCH_OPND(-1); \
2255 lval = FETCH_OPND(-2); \
2256 ltmp = JSVAL_TAG(lval); \
2257 rtmp = JSVAL_TAG(rval); \
2258 if (ltmp == rtmp) { \
2259 if (ltmp == JSVAL_STRING) { \
2260 str = JSVAL_TO_STRING(lval); \
2261 str2 = JSVAL_TO_STRING(rval); \
2262 cond = js_CompareStrings(str, str2) OP 0; \
2263 } else if (ltmp == JSVAL_DOUBLE) { \
2264 d = *JSVAL_TO_DOUBLE(lval); \
2265 d2 = *JSVAL_TO_DOUBLE(rval); \
2266 cond = COMPARE_DOUBLES(d, OP, d2, IFNAN); \
2268 /* Handle all undefined (=>NaN) and int combinations. */ \
2269 cond = lval OP rval; \
2272 if (JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval)) { \
2273 cond = (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) OP 1; \
2274 } else if (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) { \
2277 if (ltmp == JSVAL_OBJECT) { \
2278 VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_VOID, &lval); \
2279 ltmp = JSVAL_TAG(lval); \
2280 } else if (rtmp == JSVAL_OBJECT) { \
2281 VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_VOID, &rval); \
2282 rtmp = JSVAL_TAG(rval); \
2284 if (ltmp == JSVAL_STRING && rtmp == JSVAL_STRING) { \
2285 str = JSVAL_TO_STRING(lval); \
2286 str2 = JSVAL_TO_STRING(rval); \
2287 cond = js_CompareStrings(str, str2) OP 0; \
2289 VALUE_TO_NUMBER(cx, lval, d); \
2290 VALUE_TO_NUMBER(cx, rval, d2); \
2291 cond = COMPARE_DOUBLES(d, OP, d2, IFNAN); \
2296 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
2300 EQUALITY_OP(==, JS_FALSE
);
2304 EQUALITY_OP(!=, JS_TRUE
);
2307 #if !JS_BUG_FALLIBLE_EQOPS
2308 #define NEW_EQUALITY_OP(OP, IFNAN) \
2310 rval = FETCH_OPND(-1); \
2311 lval = FETCH_OPND(-2); \
2312 ltmp = JSVAL_TAG(lval); \
2313 rtmp = JSVAL_TAG(rval); \
2314 if (ltmp == rtmp) { \
2315 if (ltmp == JSVAL_STRING) { \
2316 str = JSVAL_TO_STRING(lval); \
2317 str2 = JSVAL_TO_STRING(rval); \
2318 cond = js_CompareStrings(str, str2) OP 0; \
2319 } else if (ltmp == JSVAL_DOUBLE) { \
2320 d = *JSVAL_TO_DOUBLE(lval); \
2321 d2 = *JSVAL_TO_DOUBLE(rval); \
2322 cond = COMPARE_DOUBLES(d, OP, d2, IFNAN); \
2324 cond = lval OP rval; \
2327 if (ltmp == JSVAL_DOUBLE && JSVAL_IS_INT(rval)) { \
2328 d = *JSVAL_TO_DOUBLE(lval); \
2329 d2 = JSVAL_TO_INT(rval); \
2330 cond = COMPARE_DOUBLES(d, OP, d2, IFNAN); \
2331 } else if (JSVAL_IS_INT(lval) && rtmp == JSVAL_DOUBLE) { \
2332 d = JSVAL_TO_INT(lval); \
2333 d2 = *JSVAL_TO_DOUBLE(rval); \
2334 cond = COMPARE_DOUBLES(d, OP, d2, IFNAN); \
2336 cond = lval OP rval; \
2340 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
2344 NEW_EQUALITY_OP(==, JS_FALSE
);
2348 NEW_EQUALITY_OP(!=, JS_TRUE
);
2351 #if JS_HAS_SWITCH_STATEMENT
2353 NEW_EQUALITY_OP(==, JS_FALSE
);
2356 len
= GET_JUMP_OFFSET(pc
);
2364 NEW_EQUALITY_OP(==, JS_FALSE
);
2367 len
= GET_JUMPX_OFFSET(pc
);
2375 #endif /* !JS_BUG_FALLIBLE_EQOPS */
2394 #undef RELATIONAL_OP
2397 SIGNED_SHIFT_OP(<<);
2401 SIGNED_SHIFT_OP(>>);
2408 FETCH_INT(cx
, -1, j
);
2409 FETCH_UINT(cx
, -2, u
);
2413 STORE_NUMBER(cx
, -1, d
);
2419 #undef SIGNED_SHIFT_OP
2422 rval
= FETCH_OPND(-1);
2423 lval
= FETCH_OPND(-2);
2424 VALUE_TO_PRIMITIVE(cx
, lval
, JSTYPE_VOID
, <mp
);
2425 VALUE_TO_PRIMITIVE(cx
, rval
, JSTYPE_VOID
, &rtmp
);
2426 if ((cond
= JSVAL_IS_STRING(ltmp
)) || JSVAL_IS_STRING(rtmp
)) {
2429 str
= JSVAL_TO_STRING(ltmp
);
2430 ok
= (str2
= js_ValueToString(cx
, rtmp
)) != NULL
;
2432 str2
= JSVAL_TO_STRING(rtmp
);
2433 ok
= (str
= js_ValueToString(cx
, ltmp
)) != NULL
;
2437 str
= js_ConcatStrings(cx
, str
, str2
);
2443 STORE_OPND(-1, STRING_TO_JSVAL(str
));
2445 VALUE_TO_NUMBER(cx
, lval
, d
);
2446 VALUE_TO_NUMBER(cx
, rval
, d2
);
2449 STORE_NUMBER(cx
, -1, d
);
2453 #define BINARY_OP(OP) \
2455 FETCH_NUMBER(cx, -1, d2); \
2456 FETCH_NUMBER(cx, -2, d); \
2459 STORE_NUMBER(cx, -1, d); \
2471 FETCH_NUMBER(cx
, -1, d2
);
2472 FETCH_NUMBER(cx
, -2, d
);
2476 /* XXX MSVC miscompiles such that (NaN == 0) */
2477 if (JSDOUBLE_IS_NaN(d2
))
2478 rval
= DOUBLE_TO_JSVAL(rt
->jsNaN
);
2481 if (d
== 0 || JSDOUBLE_IS_NaN(d
))
2482 rval
= DOUBLE_TO_JSVAL(rt
->jsNaN
);
2483 else if ((JSDOUBLE_HI32(d
) ^ JSDOUBLE_HI32(d2
)) >> 31)
2484 rval
= DOUBLE_TO_JSVAL(rt
->jsNegativeInfinity
);
2486 rval
= DOUBLE_TO_JSVAL(rt
->jsPositiveInfinity
);
2487 STORE_OPND(-1, rval
);
2490 STORE_NUMBER(cx
, -1, d
);
2495 FETCH_NUMBER(cx
, -1, d2
);
2496 FETCH_NUMBER(cx
, -2, d
);
2499 STORE_OPND(-1, DOUBLE_TO_JSVAL(rt
->jsNaN
));
2502 /* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
2503 if (!(JSDOUBLE_IS_FINITE(d
) && JSDOUBLE_IS_INFINITE(d2
)))
2506 STORE_NUMBER(cx
, -1, d
);
2511 POP_BOOLEAN(cx
, rval
, cond
);
2512 PUSH_OPND(BOOLEAN_TO_JSVAL(!cond
));
2516 FETCH_INT(cx
, -1, i
);
2518 STORE_NUMBER(cx
, -1, d
);
2522 FETCH_NUMBER(cx
, -1, d
);
2525 * Negation of a zero doesn't produce a negative
2526 * zero on HPUX. Perform the operation by bit
2529 JSDOUBLE_HI32(d
) ^= JSDOUBLE_HI32_SIGNBIT
;
2533 STORE_NUMBER(cx
, -1, d
);
2537 FETCH_NUMBER(cx
, -1, d
);
2538 STORE_NUMBER(cx
, -1, d
);
2542 /* Get immediate argc and find the constructor function. */
2543 argc
= GET_ARGC(pc
);
2545 #if JS_HAS_INITIALIZERS
2549 vp
= sp
- (2 + argc
);
2550 JS_ASSERT(vp
>= fp
->spbase
);
2555 if (!JSVAL_IS_OBJECT(lval
) ||
2556 (obj2
= JSVAL_TO_OBJECT(lval
)) == NULL
||
2557 /* XXX clean up to avoid special cases above ObjectOps layer */
2558 OBJ_GET_CLASS(cx
, obj2
) == &js_FunctionClass
||
2559 !obj2
->map
->ops
->construct
)
2561 fun
= js_ValueToFunction(cx
, vp
, JSV2F_CONSTRUCT
);
2568 clasp
= &js_ObjectClass
;
2570 proto
= parent
= NULL
;
2573 /* Get the constructor prototype object for this function. */
2574 ok
= OBJ_GET_PROPERTY(cx
, obj2
,
2575 (jsid
)rt
->atomState
.classPrototypeAtom
,
2579 proto
= JSVAL_IS_OBJECT(rval
) ? JSVAL_TO_OBJECT(rval
) : NULL
;
2580 parent
= OBJ_GET_PARENT(cx
, obj2
);
2582 if (OBJ_GET_CLASS(cx
, obj2
) == &js_FunctionClass
) {
2583 funclasp
= ((JSFunction
*)JS_GetPrivate(cx
, obj2
))->clasp
;
2588 obj
= js_NewObject(cx
, clasp
, proto
, parent
);
2594 /* Now we have an object with a constructor method; call it. */
2595 vp
[1] = OBJECT_TO_JSVAL(obj
);
2596 ok
= js_Invoke(cx
, argc
, JSINVOKE_CONSTRUCT
);
2598 LOAD_BRANCH_CALLBACK(cx
);
2599 LOAD_INTERRUPT_HANDLER(rt
);
2601 cx
->newborn
[GCX_OBJECT
] = NULL
;
2605 /* Check the return value and update obj from it. */
2607 if (JSVAL_IS_PRIMITIVE(rval
)) {
2608 if (fun
|| !JSVERSION_IS_ECMA(cx
->version
)) {
2609 *vp
= OBJECT_TO_JSVAL(obj
);
2612 /* native [[Construct]] returning primitive is error */
2613 str
= js_ValueToString(cx
, rval
);
2615 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2616 JSMSG_BAD_NEW_RESULT
,
2617 JS_GetStringBytes(str
));
2622 obj
= JSVAL_TO_OBJECT(rval
);
2623 JS_RUNTIME_METER(rt
, constructs
);
2627 atom
= GET_ATOM(cx
, script
, pc
);
2631 ok
= js_FindProperty(cx
, id
, &obj
, &obj2
, &prop
);
2635 /* ECMA says to return true if name is undefined or inherited. */
2638 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
2639 ok
= OBJ_DELETE_PROPERTY(cx
, obj
, id
, &rval
);
2647 atom
= GET_ATOM(cx
, script
, pc
);
2649 PROPERTY_OP(-1, ok
= OBJ_DELETE_PROPERTY(cx
, obj
, id
, &rval
));
2650 STORE_OPND(-1, rval
);
2654 ELEMENT_OP(-1, ok
= OBJ_DELETE_PROPERTY(cx
, obj
, id
, &rval
));
2656 STORE_OPND(-1, rval
);
2661 type
= JS_TypeOfValue(cx
, rval
);
2662 atom
= rt
->atomState
.typeAtoms
[type
];
2663 str
= ATOM_TO_STRING(atom
);
2664 PUSH_OPND(STRING_TO_JSVAL(str
));
2669 PUSH_OPND(JSVAL_VOID
);
2676 atom
= GET_ATOM(cx
, script
, pc
);
2680 ok
= js_FindProperty(cx
, id
, &obj
, &obj2
, &prop
);
2684 goto atom_not_defined
;
2686 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
2687 lval
= OBJECT_TO_JSVAL(obj
);
2694 atom
= GET_ATOM(cx
, script
, pc
);
2707 VALUE_TO_OBJECT(cx
, lval
, obj
);
2709 /* The operand must contain a number. */
2711 CACHED_GET(OBJ_GET_PROPERTY(cx
, obj
, id
, &rval
));
2715 /* The expression result goes in rtmp, the updated value in rval. */
2716 if (JSVAL_IS_INT(rval
) &&
2717 rval
!= INT_TO_JSVAL(JSVAL_INT_MIN
) &&
2718 rval
!= INT_TO_JSVAL(JSVAL_INT_MAX
)) {
2719 if (cs
->format
& JOF_POST
) {
2721 (cs
->format
& JOF_INC
) ? (rval
+= 2) : (rval
-= 2);
2723 (cs
->format
& JOF_INC
) ? (rval
+= 2) : (rval
-= 2);
2729 * Initially, rval contains the value to increment or decrement, which is not
2730 * yet converted. As above, the expression result goes in rtmp, the updated
2731 * value goes in rval.
2733 #define NONINT_INCREMENT_OP() \
2735 VALUE_TO_NUMBER(cx, rval, d); \
2736 if (cs->format & JOF_POST) { \
2738 if (!JSVAL_IS_NUMBER(rtmp)) { \
2739 ok = js_NewNumberValue(cx, d, &rtmp); \
2743 (cs->format & JOF_INC) ? d++ : d--; \
2744 ok = js_NewNumberValue(cx, d, &rval); \
2746 (cs->format & JOF_INC) ? ++d : --d; \
2747 ok = js_NewNumberValue(cx, d, &rval); \
2754 NONINT_INCREMENT_OP();
2757 CACHED_SET(OBJ_SET_PROPERTY(cx
, obj
, id
, &rval
));
2764 * NB: This macro can't use JS_BEGIN_MACRO/JS_END_MACRO around its body because
2765 * it must break from the switch case that calls it, not from the do...while(0)
2766 * loop created by the JS_BEGIN/END_MACRO brackets.
2768 #define FAST_INCREMENT_OP(SLOT,COUNT,BASE,PRE,OP,MINMAX) \
2769 slot = (uintN)SLOT; \
2770 JS_ASSERT(slot < fp->fun->COUNT); \
2771 vp = fp->BASE + slot; \
2773 if (JSVAL_IS_INT(rval) && \
2774 rval != INT_TO_JSVAL(JSVAL_INT_##MINMAX)) { \
2781 goto do_nonint_fast_incop;
2784 FAST_INCREMENT_OP(GET_ARGNO(pc
), nargs
, argv
, rval
, +=, MAX
);
2786 FAST_INCREMENT_OP(GET_ARGNO(pc
), nargs
, argv
, rval
, -=, MIN
);
2788 FAST_INCREMENT_OP(GET_ARGNO(pc
), nargs
, argv
, rtmp
, +=, MAX
);
2790 FAST_INCREMENT_OP(GET_ARGNO(pc
), nargs
, argv
, rtmp
, -=, MIN
);
2793 FAST_INCREMENT_OP(GET_VARNO(pc
), nvars
, vars
, rval
, +=, MAX
);
2795 FAST_INCREMENT_OP(GET_VARNO(pc
), nvars
, vars
, rval
, -=, MIN
);
2797 FAST_INCREMENT_OP(GET_VARNO(pc
), nvars
, vars
, rtmp
, +=, MAX
);
2799 FAST_INCREMENT_OP(GET_VARNO(pc
), nvars
, vars
, rtmp
, -=, MIN
);
2801 #undef FAST_INCREMENT_OP
2803 do_nonint_fast_incop
:
2804 NONINT_INCREMENT_OP();
2810 /* Get an immediate atom naming the property. */
2811 atom
= GET_ATOM(cx
, script
, pc
);
2813 PROPERTY_OP(-1, CACHED_GET(OBJ_GET_PROPERTY(cx
, obj
, id
, &rval
)));
2814 STORE_OPND(-1, rval
);
2818 /* Pop the right-hand side into rval for OBJ_SET_PROPERTY. */
2819 rval
= FETCH_OPND(-1);
2821 /* Get an immediate atom naming the property. */
2822 atom
= GET_ATOM(cx
, script
, pc
);
2824 PROPERTY_OP(-2, CACHED_SET(OBJ_SET_PROPERTY(cx
, obj
, id
, &rval
)));
2826 STORE_OPND(-1, rval
);
2830 ELEMENT_OP(-1, CACHED_GET(OBJ_GET_PROPERTY(cx
, obj
, id
, &rval
)));
2832 STORE_OPND(-1, rval
);
2836 rval
= FETCH_OPND(-1);
2837 ELEMENT_OP(-2, CACHED_SET(OBJ_SET_PROPERTY(cx
, obj
, id
, &rval
)));
2839 STORE_OPND(-1, rval
);
2843 /* Funky: the value to set is under the [obj, id] pair. */
2844 FETCH_ELEMENT_ID(-1, id
);
2845 lval
= FETCH_OPND(-2);
2846 VALUE_TO_OBJECT(cx
, lval
, obj
);
2847 rval
= FETCH_OPND(-3);
2849 ok
= OBJ_SET_PROPERTY(cx
, obj
, id
, &rval
);
2856 * LAZY_ARGS_THISP allows the JSOP_ARGSUB bytecode to defer creation of the
2857 * arguments object until it is truly needed. JSOP_ARGSUB optimizes away
2858 * arguments objects when the only uses of the 'arguments' parameter are to
2859 * fetch individual actual parameters. But if such a use were then invoked,
2860 * e.g., arguments[i](), the 'this' parameter would and must bind to the
2861 * caller's arguments object. So JSOP_ARGSUB sets obj to LAZY_ARGS_THISP.
2863 #define LAZY_ARGS_THISP ((JSObject *) 1)
2866 if (obj
== LAZY_ARGS_THISP
&& !(obj
= js_GetArgsObject(cx
, fp
))) {
2870 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
2873 case JSOP_FLASHCALL
:
2874 /* rewrite the stack */
2875 FETCH_INT(cx
, -3, j
);
2877 vp
= sp
- (argc
+ 3);
2880 for (i
= 0; i
< (j
/ 2 + 1); i
++) {
2885 /* treat it like a CALL */
2889 argc
= GET_ARGC(pc
);
2890 vp
= sp
- (argc
+ 2);
2895 if (JSVAL_IS_FUNCTION(cx
, lval
) &&
2896 (obj
= JSVAL_TO_OBJECT(lval
),
2897 fun
= (JSFunction
*) JS_GetPrivate(cx
, obj
),
2899 !(fun
->flags
& (JSFUN_HEAVYWEIGHT
| JSFUN_BOUND_METHOD
)) &&
2900 argc
>= (uintN
)(fun
->nargs
+ fun
->extra
)))
2903 uintN nframeslots
, nvars
;
2905 JSInlineFrame
*newifp
;
2906 JSInterpreterHook hook
;
2908 /* Restrict recursion of lightweight functions. */
2909 if (inlineCallCount
== MAX_INLINE_CALL_COUNT
) {
2910 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2911 JSMSG_OVER_RECURSED
);
2917 /* ZZZbe should do this only if interpreted often enough. */
2918 ok
= jsjit_Compile(cx
, fun
);
2923 /* Compute the number of stack slots needed for fun. */
2924 nframeslots
= (sizeof(JSInlineFrame
) + sizeof(jsval
) - 1)
2927 script
= fun
->script
;
2928 depth
= (jsint
) script
->depth
;
2930 /* Allocate the frame and space for vars and operands. */
2931 newsp
= js_AllocRawStack(cx
, nframeslots
+ nvars
+ 2 * depth
,
2935 goto bad_inline_call
;
2937 newifp
= (JSInlineFrame
*) newsp
;
2938 newsp
+= nframeslots
;
2940 /* Initialize the stack frame. */
2941 memset(newifp
, 0, sizeof(JSInlineFrame
));
2942 newifp
->frame
.script
= script
;
2943 newifp
->frame
.fun
= fun
;
2944 newifp
->frame
.argc
= argc
;
2945 newifp
->frame
.argv
= vp
+ 2;
2946 newifp
->frame
.rval
= JSVAL_VOID
;
2947 newifp
->frame
.nvars
= nvars
;
2948 newifp
->frame
.vars
= newsp
;
2949 newifp
->frame
.down
= fp
;
2950 newifp
->frame
.scopeChain
= OBJ_GET_PARENT(cx
, obj
);
2951 newifp
->mark
= newmark
;
2953 /* Compute the 'this' parameter now that argv is set. */
2954 ok
= ComputeThis(cx
, JSVAL_TO_OBJECT(vp
[1]), &newifp
->frame
);
2956 js_FreeRawStack(cx
, newmark
);
2957 goto bad_inline_call
;
2960 /* Push void to initialize local variables. */
2965 newifp
->frame
.spbase
= sp
;
2966 SAVE_SP(&newifp
->frame
);
2968 /* Call the debugger hook if present. */
2969 hook
= cx
->runtime
->callHook
;
2971 newifp
->hookData
= hook(cx
, &newifp
->frame
, JS_TRUE
, 0,
2972 cx
->runtime
->callHookData
);
2973 LOAD_INTERRUPT_HANDLER(rt
);
2976 /* Switch to new version if currentVersion wasn't overridden. */
2977 newifp
->callerVersion
= cx
->version
;
2978 if (cx
->version
== currentVersion
) {
2979 currentVersion
= script
->version
;
2980 if (currentVersion
!= cx
->version
)
2981 JS_SetVersion(cx
, currentVersion
);
2984 /* Push the frame and set interpreter registers. */
2985 cx
->fp
= fp
= &newifp
->frame
;
2987 endpc
= pc
+ script
->length
;
2989 JS_RUNTIME_METER(rt
, inlineCalls
);
2993 script
= fp
->script
;
2994 depth
= (jsint
) script
->depth
;
2998 ok
= js_Invoke(cx
, argc
, 0);
3000 LOAD_BRANCH_CALLBACK(cx
);
3001 LOAD_INTERRUPT_HANDLER(rt
);
3004 JS_RUNTIME_METER(rt
, nonInlineCalls
);
3005 #if JS_HAS_LVALUE_RETURN
3008 * Sneaky: use the stack depth we didn't claim in our budget,
3009 * but that we know is there on account of [fun, this] already
3010 * having been pushed, at a minimum (if no args). Those two
3011 * slots have been popped and [rval] has been pushed, which
3012 * leaves one more slot for rval2 before we might overflow.
3014 * NB: rval2 must be the property identifier, and rval the
3015 * object from which to get the property. The pair form an
3016 * ECMA "reference type", which can be used on the right- or
3017 * left-hand side of assignment ops. Only native methods can
3018 * return reference types. See JSOP_SETCALL just below for
3019 * the left-hand-side case.
3021 PUSH_OPND(cx
->rval2
);
3022 cx
->rval2set
= JS_FALSE
;
3023 ELEMENT_OP(-1, ok
= OBJ_GET_PROPERTY(cx
, obj
, id
, &rval
));
3025 STORE_OPND(-1, rval
);
3031 #if JS_HAS_LVALUE_RETURN
3033 argc
= GET_ARGC(pc
);
3035 ok
= js_Invoke(cx
, argc
, 0);
3037 LOAD_BRANCH_CALLBACK(cx
);
3038 LOAD_INTERRUPT_HANDLER(rt
);
3041 if (!cx
->rval2set
) {
3042 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
3043 JSMSG_BAD_LEFTSIDE_OF_ASS
);
3047 PUSH_OPND(cx
->rval2
);
3048 cx
->rval2set
= JS_FALSE
;
3054 atom
= GET_ATOM(cx
, script
, pc
);
3057 ok
= js_FindProperty(cx
, id
, &obj
, &obj2
, &prop
);
3061 /* Kludge to allow (typeof foo == "undefined") tests. */
3062 for (pc2
= pc
+ len
; pc2
< endpc
; pc2
++) {
3064 if (op2
== JSOP_TYPEOF
) {
3065 PUSH_OPND(JSVAL_VOID
);
3068 if (op2
!= JSOP_GROUP
)
3071 goto atom_not_defined
;
3074 /* Take the slow path if prop was not found in a native object. */
3075 if (!OBJ_IS_NATIVE(obj
) || !OBJ_IS_NATIVE(obj2
)) {
3076 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
3077 ok
= OBJ_GET_PROPERTY(cx
, obj
, id
, &rval
);
3084 /* Get and push the obj[id] property's value. */
3085 sprop
= (JSScopeProperty
*)prop
;
3086 slot
= (uintN
)sprop
->slot
;
3087 rval
= (slot
!= SPROP_INVALID_SLOT
)
3088 ? LOCKED_OBJ_GET_SLOT(obj2
, slot
)
3090 JS_UNLOCK_OBJ(cx
, obj2
);
3091 ok
= SPROP_GET(cx
, sprop
, obj
, obj2
, &rval
);
3092 JS_LOCK_OBJ(cx
, obj2
);
3094 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
3097 if (SPROP_HAS_VALID_SLOT(sprop
, OBJ_SCOPE(obj2
)))
3098 LOCKED_OBJ_SET_SLOT(obj2
, slot
, rval
);
3099 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
3104 i
= (jsint
) GET_ATOM_INDEX(pc
);
3105 rval
= INT_TO_JSVAL(i
);
3112 atom
= GET_ATOM(cx
, script
, pc
);
3113 PUSH_OPND(ATOM_KEY(atom
));
3124 * Get a suitable object from an atom mapped by the bytecode at pc.
3126 * We must handle the case where a regexp object literal is used in
3127 * a different global at execution time from the global with which
3128 * it was scanned at compile time, in order to rewrap the JSRegExp
3129 * struct with a new object having the right prototype and parent.
3131 * Unlike JSOP_DEFFUN and other prolog bytecodes, we don't want to
3132 * pay a script prolog execution price for all regexp literals in a
3133 * script (many may not be used by a particular execution of that
3134 * script, depending on control flow), so we do all fp->objAtomMap
3135 * initialization lazily, here under JSOP_OBJECT.
3137 * XXX This code is specific to regular expression objects. If we
3138 * need JSOP_OBJECT for other kinds of object literals, we should
3139 * push cloning down under JSObjectOps. Also, fp->objAtomMap is
3140 * used only for object atoms, so it's sparse (wasting some stack
3141 * space) and as its name implies, you can't get non-object atoms
3144 atomIndex
= GET_ATOM_INDEX(pc
);
3145 atomMap
= fp
->objAtomMap
;
3146 atom
= atomMap
? atomMap
->vector
[atomIndex
] : NULL
;
3148 /* Let atom and obj denote the regexp (object) mapped by pc. */
3149 atom
= js_GetAtom(cx
, &script
->atomMap
, atomIndex
);
3150 JS_ASSERT(ATOM_IS_OBJECT(atom
));
3151 obj
= ATOM_TO_OBJECT(atom
);
3152 JS_ASSERT(OBJ_GET_CLASS(cx
, obj
) == &js_RegExpClass
);
3154 /* Compute the current global object in obj2. */
3155 obj2
= fp
->scopeChain
;
3156 while ((parent
= OBJ_GET_PARENT(cx
, obj2
)) != NULL
)
3160 * If obj's parent is not obj2, we must clone obj so that it
3161 * has the right parent, and therefore, the right prototype.
3163 * Yes, this means we assume that the correct RegExp.prototype
3164 * to which regexp instances (including literals) delegate can
3165 * be distinguished solely by the instance's parent, which was
3166 * set to the parent of the RegExp constructor function object
3167 * when the instance was created. In other words,
3169 * (/x/.__parent__ == RegExp.__parent__) implies
3170 * (/x/.__proto__ == RegExp.prototype)
3172 * (unless you assign a different object to RegExp.prototype
3173 * at runtime, in which case, ECMA doesn't specify operation,
3174 * and you get what you deserve).
3176 * This same coupling between instance parent and constructor
3177 * parent turns up elsewhere (see jsobj.c's FindConstructor,
3178 * js_ConstructObject, and js_NewObject). It's fundamental.
3180 if (OBJ_GET_PARENT(cx
, obj
) != obj2
) {
3181 obj
= js_CloneRegExpObject(cx
, obj
, obj2
);
3187 atom
= js_AtomizeObject(cx
, obj
, 0);
3195 * If fp->objAtomMap is null, initialize it now so we can map
3196 * atom (whether atom is newly created for a cloned object, or
3197 * the original atom mapped by script) for faster performance
3198 * next time through JSOP_OBJECT.
3201 jsatomid mapLength
= script
->atomMap
.length
;
3202 size_t vectorBytes
= mapLength
* sizeof(JSAtom
*);
3204 /* Allocate an override atom map from cx->stackPool. */
3205 JS_ARENA_ALLOCATE_CAST(atomMap
, JSAtomMap
*,
3207 sizeof(JSAtomMap
) + vectorBytes
);
3209 JS_ReportOutOfMemory(cx
);
3214 atomMap
->length
= mapLength
;
3215 atomMap
->vector
= (JSAtom
**)(atomMap
+ 1);
3216 memset(atomMap
->vector
, 0, vectorBytes
);
3217 fp
->objAtomMap
= atomMap
;
3219 atomMap
->vector
[atomIndex
] = atom
;
3222 atom
= GET_ATOM(cx
, script
, pc
);
3223 JS_ASSERT(ATOM_IS_OBJECT(atom
));
3225 rval
= ATOM_KEY(atom
);
3232 PUSH_OPND(JSVAL_ZERO
);
3237 PUSH_OPND(JSVAL_ONE
);
3242 PUSH_OPND(JSVAL_NULL
);
3247 PUSH_OPND(OBJECT_TO_JSVAL(fp
->thisp
));
3252 PUSH_OPND(JSVAL_FALSE
);
3257 PUSH_OPND(JSVAL_TRUE
);
3261 #if JS_HAS_SWITCH_STATEMENT
3262 case JSOP_TABLESWITCH
:
3264 len
= GET_JUMP_OFFSET(pc2
);
3267 * ECMAv2 forbids conversion of discriminant, so we will skip to
3268 * the default case if the discriminant isn't already an int jsval.
3269 * (This opcode is emitted only for dense jsint-domain switches.)
3271 if (cx
->version
== JSVERSION_DEFAULT
||
3272 cx
->version
>= JSVERSION_1_4
) {
3274 if (!JSVAL_IS_INT(rval
))
3276 i
= JSVAL_TO_INT(rval
);
3278 FETCH_INT(cx
, -1, i
);
3282 pc2
+= JUMP_OFFSET_LEN
;
3283 low
= GET_JUMP_OFFSET(pc2
);
3284 pc2
+= JUMP_OFFSET_LEN
;
3285 high
= GET_JUMP_OFFSET(pc2
);
3288 if ((jsuint
)i
< (jsuint
)(high
- low
+ 1)) {
3289 pc2
+= JUMP_OFFSET_LEN
+ JUMP_OFFSET_LEN
* i
;
3290 off
= (jsint
) GET_JUMP_OFFSET(pc2
);
3296 case JSOP_LOOKUPSWITCH
:
3299 len
= GET_JUMP_OFFSET(pc2
);
3301 if (!JSVAL_IS_NUMBER(lval
) &&
3302 !JSVAL_IS_STRING(lval
) &&
3303 !JSVAL_IS_BOOLEAN(lval
)) {
3307 pc2
+= JUMP_OFFSET_LEN
;
3308 npairs
= (jsint
) GET_ATOM_INDEX(pc2
);
3309 pc2
+= ATOM_INDEX_LEN
;
3311 #define SEARCH_PAIRS(MATCH_CODE) \
3313 atom = GET_ATOM(cx, script, pc2); \
3314 rval = ATOM_KEY(atom); \
3317 pc2 += ATOM_INDEX_LEN; \
3318 len = GET_JUMP_OFFSET(pc2); \
3321 pc2 += ATOM_INDEX_LEN + JUMP_OFFSET_LEN; \
3324 if (JSVAL_IS_STRING(lval
)) {
3325 str
= JSVAL_TO_STRING(lval
);
3327 match
= (JSVAL_IS_STRING(rval
) &&
3328 ((str2
= JSVAL_TO_STRING(rval
)) == str
||
3329 !js_CompareStrings(str2
, str
)));
3331 } else if (JSVAL_IS_DOUBLE(lval
)) {
3332 d
= *JSVAL_TO_DOUBLE(lval
);
3334 match
= (JSVAL_IS_DOUBLE(rval
) &&
3335 *JSVAL_TO_DOUBLE(rval
) == d
);
3339 match
= (lval
== rval
);
3345 case JSOP_TABLESWITCHX
:
3347 len
= GET_JUMPX_OFFSET(pc2
);
3350 * ECMAv2 forbids conversion of discriminant, so we will skip to
3351 * the default case if the discriminant isn't already an int jsval.
3352 * (This opcode is emitted only for dense jsint-domain switches.)
3354 if (cx
->version
== JSVERSION_DEFAULT
||
3355 cx
->version
>= JSVERSION_1_4
) {
3357 if (!JSVAL_IS_INT(rval
))
3359 i
= JSVAL_TO_INT(rval
);
3361 FETCH_INT(cx
, -1, i
);
3365 pc2
+= JUMPX_OFFSET_LEN
;
3366 low
= GET_JUMP_OFFSET(pc2
);
3367 pc2
+= JUMP_OFFSET_LEN
;
3368 high
= GET_JUMP_OFFSET(pc2
);
3371 if ((jsuint
)i
< (jsuint
)(high
- low
+ 1)) {
3372 pc2
+= JUMP_OFFSET_LEN
+ JUMPX_OFFSET_LEN
* i
;
3373 off
= (jsint
) GET_JUMPX_OFFSET(pc2
);
3379 case JSOP_LOOKUPSWITCHX
:
3382 len
= GET_JUMPX_OFFSET(pc2
);
3384 if (!JSVAL_IS_NUMBER(lval
) &&
3385 !JSVAL_IS_STRING(lval
) &&
3386 !JSVAL_IS_BOOLEAN(lval
)) {
3390 pc2
+= JUMPX_OFFSET_LEN
;
3391 npairs
= (jsint
) GET_ATOM_INDEX(pc2
);
3392 pc2
+= ATOM_INDEX_LEN
;
3394 #define SEARCH_EXTENDED_PAIRS(MATCH_CODE) \
3396 atom = GET_ATOM(cx, script, pc2); \
3397 rval = ATOM_KEY(atom); \
3400 pc2 += ATOM_INDEX_LEN; \
3401 len = GET_JUMPX_OFFSET(pc2); \
3404 pc2 += ATOM_INDEX_LEN + JUMPX_OFFSET_LEN; \
3407 if (JSVAL_IS_STRING(lval
)) {
3408 str
= JSVAL_TO_STRING(lval
);
3409 SEARCH_EXTENDED_PAIRS(
3410 match
= (JSVAL_IS_STRING(rval
) &&
3411 ((str2
= JSVAL_TO_STRING(rval
)) == str
||
3412 !js_CompareStrings(str2
, str
)));
3414 } else if (JSVAL_IS_DOUBLE(lval
)) {
3415 d
= *JSVAL_TO_DOUBLE(lval
);
3416 SEARCH_EXTENDED_PAIRS(
3417 match
= (JSVAL_IS_DOUBLE(rval
) &&
3418 *JSVAL_TO_DOUBLE(rval
) == d
);
3421 SEARCH_EXTENDED_PAIRS(
3422 match
= (lval
== rval
);
3425 #undef SEARCH_EXTENDED_PAIRS
3428 case JSOP_CONDSWITCH
:
3431 #endif /* JS_HAS_SWITCH_STATEMENT */
3433 #if JS_HAS_EXPORT_IMPORT
3434 case JSOP_EXPORTALL
:
3437 ida
= JS_Enumerate(cx
, obj
);
3441 for (i
= 0, j
= ida
->length
; i
< j
; i
++) {
3442 id
= ida
->vector
[i
];
3443 ok
= OBJ_LOOKUP_PROPERTY(cx
, obj
, id
, &obj2
, &prop
);
3448 ok
= OBJ_GET_ATTRIBUTES(cx
, obj
, id
, prop
, &attrs
);
3450 attrs
|= JSPROP_EXPORTED
;
3451 ok
= OBJ_SET_ATTRIBUTES(cx
, obj
, id
, prop
, &attrs
);
3453 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
3457 JS_DestroyIdArray(cx
, ida
);
3461 case JSOP_EXPORTNAME
:
3462 atom
= GET_ATOM(cx
, script
, pc
);
3466 ok
= OBJ_LOOKUP_PROPERTY(cx
, obj
, id
, &obj2
, &prop
);
3470 ok
= OBJ_DEFINE_PROPERTY(cx
, obj
, id
, JSVAL_VOID
, NULL
, NULL
,
3471 JSPROP_EXPORTED
, NULL
);
3473 ok
= OBJ_GET_ATTRIBUTES(cx
, obj
, id
, prop
, &attrs
);
3475 attrs
|= JSPROP_EXPORTED
;
3476 ok
= OBJ_SET_ATTRIBUTES(cx
, obj
, id
, prop
, &attrs
);
3478 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
3484 case JSOP_IMPORTALL
:
3485 id
= (jsid
)JSVAL_VOID
;
3486 PROPERTY_OP(-1, ok
= ImportProperty(cx
, obj
, id
));
3490 case JSOP_IMPORTPROP
:
3491 /* Get an immediate atom naming the property. */
3492 atom
= GET_ATOM(cx
, script
, pc
);
3494 PROPERTY_OP(-1, ok
= ImportProperty(cx
, obj
, id
));
3498 case JSOP_IMPORTELEM
:
3499 ELEMENT_OP(-1, ok
= ImportProperty(cx
, obj
, id
));
3502 #endif /* JS_HAS_EXPORT_IMPORT */
3505 switch (JS_HandleTrap(cx
, script
, pc
, &rval
)) {
3509 case JSTRAP_CONTINUE
:
3510 JS_ASSERT(JSVAL_IS_INT(rval
));
3511 op
= (JSOp
) JSVAL_TO_INT(rval
);
3512 JS_ASSERT((uintN
)op
< (uintN
)JSOP_LIMIT
);
3513 LOAD_INTERRUPT_HANDLER(rt
);
3518 #if JS_HAS_EXCEPTIONS
3520 cx
->throwing
= JS_TRUE
;
3521 cx
->exception
= rval
;
3524 #endif /* JS_HAS_EXCEPTIONS */
3527 LOAD_INTERRUPT_HANDLER(rt
);
3530 case JSOP_ARGUMENTS
:
3532 ok
= js_GetArgsValue(cx
, fp
, &rval
);
3539 id
= (jsid
) INT_TO_JSVAL(GET_ARGNO(pc
));
3541 ok
= js_GetArgsProperty(cx
, fp
, id
, &obj
, &rval
);
3546 * If arguments was not overridden by eval('arguments = ...'),
3547 * set obj to the magic cookie respected by JSOP_PUSHOBJ, just
3548 * in case this bytecode is part of an 'arguments[i](j, k)' or
3549 * similar such invocation sequence, where the function that
3550 * is invoked expects its 'this' parameter to be the caller's
3553 obj
= LAZY_ARGS_THISP
;
3558 #undef LAZY_ARGS_THISP
3561 id
= (jsid
) rt
->atomState
.lengthAtom
;
3563 ok
= js_GetArgsProperty(cx
, fp
, id
, &obj
, &rval
);
3570 slot
= GET_ARGNO(pc
);
3571 JS_ASSERT(slot
< fp
->fun
->nargs
);
3572 PUSH_OPND(fp
->argv
[slot
]);
3577 slot
= GET_ARGNO(pc
);
3578 JS_ASSERT(slot
< fp
->fun
->nargs
);
3579 vp
= &fp
->argv
[slot
];
3581 *vp
= FETCH_OPND(-1);
3586 slot
= GET_VARNO(pc
);
3587 JS_ASSERT(slot
< fp
->fun
->nvars
);
3588 PUSH_OPND(fp
->vars
[slot
]);
3593 slot
= GET_VARNO(pc
);
3594 JS_ASSERT(slot
< fp
->fun
->nvars
);
3595 vp
= &fp
->vars
[slot
];
3597 *vp
= FETCH_OPND(-1);
3606 atom
= GET_ATOM(cx
, script
, pc
);
3608 attrs
= JSPROP_ENUMERATE
;
3609 if (!(fp
->flags
& JSFRAME_EVAL
))
3610 attrs
|= JSPROP_PERMANENT
;
3611 if (op
== JSOP_DEFCONST
)
3612 attrs
|= JSPROP_READONLY
;
3614 /* Lookup id in order to check for redeclaration problems. */
3616 ok
= js_CheckRedeclaration(cx
, obj
, id
, attrs
, &defined
);
3620 /* Bind a variable only if it's not yet defined. */
3622 ok
= OBJ_DEFINE_PROPERTY(cx
, obj
, id
, JSVAL_VOID
, NULL
, NULL
,
3634 atom
= GET_ATOM(cx
, script
, pc
);
3635 obj
= ATOM_TO_OBJECT(atom
);
3636 fun
= (JSFunction
*) JS_GetPrivate(cx
, obj
);
3637 id
= (jsid
) fun
->atom
;
3640 * We must be at top-level (either outermost block that forms a
3641 * function's body, or a global) scope, not inside an expression
3642 * (JSOP_{ANON,NAMED}FUNOBJ) or compound statement (JSOP_CLOSURE)
3643 * in the same compilation unit (ECMA Program).
3645 * However, we could be in a Program being eval'd from inside a
3646 * with statement, so we need to distinguish variables object from
3647 * scope chain head. Hence the two assignments to parent below.
3648 * First we make sure the function object we're defining has the
3649 * right scope chain. Then we define its name in fp->varobj.
3651 * If static link is not current scope, clone fun's object to link
3652 * to the current scope via parent. This clause exists to enable
3653 * sharing of compiled functions among multiple equivalent scopes,
3654 * splitting the cost of compilation evenly among the scopes and
3655 * amortizing it over a number of executions. Examples include XUL
3656 * scripts and event handlers shared among Mozilla chrome windows,
3657 * and server-side JS user-defined functions shared among requests.
3659 * NB: The Script object exposes compile and exec in the language,
3660 * such that this clause introduces an incompatible change from old
3661 * JS versions that supported Script. Such a JS version supported
3662 * executing a script that defined and called functions scoped by
3663 * the compile-time static link, not by the exec-time scope chain.
3665 * We sacrifice compatibility, breaking such scripts, in order to
3666 * promote compile-cost sharing and amortizing, and because Script
3667 * is not and will not be standardized.
3669 parent
= fp
->scopeChain
;
3670 if (OBJ_GET_PARENT(cx
, obj
) != parent
) {
3671 obj
= js_CloneFunctionObject(cx
, obj
, parent
);
3679 * ECMA requires functions defined when entering Global code to be
3680 * permanent, and functions defined when entering Eval code to be
3683 attrs
= JSPROP_ENUMERATE
;
3684 if (!(fp
->flags
& JSFRAME_EVAL
))
3685 attrs
|= JSPROP_PERMANENT
;
3688 * Load function flags that are also property attributes. Getters
3689 * and setters do not need a slot, their value is stored elsewhere
3690 * in the property itself, not in obj->slots.
3692 flags
= fun
->flags
& (JSFUN_GETTER
| JSFUN_SETTER
);
3694 attrs
|= flags
| JSPROP_SHARED
;
3697 * Check for a const property of the same name -- or any kind
3698 * of property if executing with the strict option. We check
3699 * here at runtime as well as at compile-time, to handle eval
3700 * as well as multiple HTML script tags.
3702 parent
= fp
->varobj
;
3703 ok
= js_CheckRedeclaration(cx
, parent
, id
, attrs
, &cond
);
3707 ok
= OBJ_DEFINE_PROPERTY(cx
, parent
, id
,
3708 flags
? JSVAL_VOID
: OBJECT_TO_JSVAL(obj
),
3709 (flags
& JSFUN_GETTER
)
3710 ? (JSPropertyOp
) obj
3712 (flags
& JSFUN_SETTER
)
3713 ? (JSPropertyOp
) obj
3722 #if JS_HAS_LEXICAL_CLOSURE
3723 case JSOP_DEFLOCALFUN
:
3725 * Define a local function (i.e., one nested at the top level of
3726 * another function), parented by the current scope chain, and
3727 * stored in a local variable slot that the compiler allocated.
3728 * This is an optimization over JSOP_DEFFUN that avoids requiring
3729 * a call object for the outer function's activation.
3732 slot
= GET_VARNO(pc2
);
3734 atom
= GET_ATOM(cx
, script
, pc2
);
3735 obj
= ATOM_TO_OBJECT(atom
);
3736 fun
= (JSFunction
*) JS_GetPrivate(cx
, obj
);
3738 parent
= fp
->scopeChain
;
3739 if (OBJ_GET_PARENT(cx
, obj
) != parent
) {
3740 obj
= js_CloneFunctionObject(cx
, obj
, parent
);
3746 fp
->vars
[slot
] = OBJECT_TO_JSVAL(obj
);
3749 case JSOP_ANONFUNOBJ
:
3750 /* Push the specified function object literal. */
3751 atom
= GET_ATOM(cx
, script
, pc
);
3752 obj
= ATOM_TO_OBJECT(atom
);
3754 /* If re-parenting, push a clone of the function object. */
3755 parent
= fp
->scopeChain
;
3756 if (OBJ_GET_PARENT(cx
, obj
) != parent
) {
3757 obj
= js_CloneFunctionObject(cx
, obj
, parent
);
3763 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
3766 case JSOP_NAMEDFUNOBJ
:
3767 /* ECMA ed. 3 FunctionExpression: function Identifier [etc.]. */
3768 atom
= GET_ATOM(cx
, script
, pc
);
3769 rval
= ATOM_KEY(atom
);
3770 JS_ASSERT(JSVAL_IS_FUNCTION(cx
, rval
));
3773 * 1. Create a new object as if by the expression new Object().
3774 * 2. Add Result(1) to the front of the scope chain.
3776 * Step 2 is achieved by making the new object's parent be the
3777 * current scope chain, and then making the new object the parent
3778 * of the Function object clone.
3781 parent
= js_ConstructObject(cx
, &js_ObjectClass
, NULL
,
3782 fp
->scopeChain
, 0, NULL
);
3789 * 3. Create a new Function object as specified in section 13.2
3790 * with [parameters and body specified by the function expression
3791 * that was parsed by the compiler into a Function object, and
3792 * saved in the script's atom map].
3794 obj
= js_CloneFunctionObject(cx
, JSVAL_TO_OBJECT(rval
), parent
);
3801 * 4. Create a property in the object Result(1). The property's
3802 * name is [fun->atom, the identifier parsed by the compiler],
3803 * value is Result(3), and attributes are { DontDelete, ReadOnly }.
3805 fun
= (JSFunction
*) JS_GetPrivate(cx
, obj
);
3806 attrs
= fun
->flags
& (JSFUN_GETTER
| JSFUN_SETTER
);
3808 attrs
|= JSPROP_SHARED
;
3809 ok
= OBJ_DEFINE_PROPERTY(cx
, parent
, (jsid
)fun
->atom
,
3810 attrs
? JSVAL_VOID
: OBJECT_TO_JSVAL(obj
),
3811 (attrs
& JSFUN_GETTER
)
3812 ? (JSPropertyOp
) obj
3814 (attrs
& JSFUN_SETTER
)
3815 ? (JSPropertyOp
) obj
3818 JSPROP_ENUMERATE
| JSPROP_PERMANENT
|
3822 cx
->newborn
[GCX_OBJECT
] = NULL
;
3827 * 5. Remove Result(1) from the front of the scope chain [no-op].
3828 * 6. Return Result(3).
3830 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
3835 * ECMA ed. 3 extension: a named function expression in a compound
3836 * statement (not at the top statement level of global code, or at
3837 * the top level of a function body).
3839 * Get immediate operand atom, which is a function object literal.
3840 * From it, get the function to close.
3842 atom
= GET_ATOM(cx
, script
, pc
);
3843 JS_ASSERT(JSVAL_IS_FUNCTION(cx
, ATOM_KEY(atom
)));
3844 obj
= ATOM_TO_OBJECT(atom
);
3847 * Clone the function object with the current scope chain as the
3848 * clone's parent. The original function object is the prototype
3849 * of the clone. Do this only if re-parenting; the compiler may
3850 * have seen the right parent already and created a sufficiently
3851 * well-scoped function object.
3854 parent
= fp
->scopeChain
;
3855 if (OBJ_GET_PARENT(cx
, obj
) != parent
) {
3856 obj
= js_CloneFunctionObject(cx
, obj
, parent
);
3864 * Make a property in fp->varobj with id fun->atom and value obj,
3865 * unless fun is a getter or setter (in which case, obj is cast to
3866 * a JSPropertyOp and passed accordingly).
3868 fun
= (JSFunction
*) JS_GetPrivate(cx
, obj
);
3869 attrs
= fun
->flags
& (JSFUN_GETTER
| JSFUN_SETTER
);
3871 attrs
|= JSPROP_SHARED
;
3872 ok
= OBJ_DEFINE_PROPERTY(cx
, fp
->varobj
, (jsid
)fun
->atom
,
3873 attrs
? JSVAL_VOID
: OBJECT_TO_JSVAL(obj
),
3874 (attrs
& JSFUN_GETTER
)
3875 ? (JSPropertyOp
) obj
3877 (attrs
& JSFUN_SETTER
)
3878 ? (JSPropertyOp
) obj
3880 attrs
| JSPROP_ENUMERATE
,
3883 cx
->newborn
[GCX_OBJECT
] = NULL
;
3887 #endif /* JS_HAS_LEXICAL_CLOSURE */
3889 #if JS_HAS_GETTER_SETTER
3892 JS_ASSERT(len
== 1);
3894 cs
= &js_CodeSpec
[op2
];
3899 atom
= GET_ATOM(cx
, script
, pc
);
3902 rval
= FETCH_OPND(i
);
3906 rval
= FETCH_OPND(-1);
3908 FETCH_ELEMENT_ID(i
, id
);
3910 lval
= FETCH_OPND(i
-1);
3911 VALUE_TO_OBJECT(cx
, lval
, obj
);
3914 #if JS_HAS_INITIALIZERS
3916 JS_ASSERT(sp
- fp
->spbase
>= 2);
3918 rval
= FETCH_OPND(i
);
3919 atom
= GET_ATOM(cx
, script
, pc
);
3924 JS_ASSERT(sp
- fp
->spbase
>= 3);
3925 rval
= FETCH_OPND(-1);
3927 FETCH_ELEMENT_ID(i
, id
);
3929 lval
= FETCH_OPND(i
-1);
3930 JS_ASSERT(JSVAL_IS_OBJECT(lval
));
3931 obj
= JSVAL_TO_OBJECT(lval
);
3933 #endif /* JS_HAS_INITIALIZERS */
3939 if (JS_TypeOfValue(cx
, rval
) != JSTYPE_FUNCTION
) {
3940 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
3941 JSMSG_BAD_GETTER_OR_SETTER
,
3950 * Getters and setters are just like watchpoints from an access
3951 * control point of view.
3954 ok
= OBJ_CHECK_ACCESS(cx
, obj
, id
, JSACC_WATCH
, &rtmp
, &attrs
);
3958 if (op
== JSOP_GETTER
) {
3959 getter
= (JSPropertyOp
) JSVAL_TO_OBJECT(rval
);
3961 attrs
= JSPROP_GETTER
;
3964 setter
= (JSPropertyOp
) JSVAL_TO_OBJECT(rval
);
3965 attrs
= JSPROP_SETTER
;
3967 attrs
|= JSPROP_ENUMERATE
| JSPROP_SHARED
;
3969 /* Check for a readonly or permanent property of the same name. */
3970 ok
= js_CheckRedeclaration(cx
, obj
, id
, attrs
, &cond
);
3974 ok
= OBJ_DEFINE_PROPERTY(cx
, obj
, id
, JSVAL_VOID
, getter
, setter
,
3981 STORE_OPND(-1, rval
);
3983 #endif /* JS_HAS_GETTER_SETTER */
3985 #if JS_HAS_INITIALIZERS
3992 if (--fp
->sharpDepth
== 0)
3993 fp
->sharpArray
= NULL
;
3995 /* Re-set the newborn root to the top of this object tree. */
3996 JS_ASSERT(sp
- fp
->spbase
>= 1);
3997 lval
= FETCH_OPND(-1);
3998 JS_ASSERT(JSVAL_IS_OBJECT(lval
));
3999 cx
->newborn
[GCX_OBJECT
] = JSVAL_TO_GCTHING(lval
);
4003 /* Pop the property's value into rval. */
4004 JS_ASSERT(sp
- fp
->spbase
>= 2);
4005 rval
= FETCH_OPND(-1);
4007 /* Get the immediate property name into id. */
4008 atom
= GET_ATOM(cx
, script
, pc
);
4014 /* Pop the element's value into rval. */
4015 JS_ASSERT(sp
- fp
->spbase
>= 3);
4016 rval
= FETCH_OPND(-1);
4018 /* Pop and conditionally atomize the element id. */
4019 FETCH_ELEMENT_ID(-2, id
);
4023 /* Find the object being initialized at top of stack. */
4024 lval
= FETCH_OPND(i
-1);
4025 JS_ASSERT(JSVAL_IS_OBJECT(lval
));
4026 obj
= JSVAL_TO_OBJECT(lval
);
4028 /* Set the property named by obj[id] to rval. */
4030 ok
= OBJ_SET_PROPERTY(cx
, obj
, id
, &rval
);
4036 #if JS_HAS_SHARP_VARS
4039 obj
= fp
->sharpArray
;
4041 obj
= js_NewArrayObject(cx
, 0, NULL
);
4046 fp
->sharpArray
= obj
;
4048 i
= (jsint
) GET_ATOM_INDEX(pc
);
4049 id
= (jsid
) INT_TO_JSVAL(i
);
4050 rval
= FETCH_OPND(-1);
4051 if (JSVAL_IS_PRIMITIVE(rval
)) {
4053 JS_snprintf(numBuf
, sizeof numBuf
, "%u", (unsigned) i
);
4054 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4055 JSMSG_BAD_SHARP_DEF
, numBuf
);
4059 ok
= OBJ_SET_PROPERTY(cx
, obj
, id
, &rval
);
4065 i
= (jsint
) GET_ATOM_INDEX(pc
);
4066 id
= (jsid
) INT_TO_JSVAL(i
);
4067 obj
= fp
->sharpArray
;
4072 ok
= OBJ_GET_PROPERTY(cx
, obj
, id
, &rval
);
4076 if (!JSVAL_IS_OBJECT(rval
)) {
4078 JS_snprintf(numBuf
, sizeof numBuf
, "%u", (unsigned) i
);
4079 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4080 JSMSG_BAD_SHARP_USE
, numBuf
);
4086 #endif /* JS_HAS_SHARP_VARS */
4087 #endif /* JS_HAS_INITIALIZERS */
4089 #if JS_HAS_EXCEPTIONS
4090 /* No-ops for ease of decompilation and jit'ing. */
4095 /* Reset the stack to the given depth. */
4097 i
= (jsint
) GET_ATOM_INDEX(pc
);
4099 sp
= fp
->spbase
+ i
;
4103 i
= PTRDIFF(pc
, script
->main
, jsbytecode
) + len
;
4104 len
= GET_JUMP_OFFSET(pc
);
4105 PUSH(INT_TO_JSVAL(i
));
4109 i
= PTRDIFF(pc
, script
->main
, jsbytecode
) + len
;
4110 len
= GET_JUMPX_OFFSET(pc
);
4111 PUSH(INT_TO_JSVAL(i
));
4116 JS_ASSERT(JSVAL_IS_INT(rval
));
4117 i
= JSVAL_TO_INT(rval
);
4118 pc
= script
->main
+ i
;
4122 case JSOP_EXCEPTION
:
4123 PUSH(cx
->exception
);
4127 cx
->throwing
= JS_TRUE
;
4128 cx
->exception
= POP_OPND();
4130 /* let the code at out try to catch the exception. */
4133 case JSOP_INITCATCHVAR
:
4134 /* Pop the property's value into rval. */
4135 JS_ASSERT(sp
- fp
->spbase
>= 2);
4138 /* Get the immediate catch variable name into id. */
4139 atom
= GET_ATOM(cx
, script
, pc
);
4142 /* Find the object being initialized at top of stack. */
4143 lval
= FETCH_OPND(-1);
4144 JS_ASSERT(JSVAL_IS_OBJECT(lval
));
4145 obj
= JSVAL_TO_OBJECT(lval
);
4147 /* Define obj[id] to contain rval and to be permanent. */
4149 ok
= OBJ_DEFINE_PROPERTY(cx
, obj
, id
, rval
, NULL
, NULL
,
4150 JSPROP_PERMANENT
, NULL
);
4154 #endif /* JS_HAS_EXCEPTIONS */
4156 #if JS_HAS_INSTANCEOF
4157 case JSOP_INSTANCEOF
:
4158 rval
= FETCH_OPND(-1);
4159 if (JSVAL_IS_PRIMITIVE(rval
)) {
4161 str
= js_DecompileValueGenerator(cx
, -1, rval
, NULL
);
4163 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4164 JSMSG_BAD_INSTANCEOF_RHS
,
4165 JS_GetStringBytes(str
));
4170 obj
= JSVAL_TO_OBJECT(rval
);
4171 lval
= FETCH_OPND(-2);
4173 if (obj
->map
->ops
->hasInstance
) {
4175 ok
= obj
->map
->ops
->hasInstance(cx
, obj
, lval
, &cond
);
4180 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond
));
4182 #endif /* JS_HAS_INSTANCEOF */
4184 #if JS_HAS_DEBUGGER_KEYWORD
4187 JSTrapHandler handler
= rt
->debuggerHandler
;
4190 switch (handler(cx
, script
, pc
, &rval
,
4191 rt
->debuggerHandlerData
)) {
4195 case JSTRAP_CONTINUE
:
4200 #if JS_HAS_EXCEPTIONS
4202 cx
->throwing
= JS_TRUE
;
4203 cx
->exception
= rval
;
4206 #endif /* JS_HAS_EXCEPTIONS */
4209 LOAD_INTERRUPT_HANDLER(rt
);
4213 #endif /* JS_HAS_DEBUGGER_KEYWORD */
4217 JS_snprintf(numBuf
, sizeof numBuf
, "%d", op
);
4218 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4219 JSMSG_BAD_BYTECODE
, numBuf
);
4236 for (n
= -ndefs
; n
< 0; n
++) {
4237 str
= js_DecompileValueGenerator(cx
, n
, sp
[n
], NULL
);
4239 fprintf(tracefp
, "%s %s",
4240 (n
== -ndefs
) ? " output:" : ",",
4241 JS_GetStringBytes(str
));
4244 fprintf(tracefp
, " @ %d\n", sp
- fp
->spbase
);
4246 fprintf(tracefp
, " stack: ");
4247 for (siter
= fp
->spbase
; siter
< sp
; siter
++) {
4248 str
= js_ValueToSource(cx
, *siter
);
4249 fprintf(tracefp
, "%s ",
4250 str
? JS_GetStringBytes(str
) : "<null>");
4252 fputc('\n', tracefp
);
4258 #if JS_HAS_EXCEPTIONS
4260 * Has an exception been raised?
4262 if (!ok
&& cx
->throwing
) {
4264 * Call debugger throw hook if set (XXX thread safety?).
4266 JSTrapHandler handler
= rt
->throwHook
;
4269 switch (handler(cx
, script
, pc
, &rval
, rt
->throwHookData
)) {
4271 cx
->throwing
= JS_FALSE
;
4275 cx
->throwing
= JS_FALSE
;
4279 cx
->exception
= rval
;
4280 case JSTRAP_CONTINUE
:
4283 LOAD_INTERRUPT_HANDLER(rt
);
4287 * Look for a try block within this frame that can catch the exception.
4289 SCRIPT_FIND_CATCH_START(script
, pc
, pc
);
4292 cx
->throwing
= JS_FALSE
; /* caught */
4301 * Check whether control fell off the end of a lightweight function, or an
4302 * exception thrown under such a function was not caught by it. If so, go
4303 * to the inline code under JSOP_RETURN.
4305 if (inlineCallCount
)
4309 * Reset sp before freeing stack slots, because our caller may GC soon.
4310 * Clear spbase to indicate that we've popped the 2 * depth operand slots.
4311 * Restore the previous frame's execution state.
4313 fp
->sp
= fp
->spbase
;
4315 js_FreeRawStack(cx
, mark
);
4316 if (cx
->version
== currentVersion
&& currentVersion
!= originalVersion
)
4317 JS_SetVersion(cx
, originalVersion
);
4323 const char *printable
= js_AtomToPrintableString(cx
, atom
);
4325 js_ReportIsNotDefined(cx
, printable
);