1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=79:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is Mozilla Communicator client code, released
20 * The Initial Developer of the Original Code is
21 * Netscape Communications Corporation.
22 * Portions created by the Initial Developer are Copyright (C) 1998
23 * the Initial Developer. All Rights Reserved.
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 /* This file needs to be included in possibly multiple places. */
43 #if JS_THREADED_INTERP
45 #else /* !JS_THREADED_INTERP */
47 JS_ASSERT(switchMask
== -1);
48 #endif /* !JS_THREADED_INTERP */
50 bool moreInterrupts
= false;
51 JSTrapHandler handler
= cx
->debugHooks
->interruptHandler
;
54 if (TRACE_RECORDER(cx
))
55 js_AbortRecording(cx
, "interrupt handler");
57 switch (handler(cx
, script
, regs
.pc
, &rval
,
58 cx
->debugHooks
->interruptHandlerData
)) {
68 cx
->throwing
= JS_TRUE
;
73 moreInterrupts
= true;
77 TraceRecorder
* tr
= TRACE_RECORDER(cx
);
79 JSRecordingStatus status
= TraceRecorder::monitorRecording(cx
, tr
, op
);
82 moreInterrupts
= true;
85 atoms
= COMMON_ATOMS_START(&rt
->atomState
);
87 DO_OP(); /* keep interrupting for op. */
90 // The code at 'error:' aborts the recording.
95 JS_NOT_REACHED("Bad recording status");
98 #endif /* !JS_TRACER */
100 #if JS_THREADED_INTERP
103 js_ExitTraceVisState(cx
, R_ABORT
);
105 jumpTable
= moreInterrupts
? interruptJumpTable
: normalJumpTable
;
106 JS_EXTENSION_(goto *normalJumpTable
[op
]);
108 switchMask
= moreInterrupts
? -1 : 0;
114 /* No-ops for ease of decompilation. */
115 ADD_EMPTY_CASE(JSOP_NOP
)
116 ADD_EMPTY_CASE(JSOP_CONDSWITCH
)
117 ADD_EMPTY_CASE(JSOP_TRY
)
118 #if JS_HAS_XML_SUPPORT
119 ADD_EMPTY_CASE(JSOP_STARTXML
)
120 ADD_EMPTY_CASE(JSOP_STARTXMLEXPR
)
124 /* ADD_EMPTY_CASE is not used here as JSOP_LINENO_LENGTH == 3. */
125 BEGIN_CASE(JSOP_LINENO
)
126 END_CASE(JSOP_LINENO
)
128 BEGIN_CASE(JSOP_PUSH
)
129 PUSH_OPND(JSVAL_VOID
);
136 BEGIN_CASE(JSOP_POPN
)
137 regs
.sp
-= GET_UINT16(regs
.pc
);
139 JS_ASSERT(StackBase(fp
) <= regs
.sp
);
140 obj
= fp
->blockChain
;
142 OBJ_BLOCK_DEPTH(cx
, obj
) + OBJ_BLOCK_COUNT(cx
, obj
)
143 <= (size_t) (regs
.sp
- StackBase(fp
)));
144 for (obj
= fp
->scopeChain
; obj
; obj
= OBJ_GET_PARENT(cx
, obj
)) {
145 clasp
= OBJ_GET_CLASS(cx
, obj
);
146 if (clasp
!= &js_BlockClass
&& clasp
!= &js_WithClass
)
148 if (obj
->getAssignedPrivate() != fp
)
150 JS_ASSERT(StackBase(fp
) + OBJ_BLOCK_DEPTH(cx
, obj
)
151 + ((clasp
== &js_BlockClass
)
152 ? OBJ_BLOCK_COUNT(cx
, obj
)
159 BEGIN_CASE(JSOP_SETRVAL
)
160 BEGIN_CASE(JSOP_POPV
)
161 ASSERT_NOT_THROWING(cx
);
162 fp
->rval
= POP_OPND();
165 BEGIN_CASE(JSOP_ENTERWITH
)
166 if (!js_EnterWith(cx
, -1))
170 * We must ensure that different "with" blocks have different
171 * stack depth associated with them. This allows the try handler
172 * search to properly recover the scope chain. Thus we must keep
173 * the stack at least at the current level.
175 * We set sp[-1] to the current "with" object to help asserting
176 * the enter/leave balance in [leavewith].
178 regs
.sp
[-1] = OBJECT_TO_JSVAL(fp
->scopeChain
);
179 END_CASE(JSOP_ENTERWITH
)
181 BEGIN_CASE(JSOP_LEAVEWITH
)
182 JS_ASSERT(regs
.sp
[-1] == OBJECT_TO_JSVAL(fp
->scopeChain
));
185 END_CASE(JSOP_LEAVEWITH
)
187 BEGIN_CASE(JSOP_RETURN
)
188 fp
->rval
= POP_OPND();
191 BEGIN_CASE(JSOP_RETRVAL
) /* fp->rval already set */
192 BEGIN_CASE(JSOP_STOP
)
194 * When the inlined frame exits with an exception or an error, ok
195 * will be false after the inline_return label.
197 ASSERT_NOT_THROWING(cx
);
202 * If we are at the end of an imacro, return to its caller in
205 JS_ASSERT(op
== JSOP_STOP
);
208 JS_ASSERT((uintN
)(regs
.sp
- fp
->slots
) <= script
->nslots
);
209 regs
.pc
= fp
->imacpc
+ js_CodeSpec
[*fp
->imacpc
].length
;
211 atoms
= script
->atomMap
.vector
;
216 JS_ASSERT(regs
.sp
== StackBase(fp
));
217 if ((fp
->flags
& JSFRAME_CONSTRUCTING
) &&
218 JSVAL_IS_PRIMITIVE(fp
->rval
)) {
220 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
221 JSMSG_BAD_NEW_RESULT
,
222 js_ValueToPrintableString(cx
, rval
));
225 fp
->rval
= OBJECT_TO_JSVAL(fp
->thisp
);
231 JSInlineFrame
*ifp
= (JSInlineFrame
*) fp
;
232 void *hookData
= ifp
->hookData
;
234 JS_ASSERT(!fp
->blockChain
);
235 JS_ASSERT(!js_IsActiveWithOrBlock(cx
, fp
->scopeChain
, 0));
237 if (script
->staticLevel
< JS_DISPLAY_SIZE
)
238 cx
->display
[script
->staticLevel
] = fp
->displaySave
;
241 JSInterpreterHook hook
;
244 hook
= cx
->debugHooks
->callHook
;
247 * Do not pass &ok directly as exposing the address
248 * inhibits optimizations and uninitialised warnings.
251 hook(cx
, fp
, JS_FALSE
, &status
, hookData
);
253 CHECK_INTERRUPT_HANDLER();
258 * If fp has a call object, sync values and clear the back-
259 * pointer. This can happen for a lightweight function if it
260 * calls eval unexpectedly (in a way that is hidden from the
261 * compiler). See bug 325540.
263 fp
->putActivationObjects(cx
);
265 #ifdef INCLUDE_MOZILLA_DTRACE
266 /* DTrace function return, inlines */
267 if (JAVASCRIPT_FUNCTION_RVAL_ENABLED())
268 jsdtrace_function_rval(cx
, fp
, fp
->fun
, &fp
->rval
);
269 if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
270 jsdtrace_function_return(cx
, fp
, fp
->fun
);
273 /* Restore context version only if callee hasn't set version. */
274 if (JS_LIKELY(cx
->version
== currentVersion
)) {
275 currentVersion
= ifp
->callerVersion
;
276 if (currentVersion
!= cx
->version
)
277 js_SetVersion(cx
, currentVersion
);
281 * If inline-constructing, replace primitive rval with the new
282 * object passed in via |this|, and instrument this constructor
285 if (fp
->flags
& JSFRAME_CONSTRUCTING
) {
286 if (JSVAL_IS_PRIMITIVE(fp
->rval
))
287 fp
->rval
= OBJECT_TO_JSVAL(fp
->thisp
);
288 JS_RUNTIME_METER(cx
->runtime
, constructs
);
291 /* Restore caller's registers. */
292 regs
= ifp
->callerRegs
;
294 /* Store the return value in the caller's operand frame. */
295 regs
.sp
-= 1 + (size_t) ifp
->frame
.argc
;
296 regs
.sp
[-1] = fp
->rval
;
298 /* Restore cx->fp and release the inline frame's space. */
299 cx
->fp
= fp
= fp
->down
;
300 JS_ASSERT(fp
->regs
== &ifp
->callerRegs
);
302 JS_ARENA_RELEASE(&cx
->stackPool
, ifp
->mark
);
304 /* Restore the calling script's interpreter registers. */
306 atoms
= FrameAtomBase(cx
, fp
);
308 /* Resume execution in the calling frame. */
312 JS_ASSERT(js_CodeSpec
[js_GetOpcode(cx
, script
, regs
.pc
)].length
313 == JSOP_CALL_LENGTH
);
314 len
= JSOP_CALL_LENGTH
;
321 BEGIN_CASE(JSOP_DEFAULT
)
324 BEGIN_CASE(JSOP_GOTO
)
325 len
= GET_JUMP_OFFSET(regs
.pc
);
329 BEGIN_CASE(JSOP_IFEQ
)
330 POP_BOOLEAN(cx
, rval
, cond
);
331 if (cond
== JS_FALSE
) {
332 len
= GET_JUMP_OFFSET(regs
.pc
);
337 BEGIN_CASE(JSOP_IFNE
)
338 POP_BOOLEAN(cx
, rval
, cond
);
339 if (cond
!= JS_FALSE
) {
340 len
= GET_JUMP_OFFSET(regs
.pc
);
346 POP_BOOLEAN(cx
, rval
, cond
);
347 if (cond
== JS_TRUE
) {
348 len
= GET_JUMP_OFFSET(regs
.pc
);
355 POP_BOOLEAN(cx
, rval
, cond
);
356 if (cond
== JS_FALSE
) {
357 len
= GET_JUMP_OFFSET(regs
.pc
);
363 BEGIN_CASE(JSOP_DEFAULTX
)
366 BEGIN_CASE(JSOP_GOTOX
)
367 len
= GET_JUMPX_OFFSET(regs
.pc
);
369 END_CASE(JSOP_GOTOX
);
371 BEGIN_CASE(JSOP_IFEQX
)
372 POP_BOOLEAN(cx
, rval
, cond
);
373 if (cond
== JS_FALSE
) {
374 len
= GET_JUMPX_OFFSET(regs
.pc
);
379 BEGIN_CASE(JSOP_IFNEX
)
380 POP_BOOLEAN(cx
, rval
, cond
);
381 if (cond
!= JS_FALSE
) {
382 len
= GET_JUMPX_OFFSET(regs
.pc
);
388 POP_BOOLEAN(cx
, rval
, cond
);
389 if (cond
== JS_TRUE
) {
390 len
= GET_JUMPX_OFFSET(regs
.pc
);
396 BEGIN_CASE(JSOP_ANDX
)
397 POP_BOOLEAN(cx
, rval
, cond
);
398 if (cond
== JS_FALSE
) {
399 len
= GET_JUMPX_OFFSET(regs
.pc
);
406 * If the index value at sp[n] is not an int that fits in a jsval, it could
407 * be an object (an XML QName, AttributeName, or AnyName), but only if we are
408 * compiling with JS_HAS_XML_SUPPORT. Otherwise convert the index value to a
411 #define FETCH_ELEMENT_ID(obj, n, id) \
413 jsval idval_ = FETCH_OPND(n); \
414 if (JSVAL_IS_INT(idval_)) { \
415 id = INT_JSVAL_TO_JSID(idval_); \
417 if (!js_InternNonIntElementId(cx, obj, idval_, &id)) \
419 regs.sp[n] = ID_TO_VALUE(id); \
423 #define TRY_BRANCH_AFTER_COND(cond,spdec) \
426 JS_ASSERT(js_CodeSpec[op].length == 1); \
427 diff_ = (uintN) regs.pc[1] - (uintN) JSOP_IFEQ; \
430 if (cond == (diff_ != 0)) { \
432 len = GET_JUMP_OFFSET(regs.pc); \
435 len = 1 + JSOP_IFEQ_LENGTH; \
441 rval
= FETCH_OPND(-1);
442 if (JSVAL_IS_PRIMITIVE(rval
)) {
443 js_ReportValueError(cx
, JSMSG_IN_NOT_OBJECT
, -1, rval
, NULL
);
446 obj
= JSVAL_TO_OBJECT(rval
);
447 FETCH_ELEMENT_ID(obj
, -2, id
);
448 if (!obj
->lookupProperty(cx
, id
, &obj2
, &prop
))
452 obj2
->dropProperty(cx
, prop
);
453 TRY_BRANCH_AFTER_COND(cond
, 2);
455 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond
));
458 BEGIN_CASE(JSOP_ITER
)
459 JS_ASSERT(regs
.sp
> StackBase(fp
));
461 if (!js_ValueToIterator(cx
, flags
, ®s
.sp
[-1]))
463 CHECK_INTERRUPT_HANDLER();
464 JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs
.sp
[-1]));
468 BEGIN_CASE(JSOP_NEXTITER
)
469 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
470 JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs
.sp
[-2]));
471 if (!js_CallIteratorNext(cx
, JSVAL_TO_OBJECT(regs
.sp
[-2]), ®s
.sp
[-1]))
473 CHECK_INTERRUPT_HANDLER();
474 rval
= BOOLEAN_TO_JSVAL(regs
.sp
[-1] != JSVAL_HOLE
);
476 END_CASE(JSOP_NEXTITER
)
478 BEGIN_CASE(JSOP_ENDITER
)
480 * Decrease the stack pointer even when !ok -- see comments in the
481 * exception capturing code for details.
483 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
484 ok
= js_CloseIterator(cx
, regs
.sp
[-2]);
488 END_CASE(JSOP_ENDITER
)
490 BEGIN_CASE(JSOP_FORARG
)
491 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
492 slot
= GET_ARGNO(regs
.pc
);
493 JS_ASSERT(slot
< fp
->fun
->nargs
);
494 fp
->argv
[slot
] = regs
.sp
[-1];
495 END_CASE(JSOP_FORARG
)
497 BEGIN_CASE(JSOP_FORLOCAL
)
498 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
499 slot
= GET_SLOTNO(regs
.pc
);
500 JS_ASSERT(slot
< fp
->script
->nslots
);
501 fp
->slots
[slot
] = regs
.sp
[-1];
502 END_CASE(JSOP_FORLOCAL
)
504 BEGIN_CASE(JSOP_FORNAME
)
505 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
507 id
= ATOM_TO_JSID(atom
);
508 if (!js_FindProperty(cx
, id
, &obj
, &obj2
, &prop
))
511 obj2
->dropProperty(cx
, prop
);
512 ok
= obj
->setProperty(cx
, id
, ®s
.sp
[-1]);
515 END_CASE(JSOP_FORNAME
)
517 BEGIN_CASE(JSOP_FORPROP
)
518 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
520 id
= ATOM_TO_JSID(atom
);
521 FETCH_OBJECT(cx
, -1, lval
, obj
);
522 ok
= obj
->setProperty(cx
, id
, ®s
.sp
[-2]);
526 END_CASE(JSOP_FORPROP
)
528 BEGIN_CASE(JSOP_FORELEM
)
530 * JSOP_FORELEM simply dups the property identifier at top of stack
531 * and lets the subsequent JSOP_ENUMELEM opcode sequence handle the
532 * left-hand side expression evaluation and assignment. This opcode
533 * exists solely to help the decompiler.
535 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
536 rval
= FETCH_OPND(-1);
538 END_CASE(JSOP_FORELEM
)
541 JS_ASSERT(regs
.sp
> StackBase(fp
));
542 rval
= FETCH_OPND(-1);
546 BEGIN_CASE(JSOP_DUP2
)
547 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
548 lval
= FETCH_OPND(-2);
549 rval
= FETCH_OPND(-1);
554 BEGIN_CASE(JSOP_SWAP
)
555 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
556 lval
= FETCH_OPND(-2);
557 rval
= FETCH_OPND(-1);
558 STORE_OPND(-1, lval
);
559 STORE_OPND(-2, rval
);
562 BEGIN_CASE(JSOP_PICK
)
564 JS_ASSERT(regs
.sp
- (i
+1) >= StackBase(fp
));
565 lval
= regs
.sp
[-(i
+1)];
566 memmove(regs
.sp
- (i
+1), regs
.sp
- i
, sizeof(jsval
)*i
);
570 #define PROPERTY_OP(n, call) \
572 /* Fetch the left part and resolve it to a non-null object. */ \
573 FETCH_OBJECT(cx, n, lval, obj); \
575 /* Get or set the property. */ \
580 #define ELEMENT_OP(n, call) \
582 /* Fetch the left part and resolve it to a non-null object. */ \
583 FETCH_OBJECT(cx, n - 1, lval, obj); \
585 /* Fetch index and convert it to id suitable for use with obj. */ \
586 FETCH_ELEMENT_ID(obj, n, id); \
588 /* Get or set the element. */ \
593 #define NATIVE_GET(cx,obj,pobj,sprop,vp) \
595 if (SPROP_HAS_STUB_GETTER(sprop)) { \
596 /* Fast path for Object instance properties. */ \
597 JS_ASSERT((sprop)->slot != SPROP_INVALID_SLOT || \
598 !SPROP_HAS_STUB_SETTER(sprop)); \
599 *vp = ((sprop)->slot != SPROP_INVALID_SLOT) \
600 ? LOCKED_OBJ_GET_SLOT(pobj, (sprop)->slot) \
603 if (!js_NativeGet(cx, obj, pobj, sprop, vp)) \
608 #define NATIVE_SET(cx,obj,sprop,entry,vp) \
610 TRACE_2(SetPropHit, entry, sprop); \
611 if (SPROP_HAS_STUB_SETTER(sprop) && \
612 (sprop)->slot != SPROP_INVALID_SLOT) { \
613 /* Fast path for, e.g., Object instance properties. */ \
614 LOCKED_OBJ_WRITE_SLOT(cx, obj, (sprop)->slot, *vp); \
616 if (!js_NativeSet(cx, obj, sprop, vp)) \
622 * Skip the JSOP_POP typically found after a JSOP_SET* opcode, where oplen is
623 * the constant length of the SET opcode sequence, and spdec is the constant
624 * by which to decrease the stack pointer to pop all of the SET op's operands.
626 * NB: unlike macros that could conceivably be replaced by functions (ignoring
627 * goto error), where a call should not have to be braced in order to expand
628 * correctly (e.g., in if (cond) FOO(); else BAR()), these three macros lack
629 * JS_{BEGIN,END}_MACRO brackets. They are also indented so as to align with
630 * nearby opcode code.
632 #define SKIP_POP_AFTER_SET(oplen,spdec) \
633 if (regs.pc[oplen] == JSOP_POP) { \
635 regs.pc += oplen + JSOP_POP_LENGTH; \
636 op = (JSOp) *regs.pc; \
640 #define END_SET_CASE(OP) \
641 SKIP_POP_AFTER_SET(OP##_LENGTH, 1); \
644 #define END_SET_CASE_STORE_RVAL(OP,spdec) \
645 SKIP_POP_AFTER_SET(OP##_LENGTH, spdec); \
646 rval = FETCH_OPND(-1); \
647 regs.sp -= (spdec) - 1; \
648 STORE_OPND(-1, rval); \
651 BEGIN_CASE(JSOP_SETCONST
)
654 rval
= FETCH_OPND(-1);
655 if (!obj
->defineProperty(cx
, ATOM_TO_JSID(atom
), rval
,
656 JS_PropertyStub
, JS_PropertyStub
,
657 JSPROP_ENUMERATE
| JSPROP_PERMANENT
| JSPROP_READONLY
,
661 END_SET_CASE(JSOP_SETCONST
);
663 #if JS_HAS_DESTRUCTURING
664 BEGIN_CASE(JSOP_ENUMCONSTELEM
)
665 rval
= FETCH_OPND(-3);
666 FETCH_OBJECT(cx
, -2, lval
, obj
);
667 FETCH_ELEMENT_ID(obj
, -1, id
);
668 if (!obj
->defineProperty(cx
, id
, rval
,
669 JS_PropertyStub
, JS_PropertyStub
,
670 JSPROP_ENUMERATE
| JSPROP_PERMANENT
| JSPROP_READONLY
,
675 END_CASE(JSOP_ENUMCONSTELEM
)
678 BEGIN_CASE(JSOP_BINDNAME
)
680 JSPropCacheEntry
*entry
;
683 * We can skip the property lookup for the global object. If
684 * the property does not exist anywhere on the scope chain,
685 * JSOP_SETNAME adds the property to the global.
687 * As a consequence of this optimization for the global object
688 * we run its JSRESOLVE_ASSIGNING-tolerant resolve hooks only
689 * in JSOP_SETNAME, after the interpreter evaluates the right-
690 * hand-side of the assignment, and not here.
692 * This should be transparent to the hooks because the script,
693 * instead of name = rhs, could have used global.name = rhs
694 * given a global object reference, which also calls the hooks
695 * only after evaluating the rhs. We desire such resolve hook
696 * equivalence between the two forms.
698 obj
= fp
->scopeChain
;
699 if (!OBJ_GET_PARENT(cx
, obj
))
701 if (JS_LIKELY(OBJ_IS_NATIVE(obj
))) {
702 PROPERTY_CACHE_TEST(cx
, regs
.pc
, obj
, obj2
, entry
, atom
);
704 ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj
, obj2
, entry
);
705 JS_UNLOCK_OBJ(cx
, obj2
);
712 id
= ATOM_TO_JSID(atom
);
713 obj
= js_FindIdentifierBase(cx
, fp
->scopeChain
, id
);
717 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
718 END_CASE(JSOP_BINDNAME
)
720 BEGIN_CASE(JSOP_IMACOP
)
721 JS_ASSERT(JS_UPTRDIFF(fp
->imacpc
, script
->code
) < script
->length
);
722 op
= JSOp(*fp
->imacpc
);
725 #define BITWISE_OP(OP) \
727 FETCH_INT(cx, -2, i); \
728 FETCH_INT(cx, -1, j); \
731 STORE_INT(cx, -1, i); \
734 BEGIN_CASE(JSOP_BITOR
)
738 BEGIN_CASE(JSOP_BITXOR
)
740 END_CASE(JSOP_BITXOR
)
742 BEGIN_CASE(JSOP_BITAND
)
744 END_CASE(JSOP_BITAND
)
746 #define RELATIONAL_OP(OP) \
748 rval = FETCH_OPND(-1); \
749 lval = FETCH_OPND(-2); \
750 /* Optimize for two int-tagged operands (typical loop control). */ \
751 if ((lval & rval) & JSVAL_INT) { \
752 cond = JSVAL_TO_INT(lval) OP JSVAL_TO_INT(rval); \
754 if (!JSVAL_IS_PRIMITIVE(lval)) \
755 DEFAULT_VALUE(cx, -2, JSTYPE_NUMBER, lval); \
756 if (!JSVAL_IS_PRIMITIVE(rval)) \
757 DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \
758 if (JSVAL_IS_STRING(lval) && JSVAL_IS_STRING(rval)) { \
759 str = JSVAL_TO_STRING(lval); \
760 str2 = JSVAL_TO_STRING(rval); \
761 cond = js_CompareStrings(str, str2) OP 0; \
763 VALUE_TO_NUMBER(cx, -2, lval, d); \
764 VALUE_TO_NUMBER(cx, -1, rval, d2); \
765 cond = JSDOUBLE_COMPARE(d, OP, d2, JS_FALSE); \
768 TRY_BRANCH_AFTER_COND(cond, 2); \
770 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
774 * NB: These macros can't use JS_BEGIN_MACRO/JS_END_MACRO around their bodies
775 * because they begin if/else chains, so callers must not put semicolons after
776 * the call expressions!
778 #if JS_HAS_XML_SUPPORT
779 #define XML_EQUALITY_OP(OP) \
780 if ((ltmp == JSVAL_OBJECT && \
781 (obj2 = JSVAL_TO_OBJECT(lval)) && \
782 OBJECT_IS_XML(cx, obj2)) || \
783 (rtmp == JSVAL_OBJECT && \
784 (obj2 = JSVAL_TO_OBJECT(rval)) && \
785 OBJECT_IS_XML(cx, obj2))) { \
786 if (JSVAL_IS_OBJECT(rval) && obj2 == JSVAL_TO_OBJECT(rval)) \
788 if (!js_TestXMLEquality(cx, obj2, rval, &cond)) \
790 cond = cond OP JS_TRUE; \
793 #define EXTENDED_EQUALITY_OP(OP) \
794 if (ltmp == JSVAL_OBJECT && \
795 (obj2 = JSVAL_TO_OBJECT(lval)) && \
796 ((clasp = OBJ_GET_CLASS(cx, obj2))->flags & JSCLASS_IS_EXTENDED)) { \
797 JSExtendedClass *xclasp; \
799 xclasp = (JSExtendedClass *) clasp; \
800 if (!xclasp->equality(cx, obj2, rval, &cond)) \
802 cond = cond OP JS_TRUE; \
805 #define XML_EQUALITY_OP(OP) /* nothing */
806 #define EXTENDED_EQUALITY_OP(OP) /* nothing */
809 #define EQUALITY_OP(OP, IFNAN) \
811 rval = FETCH_OPND(-1); \
812 lval = FETCH_OPND(-2); \
813 ltmp = JSVAL_TAG(lval); \
814 rtmp = JSVAL_TAG(rval); \
815 XML_EQUALITY_OP(OP) \
816 if (ltmp == rtmp) { \
817 if (ltmp == JSVAL_STRING) { \
818 str = JSVAL_TO_STRING(lval); \
819 str2 = JSVAL_TO_STRING(rval); \
820 cond = js_EqualStrings(str, str2) OP JS_TRUE; \
821 } else if (ltmp == JSVAL_DOUBLE) { \
822 d = *JSVAL_TO_DOUBLE(lval); \
823 d2 = *JSVAL_TO_DOUBLE(rval); \
824 cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN); \
826 EXTENDED_EQUALITY_OP(OP) \
827 /* Handle all undefined (=>NaN) and int combinations. */ \
828 cond = lval OP rval; \
831 if (JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval)) { \
832 cond = (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) OP 1; \
833 } else if (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) { \
836 if (ltmp == JSVAL_OBJECT) { \
837 DEFAULT_VALUE(cx, -2, JSTYPE_VOID, lval); \
838 ltmp = JSVAL_TAG(lval); \
839 } else if (rtmp == JSVAL_OBJECT) { \
840 DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval); \
841 rtmp = JSVAL_TAG(rval); \
843 if (ltmp == JSVAL_STRING && rtmp == JSVAL_STRING) { \
844 str = JSVAL_TO_STRING(lval); \
845 str2 = JSVAL_TO_STRING(rval); \
846 cond = js_EqualStrings(str, str2) OP JS_TRUE; \
848 VALUE_TO_NUMBER(cx, -2, lval, d); \
849 VALUE_TO_NUMBER(cx, -1, rval, d2); \
850 cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN); \
854 TRY_BRANCH_AFTER_COND(cond, 2); \
856 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
860 EQUALITY_OP(==, JS_FALSE
);
864 EQUALITY_OP(!=, JS_TRUE
);
867 #define STRICT_EQUALITY_OP(OP) \
869 rval = FETCH_OPND(-1); \
870 lval = FETCH_OPND(-2); \
871 cond = js_StrictlyEqual(cx, lval, rval) OP JS_TRUE; \
873 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
876 BEGIN_CASE(JSOP_STRICTEQ
)
877 STRICT_EQUALITY_OP(==);
878 END_CASE(JSOP_STRICTEQ
)
880 BEGIN_CASE(JSOP_STRICTNE
)
881 STRICT_EQUALITY_OP(!=);
882 END_CASE(JSOP_STRICTNE
)
884 BEGIN_CASE(JSOP_CASE
)
885 STRICT_EQUALITY_OP(==);
888 len
= GET_JUMP_OFFSET(regs
.pc
);
894 BEGIN_CASE(JSOP_CASEX
)
895 STRICT_EQUALITY_OP(==);
898 len
= GET_JUMPX_OFFSET(regs
.pc
);
923 #define SIGNED_SHIFT_OP(OP) \
925 FETCH_INT(cx, -2, i); \
926 FETCH_INT(cx, -1, j); \
929 STORE_INT(cx, -1, i); \
940 BEGIN_CASE(JSOP_URSH
)
944 FETCH_UINT(cx
, -2, u
);
945 FETCH_INT(cx
, -1, j
);
948 STORE_UINT(cx
, -1, u
);
953 #undef SIGNED_SHIFT_OP
956 rval
= FETCH_OPND(-1);
957 lval
= FETCH_OPND(-2);
958 #if JS_HAS_XML_SUPPORT
959 if (!JSVAL_IS_PRIMITIVE(lval
) &&
960 (obj2
= JSVAL_TO_OBJECT(lval
), OBJECT_IS_XML(cx
, obj2
)) &&
961 VALUE_IS_XML(cx
, rval
)) {
962 if (!js_ConcatenateXML(cx
, obj2
, rval
, &rval
))
965 STORE_OPND(-1, rval
);
969 if (!JSVAL_IS_PRIMITIVE(lval
))
970 DEFAULT_VALUE(cx
, -2, JSTYPE_VOID
, lval
);
971 if (!JSVAL_IS_PRIMITIVE(rval
))
972 DEFAULT_VALUE(cx
, -1, JSTYPE_VOID
, rval
);
973 if ((cond
= JSVAL_IS_STRING(lval
)) || JSVAL_IS_STRING(rval
)) {
975 str
= JSVAL_TO_STRING(lval
);
976 str2
= js_ValueToString(cx
, rval
);
979 regs
.sp
[-1] = STRING_TO_JSVAL(str2
);
981 str2
= JSVAL_TO_STRING(rval
);
982 str
= js_ValueToString(cx
, lval
);
985 regs
.sp
[-2] = STRING_TO_JSVAL(str
);
987 str
= js_ConcatStrings(cx
, str
, str2
);
991 STORE_OPND(-1, STRING_TO_JSVAL(str
));
993 VALUE_TO_NUMBER(cx
, -2, lval
, d
);
994 VALUE_TO_NUMBER(cx
, -1, rval
, d2
);
997 STORE_NUMBER(cx
, -1, d
);
1002 #define BINARY_OP(OP) \
1004 FETCH_NUMBER(cx, -2, d); \
1005 FETCH_NUMBER(cx, -1, d2); \
1008 STORE_NUMBER(cx, -1, d); \
1011 BEGIN_CASE(JSOP_SUB
)
1015 BEGIN_CASE(JSOP_MUL
)
1019 BEGIN_CASE(JSOP_DIV
)
1020 FETCH_NUMBER(cx
, -1, d2
);
1021 FETCH_NUMBER(cx
, -2, d
);
1025 /* XXX MSVC miscompiles such that (NaN == 0) */
1026 if (JSDOUBLE_IS_NaN(d2
))
1027 rval
= DOUBLE_TO_JSVAL(rt
->jsNaN
);
1030 if (d
== 0 || JSDOUBLE_IS_NaN(d
))
1031 rval
= DOUBLE_TO_JSVAL(rt
->jsNaN
);
1032 else if ((JSDOUBLE_HI32(d
) ^ JSDOUBLE_HI32(d2
)) >> 31)
1033 rval
= DOUBLE_TO_JSVAL(rt
->jsNegativeInfinity
);
1035 rval
= DOUBLE_TO_JSVAL(rt
->jsPositiveInfinity
);
1036 STORE_OPND(-1, rval
);
1039 STORE_NUMBER(cx
, -1, d
);
1043 BEGIN_CASE(JSOP_MOD
)
1044 FETCH_NUMBER(cx
, -1, d2
);
1045 FETCH_NUMBER(cx
, -2, d
);
1048 STORE_OPND(-1, DOUBLE_TO_JSVAL(rt
->jsNaN
));
1051 STORE_NUMBER(cx
, -1, d
);
1055 BEGIN_CASE(JSOP_NOT
)
1056 POP_BOOLEAN(cx
, rval
, cond
);
1057 PUSH_OPND(BOOLEAN_TO_JSVAL(!cond
));
1060 BEGIN_CASE(JSOP_BITNOT
)
1061 FETCH_INT(cx
, -1, i
);
1063 STORE_INT(cx
, -1, i
);
1064 END_CASE(JSOP_BITNOT
)
1066 BEGIN_CASE(JSOP_NEG
)
1068 * When the operand is int jsval, INT_FITS_IN_JSVAL(i) implies
1069 * INT_FITS_IN_JSVAL(-i) unless i is 0 or JSVAL_INT_MIN when the
1070 * results, -0.0 or JSVAL_INT_MAX + 1, are jsdouble values.
1072 rval
= FETCH_OPND(-1);
1073 if (JSVAL_IS_INT(rval
) &&
1074 rval
!= INT_TO_JSVAL(JSVAL_INT_MIN
) &&
1075 (i
= JSVAL_TO_INT(rval
)) != 0) {
1076 JS_STATIC_ASSERT(!INT_FITS_IN_JSVAL(-JSVAL_INT_MIN
));
1078 JS_ASSERT(INT_FITS_IN_JSVAL(i
));
1079 regs
.sp
[-1] = INT_TO_JSVAL(i
);
1081 if (JSVAL_IS_DOUBLE(rval
)) {
1082 d
= *JSVAL_TO_DOUBLE(rval
);
1084 d
= js_ValueToNumber(cx
, ®s
.sp
[-1]);
1085 if (JSVAL_IS_NULL(regs
.sp
[-1]))
1087 JS_ASSERT(JSVAL_IS_NUMBER(regs
.sp
[-1]) ||
1088 regs
.sp
[-1] == JSVAL_TRUE
);
1092 * Negation of a zero doesn't produce a negative
1093 * zero on HPUX. Perform the operation by bit
1096 JSDOUBLE_HI32(d
) ^= JSDOUBLE_HI32_SIGNBIT
;
1100 if (!js_NewNumberInRootedValue(cx
, d
, ®s
.sp
[-1]))
1105 BEGIN_CASE(JSOP_POS
)
1106 rval
= FETCH_OPND(-1);
1107 if (!JSVAL_IS_NUMBER(rval
)) {
1108 d
= js_ValueToNumber(cx
, ®s
.sp
[-1]);
1110 if (JSVAL_IS_NULL(rval
))
1112 if (rval
== JSVAL_TRUE
) {
1113 if (!js_NewNumberInRootedValue(cx
, d
, ®s
.sp
[-1]))
1116 JS_ASSERT(JSVAL_IS_NUMBER(rval
));
1121 BEGIN_CASE(JSOP_DELNAME
)
1123 id
= ATOM_TO_JSID(atom
);
1124 if (!js_FindProperty(cx
, id
, &obj
, &obj2
, &prop
))
1127 /* ECMA says to return true if name is undefined or inherited. */
1128 PUSH_OPND(JSVAL_TRUE
);
1130 obj2
->dropProperty(cx
, prop
);
1131 if (!obj
->deleteProperty(cx
, id
, ®s
.sp
[-1]))
1134 END_CASE(JSOP_DELNAME
)
1136 BEGIN_CASE(JSOP_DELPROP
)
1138 id
= ATOM_TO_JSID(atom
);
1139 PROPERTY_OP(-1, obj
->deleteProperty(cx
, id
, &rval
));
1140 STORE_OPND(-1, rval
);
1141 END_CASE(JSOP_DELPROP
)
1143 BEGIN_CASE(JSOP_DELELEM
)
1144 ELEMENT_OP(-1, obj
->deleteProperty(cx
, id
, &rval
));
1146 STORE_OPND(-1, rval
);
1147 END_CASE(JSOP_DELELEM
)
1149 BEGIN_CASE(JSOP_TYPEOFEXPR
)
1150 BEGIN_CASE(JSOP_TYPEOF
)
1151 rval
= FETCH_OPND(-1);
1152 type
= JS_TypeOfValue(cx
, rval
);
1153 atom
= rt
->atomState
.typeAtoms
[type
];
1154 STORE_OPND(-1, ATOM_KEY(atom
));
1155 END_CASE(JSOP_TYPEOF
)
1157 BEGIN_CASE(JSOP_VOID
)
1158 STORE_OPND(-1, JSVAL_VOID
);
1161 BEGIN_CASE(JSOP_INCELEM
)
1162 BEGIN_CASE(JSOP_DECELEM
)
1163 BEGIN_CASE(JSOP_ELEMINC
)
1164 BEGIN_CASE(JSOP_ELEMDEC
)
1166 * Delay fetching of id until we have the object to ensure
1167 * the proper evaluation order. See bug 372331.
1171 goto fetch_incop_obj
;
1173 BEGIN_CASE(JSOP_INCPROP
)
1174 BEGIN_CASE(JSOP_DECPROP
)
1175 BEGIN_CASE(JSOP_PROPINC
)
1176 BEGIN_CASE(JSOP_PROPDEC
)
1178 id
= ATOM_TO_JSID(atom
);
1182 FETCH_OBJECT(cx
, i
, lval
, obj
);
1184 FETCH_ELEMENT_ID(obj
, -1, id
);
1187 BEGIN_CASE(JSOP_INCNAME
)
1188 BEGIN_CASE(JSOP_DECNAME
)
1189 BEGIN_CASE(JSOP_NAMEINC
)
1190 BEGIN_CASE(JSOP_NAMEDEC
)
1192 JSPropCacheEntry
*entry
;
1194 obj
= fp
->scopeChain
;
1195 if (JS_LIKELY(OBJ_IS_NATIVE(obj
))) {
1196 PROPERTY_CACHE_TEST(cx
, regs
.pc
, obj
, obj2
, entry
, atom
);
1198 ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj
, obj2
, entry
);
1199 if (obj
== obj2
&& PCVAL_IS_SLOT(entry
->vword
)) {
1200 slot
= PCVAL_TO_SLOT(entry
->vword
);
1201 JS_ASSERT(slot
< OBJ_SCOPE(obj
)->freeslot
);
1202 rval
= LOCKED_OBJ_GET_SLOT(obj
, slot
);
1203 if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval
))) {
1205 rval
+= (js_CodeSpec
[op
].format
& JOF_INC
) ? 2 : -2;
1206 if (!(js_CodeSpec
[op
].format
& JOF_POST
))
1208 LOCKED_OBJ_SET_SLOT(obj
, slot
, rval
);
1209 JS_UNLOCK_OBJ(cx
, obj
);
1211 len
= JSOP_INCNAME_LENGTH
;
1215 JS_UNLOCK_OBJ(cx
, obj2
);
1221 id
= ATOM_TO_JSID(atom
);
1222 if (!js_FindPropertyHelper(cx
, id
, true, &obj
, &obj2
, &prop
))
1225 goto atom_not_defined
;
1226 obj2
->dropProperty(cx
, prop
);
1231 const JSCodeSpec
*cs
;
1235 * We need a root to store the value to leave on the stack until
1236 * we have done with obj->setProperty.
1238 PUSH_OPND(JSVAL_NULL
);
1239 if (!obj
->getProperty(cx
, id
, ®s
.sp
[-1]))
1242 cs
= &js_CodeSpec
[op
];
1243 JS_ASSERT(cs
->ndefs
== 1);
1244 JS_ASSERT((cs
->format
& JOF_TMPSLOT_MASK
) == JOF_TMPSLOT2
);
1246 if (JS_LIKELY(CAN_DO_FAST_INC_DEC(v
))) {
1249 incr
= (cs
->format
& JOF_INC
) ? 2 : -2;
1250 if (cs
->format
& JOF_POST
) {
1251 regs
.sp
[-1] = v
+ incr
;
1256 fp
->flags
|= JSFRAME_ASSIGNING
;
1257 ok
= obj
->setProperty(cx
, id
, ®s
.sp
[-1]);
1258 fp
->flags
&= ~JSFRAME_ASSIGNING
;
1263 * We must set regs.sp[-1] to v for both post and pre increments
1264 * as the setter overwrites regs.sp[-1].
1268 /* We need an extra root for the result. */
1269 PUSH_OPND(JSVAL_NULL
);
1270 if (!js_DoIncDec(cx
, cs
, ®s
.sp
[-2], ®s
.sp
[-1]))
1272 fp
->flags
|= JSFRAME_ASSIGNING
;
1273 ok
= obj
->setProperty(cx
, id
, ®s
.sp
[-1]);
1274 fp
->flags
&= ~JSFRAME_ASSIGNING
;
1280 if (cs
->nuses
== 0) {
1281 /* regs.sp[-1] already contains the result of name increment. */
1284 regs
.sp
-= cs
->nuses
;
1294 /* Position cases so the most frequent i++ does not need a jump. */
1295 BEGIN_CASE(JSOP_DECARG
)
1296 incr
= -2; incr2
= -2; goto do_arg_incop
;
1297 BEGIN_CASE(JSOP_ARGDEC
)
1298 incr
= -2; incr2
= 0; goto do_arg_incop
;
1299 BEGIN_CASE(JSOP_INCARG
)
1300 incr
= 2; incr2
= 2; goto do_arg_incop
;
1301 BEGIN_CASE(JSOP_ARGINC
)
1302 incr
= 2; incr2
= 0;
1305 slot
= GET_ARGNO(regs
.pc
);
1306 JS_ASSERT(slot
< fp
->fun
->nargs
);
1307 METER_SLOT_OP(op
, slot
);
1308 vp
= fp
->argv
+ slot
;
1309 goto do_int_fast_incop
;
1311 BEGIN_CASE(JSOP_DECLOCAL
)
1312 incr
= -2; incr2
= -2; goto do_local_incop
;
1313 BEGIN_CASE(JSOP_LOCALDEC
)
1314 incr
= -2; incr2
= 0; goto do_local_incop
;
1315 BEGIN_CASE(JSOP_INCLOCAL
)
1316 incr
= 2; incr2
= 2; goto do_local_incop
;
1317 BEGIN_CASE(JSOP_LOCALINC
)
1318 incr
= 2; incr2
= 0;
1321 * do_local_incop comes right before do_int_fast_incop as we want to
1322 * avoid an extra jump for variable cases as local++ is more frequent
1326 slot
= GET_SLOTNO(regs
.pc
);
1327 JS_ASSERT(slot
< fp
->script
->nslots
);
1328 vp
= fp
->slots
+ slot
;
1329 METER_SLOT_OP(op
, slot
);
1330 vp
= fp
->slots
+ slot
;
1334 if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval
))) {
1336 JS_ASSERT(JSOP_INCARG_LENGTH
== js_CodeSpec
[op
].length
);
1337 SKIP_POP_AFTER_SET(JSOP_INCARG_LENGTH
, 0);
1338 PUSH_OPND(rval
+ incr2
);
1341 if (!js_DoIncDec(cx
, &js_CodeSpec
[op
], ®s
.sp
[-1], vp
))
1344 len
= JSOP_INCARG_LENGTH
;
1345 JS_ASSERT(len
== js_CodeSpec
[op
].length
);
1349 /* NB: This macro doesn't use JS_BEGIN_MACRO/JS_END_MACRO around its body. */
1350 #define FAST_GLOBAL_INCREMENT_OP(SLOWOP,INCR,INCR2) \
1354 goto do_global_incop
1359 BEGIN_CASE(JSOP_DECGVAR
)
1360 FAST_GLOBAL_INCREMENT_OP(JSOP_DECNAME
, -2, -2);
1361 BEGIN_CASE(JSOP_GVARDEC
)
1362 FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEDEC
, -2, 0);
1363 BEGIN_CASE(JSOP_INCGVAR
)
1364 FAST_GLOBAL_INCREMENT_OP(JSOP_INCNAME
, 2, 2);
1365 BEGIN_CASE(JSOP_GVARINC
)
1366 FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEINC
, 2, 0);
1368 #undef FAST_GLOBAL_INCREMENT_OP
1371 JS_ASSERT((js_CodeSpec
[op
].format
& JOF_TMPSLOT_MASK
) ==
1373 slot
= GET_SLOTNO(regs
.pc
);
1374 JS_ASSERT(slot
< GlobalVarCount(fp
));
1375 METER_SLOT_OP(op
, slot
);
1376 lval
= fp
->slots
[slot
];
1377 if (JSVAL_IS_NULL(lval
)) {
1381 slot
= JSVAL_TO_INT(lval
);
1382 rval
= OBJ_GET_SLOT(cx
, fp
->varobj
, slot
);
1383 if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval
))) {
1384 PUSH_OPND(rval
+ incr2
);
1388 PUSH_OPND(JSVAL_NULL
); /* Extra root */
1389 if (!js_DoIncDec(cx
, &js_CodeSpec
[op
], ®s
.sp
[-2], ®s
.sp
[-1]))
1394 OBJ_SET_SLOT(cx
, fp
->varobj
, slot
, rval
);
1395 len
= JSOP_INCGVAR_LENGTH
; /* all gvar incops are same length */
1396 JS_ASSERT(len
== js_CodeSpec
[op
].length
);
1400 #define COMPUTE_THIS(cx, fp, obj) \
1402 if (!(obj = js_ComputeThisForFrame(cx, fp))) \
1406 BEGIN_CASE(JSOP_THIS
)
1407 COMPUTE_THIS(cx
, fp
, obj
);
1408 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
1411 BEGIN_CASE(JSOP_GETTHISPROP
)
1413 COMPUTE_THIS(cx
, fp
, obj
);
1415 goto do_getprop_with_obj
;
1419 BEGIN_CASE(JSOP_GETARGPROP
)
1421 slot
= GET_ARGNO(regs
.pc
);
1422 JS_ASSERT(slot
< fp
->fun
->nargs
);
1423 PUSH_OPND(fp
->argv
[slot
]);
1424 goto do_getprop_body
;
1426 BEGIN_CASE(JSOP_GETLOCALPROP
)
1428 slot
= GET_SLOTNO(regs
.pc
);
1429 JS_ASSERT(slot
< script
->nslots
);
1430 PUSH_OPND(fp
->slots
[slot
]);
1431 goto do_getprop_body
;
1433 BEGIN_CASE(JSOP_GETPROP
)
1434 BEGIN_CASE(JSOP_GETXPROP
)
1438 lval
= FETCH_OPND(-1);
1440 do_getprop_with_lval
:
1441 VALUE_TO_OBJECT(cx
, -1, lval
, obj
);
1443 do_getprop_with_obj
:
1446 JSPropCacheEntry
*entry
;
1448 aobj
= js_GetProtoIfDenseArray(cx
, obj
);
1449 if (JS_LIKELY(aobj
->map
->ops
->getProperty
== js_GetProperty
)) {
1450 PROPERTY_CACHE_TEST(cx
, regs
.pc
, aobj
, obj2
, entry
, atom
);
1452 ASSERT_VALID_PROPERTY_CACHE_HIT(i
, aobj
, obj2
, entry
);
1453 if (PCVAL_IS_OBJECT(entry
->vword
)) {
1454 rval
= PCVAL_OBJECT_TO_JSVAL(entry
->vword
);
1455 } else if (PCVAL_IS_SLOT(entry
->vword
)) {
1456 slot
= PCVAL_TO_SLOT(entry
->vword
);
1457 JS_ASSERT(slot
< OBJ_SCOPE(obj2
)->freeslot
);
1458 rval
= LOCKED_OBJ_GET_SLOT(obj2
, slot
);
1460 JS_ASSERT(PCVAL_IS_SPROP(entry
->vword
));
1461 sprop
= PCVAL_TO_SPROP(entry
->vword
);
1462 NATIVE_GET(cx
, obj
, obj2
, sprop
, &rval
);
1464 JS_UNLOCK_OBJ(cx
, obj2
);
1470 atom
= rt
->atomState
.lengthAtom
;
1474 id
= ATOM_TO_JSID(atom
);
1476 ? !js_GetPropertyHelper(cx
, obj
, id
, true, &rval
)
1477 : !obj
->getProperty(cx
, id
, &rval
)) {
1482 STORE_OPND(-1, rval
);
1483 JS_ASSERT(JSOP_GETPROP_LENGTH
+ i
== js_CodeSpec
[op
].length
);
1484 len
= JSOP_GETPROP_LENGTH
+ i
;
1487 BEGIN_CASE(JSOP_LENGTH
)
1488 lval
= FETCH_OPND(-1);
1489 if (JSVAL_IS_STRING(lval
)) {
1490 str
= JSVAL_TO_STRING(lval
);
1491 regs
.sp
[-1] = INT_TO_JSVAL(str
->length());
1492 } else if (!JSVAL_IS_PRIMITIVE(lval
) &&
1493 (obj
= JSVAL_TO_OBJECT(lval
), OBJ_IS_ARRAY(cx
, obj
))) {
1497 * We know that the array is created with only its 'length'
1498 * private data in a fixed slot at JSSLOT_ARRAY_LENGTH. See
1499 * also JSOP_ARRAYPUSH, far below.
1501 length
= obj
->fslots
[JSSLOT_ARRAY_LENGTH
];
1502 if (length
<= JSVAL_INT_MAX
) {
1503 regs
.sp
[-1] = INT_TO_JSVAL(length
);
1504 } else if (!js_NewDoubleInRootedValue(cx
, (jsdouble
) length
,
1510 goto do_getprop_with_lval
;
1512 END_CASE(JSOP_LENGTH
)
1514 BEGIN_CASE(JSOP_CALLPROP
)
1517 JSPropCacheEntry
*entry
;
1519 lval
= FETCH_OPND(-1);
1520 if (!JSVAL_IS_PRIMITIVE(lval
)) {
1521 obj
= JSVAL_TO_OBJECT(lval
);
1523 if (JSVAL_IS_STRING(lval
)) {
1525 } else if (JSVAL_IS_NUMBER(lval
)) {
1527 } else if (JSVAL_IS_BOOLEAN(lval
)) {
1528 i
= JSProto_Boolean
;
1530 JS_ASSERT(JSVAL_IS_NULL(lval
) || JSVAL_IS_VOID(lval
));
1531 js_ReportIsNullOrUndefined(cx
, -1, lval
, NULL
);
1535 if (!js_GetClassPrototype(cx
, NULL
, INT_TO_JSID(i
), &obj
))
1539 aobj
= js_GetProtoIfDenseArray(cx
, obj
);
1540 if (JS_LIKELY(aobj
->map
->ops
->getProperty
== js_GetProperty
)) {
1541 PROPERTY_CACHE_TEST(cx
, regs
.pc
, aobj
, obj2
, entry
, atom
);
1543 ASSERT_VALID_PROPERTY_CACHE_HIT(0, aobj
, obj2
, entry
);
1544 if (PCVAL_IS_OBJECT(entry
->vword
)) {
1545 rval
= PCVAL_OBJECT_TO_JSVAL(entry
->vword
);
1546 } else if (PCVAL_IS_SLOT(entry
->vword
)) {
1547 slot
= PCVAL_TO_SLOT(entry
->vword
);
1548 JS_ASSERT(slot
< OBJ_SCOPE(obj2
)->freeslot
);
1549 rval
= LOCKED_OBJ_GET_SLOT(obj2
, slot
);
1551 JS_ASSERT(PCVAL_IS_SPROP(entry
->vword
));
1552 sprop
= PCVAL_TO_SPROP(entry
->vword
);
1553 NATIVE_GET(cx
, obj
, obj2
, sprop
, &rval
);
1555 JS_UNLOCK_OBJ(cx
, obj2
);
1556 STORE_OPND(-1, rval
);
1566 * Cache miss: use the immediate atom that was loaded for us under
1567 * PROPERTY_CACHE_TEST.
1569 id
= ATOM_TO_JSID(atom
);
1571 if (!JSVAL_IS_PRIMITIVE(lval
)) {
1572 if (!js_GetMethod(cx
, obj
, id
, !!entry
, &rval
))
1574 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
1575 STORE_OPND(-2, rval
);
1577 JS_ASSERT(obj
->map
->ops
->getProperty
== js_GetProperty
);
1578 if (!js_GetPropertyHelper(cx
, obj
, id
, true, &rval
))
1580 STORE_OPND(-1, lval
);
1581 STORE_OPND(-2, rval
);
1585 /* Wrap primitive lval in object clothing if necessary. */
1586 if (JSVAL_IS_PRIMITIVE(lval
)) {
1587 /* FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=412571 */
1588 if (!VALUE_IS_FUNCTION(cx
, rval
) ||
1589 (obj
= JSVAL_TO_OBJECT(rval
),
1590 fun
= GET_FUNCTION_PRIVATE(cx
, obj
),
1591 !PRIMITIVE_THIS_TEST(fun
, lval
))) {
1592 if (!js_PrimitiveToObject(cx
, ®s
.sp
[-1]))
1596 #if JS_HAS_NO_SUCH_METHOD
1597 if (JS_UNLIKELY(JSVAL_IS_VOID(rval
))) {
1599 regs
.sp
[-2] = ATOM_KEY(atom
);
1600 if (!js_OnUnknownMethod(cx
, regs
.sp
- 2))
1605 END_CASE(JSOP_CALLPROP
)
1607 BEGIN_CASE(JSOP_SETNAME
)
1608 BEGIN_CASE(JSOP_SETPROP
)
1609 rval
= FETCH_OPND(-1);
1610 lval
= FETCH_OPND(-2);
1611 JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval
) || op
== JSOP_SETPROP
);
1612 VALUE_TO_OBJECT(cx
, -2, lval
, obj
);
1615 JSPropCacheEntry
*entry
;
1619 if (JS_LIKELY(obj
->map
->ops
->setProperty
== js_SetProperty
)) {
1620 JSPropertyCache
*cache
= &JS_PROPERTY_CACHE(cx
);
1621 uint32 kshape
= OBJ_SHAPE(obj
);
1624 * Open-code PROPERTY_CACHE_TEST, specializing for two
1625 * important set-property cases. First:
1627 * function f(a, b, c) {
1628 * var o = {p:a, q:b, r:c};
1632 * or similar real-world cases, which evolve a newborn
1633 * native object predicatably through some bounded number
1634 * of property additions. And second:
1638 * in a frequently executed method or loop body, where p
1639 * will (possibly after the first iteration) always exist
1640 * in native object o.
1642 entry
= &cache
->table
[PROPERTY_CACHE_HASH_PC(regs
.pc
, kshape
)];
1643 PCMETER(cache
->pctestentry
= entry
);
1644 PCMETER(cache
->tests
++);
1645 PCMETER(cache
->settests
++);
1646 if (entry
->kpc
== regs
.pc
&& entry
->kshape
== kshape
) {
1647 JS_ASSERT(PCVCAP_TAG(entry
->vcap
) <= 1);
1648 if (JS_LOCK_OBJ_IF_SHAPE(cx
, obj
, kshape
)) {
1649 JS_ASSERT(PCVAL_IS_SPROP(entry
->vword
));
1650 sprop
= PCVAL_TO_SPROP(entry
->vword
);
1651 JS_ASSERT(!(sprop
->attrs
& JSPROP_READONLY
));
1652 JS_ASSERT_IF(!(sprop
->attrs
& JSPROP_SHARED
),
1653 PCVCAP_TAG(entry
->vcap
) == 0);
1655 JSScope
*scope
= OBJ_SCOPE(obj
);
1656 JS_ASSERT(!scope
->sealed());
1659 * Fastest path: check whether the cached sprop is
1660 * already in scope and call NATIVE_SET and break
1661 * to get out of the do-while(0). But we can call
1662 * NATIVE_SET only if obj owns scope or sprop is
1666 if (sprop
->attrs
& JSPROP_SHARED
) {
1667 if (PCVCAP_TAG(entry
->vcap
) == 0 ||
1668 ((obj2
= OBJ_GET_PROTO(cx
, obj
)) &&
1669 OBJ_IS_NATIVE(obj2
) &&
1670 OBJ_SHAPE(obj2
) == PCVCAP_SHAPE(entry
->vcap
))) {
1671 goto fast_set_propcache_hit
;
1674 /* The cache entry doesn't apply. vshape mismatch. */
1675 checkForAdd
= false;
1676 } else if (scope
->owned()) {
1677 if (sprop
== scope
->lastProp
|| scope
->has(sprop
)) {
1678 fast_set_propcache_hit
:
1679 PCMETER(cache
->pchits
++);
1680 PCMETER(cache
->setpchits
++);
1681 NATIVE_SET(cx
, obj
, sprop
, entry
, &rval
);
1682 JS_UNLOCK_SCOPE(cx
, scope
);
1686 !(sprop
->attrs
& JSPROP_SHARED
) &&
1687 sprop
->parent
== scope
->lastProp
&&
1688 !scope
->hadMiddleDelete();
1690 scope
= js_GetMutableScope(cx
, obj
);
1692 JS_UNLOCK_OBJ(cx
, obj
);
1695 checkForAdd
= !sprop
->parent
;
1699 SPROP_HAS_STUB_SETTER(sprop
) &&
1700 (slot
= sprop
->slot
) == scope
->freeslot
) {
1702 * Fast path: adding a plain old property that
1703 * was once at the frontier of the property
1704 * tree, whose slot is next to claim among the
1705 * allocated slots in obj, where scope->table
1706 * has not been created yet.
1708 * We may want to remove hazard conditions
1709 * above and inline compensation code here,
1710 * depending on real-world workloads.
1712 JS_ASSERT(!(LOCKED_OBJ_GET_CLASS(obj
)->flags
&
1713 JSCLASS_SHARE_ALL_PROPERTIES
));
1715 PCMETER(cache
->pchits
++);
1716 PCMETER(cache
->addpchits
++);
1719 * Beware classes such as Function that use
1720 * the reserveSlots hook to allocate a number
1721 * of reserved slots that may vary with obj.
1723 if (slot
< STOBJ_NSLOTS(obj
) &&
1724 !OBJ_GET_CLASS(cx
, obj
)->reserveSlots
) {
1727 if (!js_AllocSlot(cx
, obj
, &slot
)) {
1728 JS_UNLOCK_SCOPE(cx
, scope
);
1734 * If this obj's number of reserved slots
1735 * differed, or if something created a hash
1736 * table for scope, we must pay the price of
1739 * If slot does not match the cached sprop's
1740 * slot, update the cache entry in the hope
1741 * that obj and other instances with the same
1742 * number of reserved slots are now "hot".
1744 if (slot
!= sprop
->slot
|| scope
->table
) {
1745 JSScopeProperty
*sprop2
=
1746 scope
->add(cx
, sprop
->id
,
1747 sprop
->getter
, sprop
->setter
,
1749 sprop
->flags
, sprop
->shortid
);
1751 js_FreeSlot(cx
, obj
, slot
);
1752 JS_UNLOCK_SCOPE(cx
, scope
);
1755 if (sprop2
!= sprop
) {
1756 PCMETER(cache
->slotchanges
++);
1757 JS_ASSERT(slot
!= sprop
->slot
&&
1758 slot
== sprop2
->slot
&&
1759 sprop2
->id
== sprop
->id
);
1760 entry
->vword
= SPROP_TO_PCVAL(sprop2
);
1764 scope
->extend(cx
, sprop
);
1767 LOCKED_OBJ_WRITE_BARRIER(cx
, obj
, slot
, rval
);
1768 TRACE_2(SetPropHit
, entry
, sprop
);
1769 LOCKED_OBJ_SET_SLOT(obj
, slot
, rval
);
1770 JS_UNLOCK_SCOPE(cx
, scope
);
1773 * Purge the property cache of the id we may
1774 * have just shadowed in obj's scope and proto
1775 * chains. We do this after unlocking obj's
1776 * scope to avoid lock nesting.
1778 js_PurgeScopeChain(cx
, obj
, sprop
->id
);
1781 JS_UNLOCK_SCOPE(cx
, scope
);
1782 PCMETER(cache
->setpcmisses
++);
1786 atom
= js_FullTestPropertyCache(cx
, regs
.pc
, &obj
, &obj2
,
1789 PCMETER(cache
->misses
++);
1790 PCMETER(cache
->setmisses
++);
1792 ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj
, obj2
, entry
);
1795 JS_ASSERT(PCVAL_IS_SPROP(entry
->vword
));
1796 sprop
= PCVAL_TO_SPROP(entry
->vword
);
1797 JS_ASSERT(!(sprop
->attrs
& JSPROP_READONLY
));
1798 JS_ASSERT(!OBJ_SCOPE(obj2
)->sealed());
1799 NATIVE_SET(cx
, obj
, sprop
, entry
, &rval
);
1801 JS_UNLOCK_OBJ(cx
, obj2
);
1809 id
= ATOM_TO_JSID(atom
);
1811 if (!js_SetPropertyHelper(cx
, obj
, id
, true, &rval
))
1814 if (!obj
->setProperty(cx
, id
, &rval
))
1816 ABORT_RECORDING(cx
, "Non-native set");
1819 END_SET_CASE_STORE_RVAL(JSOP_SETPROP
, 2);
1821 BEGIN_CASE(JSOP_GETELEM
)
1822 /* Open-coded ELEMENT_OP optimized for strings and dense arrays. */
1823 lval
= FETCH_OPND(-2);
1824 rval
= FETCH_OPND(-1);
1825 if (JSVAL_IS_STRING(lval
) && JSVAL_IS_INT(rval
)) {
1826 str
= JSVAL_TO_STRING(lval
);
1827 i
= JSVAL_TO_INT(rval
);
1828 if ((size_t)i
< str
->length()) {
1829 str
= js_GetUnitString(cx
, str
, (size_t)i
);
1832 rval
= STRING_TO_JSVAL(str
);
1837 VALUE_TO_OBJECT(cx
, -2, lval
, obj
);
1838 if (JSVAL_IS_INT(rval
)) {
1839 if (OBJ_IS_DENSE_ARRAY(cx
, obj
)) {
1842 length
= js_DenseArrayCapacity(obj
);
1843 i
= JSVAL_TO_INT(rval
);
1844 if ((jsuint
)i
< length
&&
1845 i
< obj
->fslots
[JSSLOT_ARRAY_LENGTH
]) {
1846 rval
= obj
->dslots
[i
];
1847 if (rval
!= JSVAL_HOLE
)
1850 /* Reload rval from the stack in the rare hole case. */
1851 rval
= FETCH_OPND(-1);
1854 id
= INT_JSVAL_TO_JSID(rval
);
1856 if (!js_InternNonIntElementId(cx
, obj
, rval
, &id
))
1860 if (!obj
->getProperty(cx
, id
, &rval
))
1864 STORE_OPND(-1, rval
);
1865 END_CASE(JSOP_GETELEM
)
1867 BEGIN_CASE(JSOP_CALLELEM
)
1868 ELEMENT_OP(-1, js_GetMethod(cx
, obj
, id
, false, &rval
));
1869 #if JS_HAS_NO_SUCH_METHOD
1870 if (JS_UNLIKELY(JSVAL_IS_VOID(rval
))) {
1871 regs
.sp
[-2] = regs
.sp
[-1];
1872 regs
.sp
[-1] = OBJECT_TO_JSVAL(obj
);
1873 if (!js_OnUnknownMethod(cx
, regs
.sp
- 2))
1878 STORE_OPND(-2, rval
);
1879 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
1881 END_CASE(JSOP_CALLELEM
)
1883 BEGIN_CASE(JSOP_SETELEM
)
1884 rval
= FETCH_OPND(-1);
1885 FETCH_OBJECT(cx
, -3, lval
, obj
);
1886 FETCH_ELEMENT_ID(obj
, -2, id
);
1888 if (OBJ_IS_DENSE_ARRAY(cx
, obj
) && JSID_IS_INT(id
)) {
1891 length
= js_DenseArrayCapacity(obj
);
1892 i
= JSID_TO_INT(id
);
1893 if ((jsuint
)i
< length
) {
1894 if (obj
->dslots
[i
] == JSVAL_HOLE
) {
1895 if (js_PrototypeHasIndexedProperties(cx
, obj
))
1897 if (i
>= obj
->fslots
[JSSLOT_ARRAY_LENGTH
])
1898 obj
->fslots
[JSSLOT_ARRAY_LENGTH
] = i
+ 1;
1899 obj
->fslots
[JSSLOT_ARRAY_COUNT
]++;
1901 obj
->dslots
[i
] = rval
;
1906 if (!obj
->setProperty(cx
, id
, &rval
))
1909 END_SET_CASE_STORE_RVAL(JSOP_SETELEM
, 3)
1911 BEGIN_CASE(JSOP_ENUMELEM
)
1912 /* Funky: the value to set is under the [obj, id] pair. */
1913 rval
= FETCH_OPND(-3);
1914 FETCH_OBJECT(cx
, -2, lval
, obj
);
1915 FETCH_ELEMENT_ID(obj
, -1, id
);
1916 if (!obj
->setProperty(cx
, id
, &rval
))
1919 END_CASE(JSOP_ENUMELEM
)
1921 BEGIN_CASE(JSOP_NEW
)
1922 /* Get immediate argc and find the constructor function. */
1923 argc
= GET_ARGC(regs
.pc
);
1924 vp
= regs
.sp
- (2 + argc
);
1925 JS_ASSERT(vp
>= StackBase(fp
));
1928 * Assign lval, obj, and fun exactly as the code at inline_call:
1929 * expects to find them, to avoid nesting a js_Interpret call via
1930 * js_InvokeConstructor.
1933 if (VALUE_IS_FUNCTION(cx
, lval
)) {
1934 obj
= JSVAL_TO_OBJECT(lval
);
1935 fun
= GET_FUNCTION_PRIVATE(cx
, obj
);
1936 if (FUN_INTERPRETED(fun
)) {
1937 /* Root as we go using vp[1]. */
1938 if (!obj
->getProperty(cx
,
1939 ATOM_TO_JSID(cx
->runtime
->atomState
.classPrototypeAtom
),
1944 obj2
= js_NewObject(cx
, &js_ObjectClass
,
1945 JSVAL_IS_OBJECT(rval
)
1946 ? JSVAL_TO_OBJECT(rval
)
1948 OBJ_GET_PARENT(cx
, obj
));
1951 vp
[1] = OBJECT_TO_JSVAL(obj2
);
1952 flags
= JSFRAME_CONSTRUCTING
;
1957 if (!js_InvokeConstructor(cx
, argc
, JS_FALSE
, vp
))
1960 CHECK_INTERRUPT_HANDLER();
1961 TRACE_0(NativeCallComplete
);
1964 BEGIN_CASE(JSOP_CALL
)
1965 BEGIN_CASE(JSOP_EVAL
)
1966 BEGIN_CASE(JSOP_APPLY
)
1967 argc
= GET_ARGC(regs
.pc
);
1968 vp
= regs
.sp
- (argc
+ 2);
1971 if (VALUE_IS_FUNCTION(cx
, lval
)) {
1972 obj
= JSVAL_TO_OBJECT(lval
);
1973 fun
= GET_FUNCTION_PRIVATE(cx
, obj
);
1975 /* Clear frame flags since this is not a constructor call. */
1977 if (FUN_INTERPRETED(fun
))
1980 uintN nframeslots
, nvars
, missing
;
1985 JSInlineFrame
*newifp
;
1986 JSInterpreterHook hook
;
1988 /* Restrict recursion of lightweight functions. */
1989 if (inlineCallCount
== MAX_INLINE_CALL_COUNT
) {
1990 js_ReportOverRecursed(cx
);
1994 /* Compute the total number of stack slots needed by fun. */
1995 nframeslots
= JS_HOWMANY(sizeof(JSInlineFrame
),
1997 script
= fun
->u
.i
.script
;
1998 atoms
= script
->atomMap
.vector
;
1999 nbytes
= (nframeslots
+ script
->nslots
) * sizeof(jsval
);
2001 /* Allocate missing expected args adjacent to actuals. */
2002 a
= cx
->stackPool
.current
;
2003 newmark
= (void *) a
->avail
;
2004 if (fun
->nargs
<= argc
) {
2007 newsp
= vp
+ 2 + fun
->nargs
;
2008 JS_ASSERT(newsp
> regs
.sp
);
2009 if ((jsuword
) newsp
<= a
->limit
) {
2010 if ((jsuword
) newsp
> a
->avail
)
2011 a
->avail
= (jsuword
) newsp
;
2012 jsval
*argsp
= newsp
;
2014 *--argsp
= JSVAL_VOID
;
2015 } while (argsp
!= regs
.sp
);
2018 missing
= fun
->nargs
- argc
;
2019 nbytes
+= (2 + fun
->nargs
) * sizeof(jsval
);
2023 /* Allocate the inline frame with its slots and operands. */
2024 if (a
->avail
+ nbytes
<= a
->limit
) {
2025 newsp
= (jsval
*) a
->avail
;
2027 JS_ASSERT(missing
== 0);
2029 JS_ARENA_ALLOCATE_CAST(newsp
, jsval
*, &cx
->stackPool
,
2032 js_ReportOutOfScriptQuota(cx
);
2033 goto bad_inline_call
;
2037 * Move args if the missing ones overflow arena a, then
2038 * push undefined for the missing args.
2041 memcpy(newsp
, vp
, (2 + argc
) * sizeof(jsval
));
2043 newsp
= vp
+ 2 + argc
;
2045 *newsp
++ = JSVAL_VOID
;
2046 } while (--missing
!= 0);
2050 /* Claim space for the stack frame and initialize it. */
2051 newifp
= (JSInlineFrame
*) newsp
;
2052 newsp
+= nframeslots
;
2053 newifp
->frame
.callobj
= NULL
;
2054 newifp
->frame
.argsobj
= NULL
;
2055 newifp
->frame
.varobj
= NULL
;
2056 newifp
->frame
.script
= script
;
2057 newifp
->frame
.fun
= fun
;
2058 newifp
->frame
.argc
= argc
;
2059 newifp
->frame
.argv
= vp
+ 2;
2060 newifp
->frame
.rval
= JSVAL_VOID
;
2061 newifp
->frame
.down
= fp
;
2062 newifp
->frame
.annotation
= NULL
;
2063 newifp
->frame
.scopeChain
= parent
= OBJ_GET_PARENT(cx
, obj
);
2064 newifp
->frame
.sharpDepth
= 0;
2065 newifp
->frame
.sharpArray
= NULL
;
2066 newifp
->frame
.flags
= flags
;
2067 newifp
->frame
.dormantNext
= NULL
;
2068 newifp
->frame
.xmlNamespace
= NULL
;
2069 newifp
->frame
.blockChain
= NULL
;
2070 if (script
->staticLevel
< JS_DISPLAY_SIZE
) {
2071 JSStackFrame
**disp
= &cx
->display
[script
->staticLevel
];
2072 newifp
->frame
.displaySave
= *disp
;
2073 *disp
= &newifp
->frame
;
2075 newifp
->mark
= newmark
;
2077 /* Compute the 'this' parameter now that argv is set. */
2078 JS_ASSERT(!JSFUN_BOUND_METHOD_TEST(fun
->flags
));
2079 JS_ASSERT(JSVAL_IS_OBJECT(vp
[1]));
2080 newifp
->frame
.thisp
= (JSObject
*)vp
[1];
2082 newifp
->frame
.regs
= NULL
;
2083 newifp
->frame
.imacpc
= NULL
;
2084 newifp
->frame
.slots
= newsp
;
2086 /* Push void to initialize local variables. */
2087 nvars
= fun
->u
.i
.nvars
;
2089 *newsp
++ = JSVAL_VOID
;
2091 /* Scope with a call object parented by callee's parent. */
2092 if (JSFUN_HEAVYWEIGHT_TEST(fun
->flags
) &&
2093 !js_GetCallObject(cx
, &newifp
->frame
)) {
2094 goto bad_inline_call
;
2097 /* Switch version if currentVersion wasn't overridden. */
2098 newifp
->callerVersion
= (JSVersion
) cx
->version
;
2099 if (JS_LIKELY(cx
->version
== currentVersion
)) {
2100 currentVersion
= (JSVersion
) script
->version
;
2101 if (currentVersion
!= cx
->version
)
2102 js_SetVersion(cx
, currentVersion
);
2105 /* Push the frame and set interpreter registers. */
2106 newifp
->callerRegs
= regs
;
2107 fp
->regs
= &newifp
->callerRegs
;
2109 regs
.pc
= script
->code
;
2110 newifp
->frame
.regs
= ®s
;
2111 cx
->fp
= fp
= &newifp
->frame
;
2113 /* Call the debugger hook if present. */
2114 hook
= cx
->debugHooks
->callHook
;
2116 newifp
->hookData
= hook(cx
, &newifp
->frame
, JS_TRUE
, 0,
2117 cx
->debugHooks
->callHookData
);
2118 CHECK_INTERRUPT_HANDLER();
2120 newifp
->hookData
= NULL
;
2123 TRACE_0(EnterFrame
);
2126 JS_RUNTIME_METER(rt
, inlineCalls
);
2128 #ifdef INCLUDE_MOZILLA_DTRACE
2129 /* DTrace function entry, inlines */
2130 if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
2131 jsdtrace_function_entry(cx
, fp
, fun
);
2132 if (JAVASCRIPT_FUNCTION_INFO_ENABLED())
2133 jsdtrace_function_info(cx
, fp
, fp
->down
, fun
);
2134 if (JAVASCRIPT_FUNCTION_ARGS_ENABLED())
2135 jsdtrace_function_args(cx
, fp
, fun
, fp
->argc
, fp
->argv
);
2138 /* Load first op and dispatch it (safe since JSOP_STOP). */
2139 op
= (JSOp
) *regs
.pc
;
2143 JS_ASSERT(fp
->regs
== ®s
);
2144 script
= fp
->script
;
2145 atoms
= script
->atomMap
.vector
;
2146 js_FreeRawStack(cx
, newmark
);
2150 if (fun
->flags
& JSFUN_FAST_NATIVE
) {
2151 #ifdef INCLUDE_MOZILLA_DTRACE
2152 /* DTrace function entry, non-inlines */
2153 if (VALUE_IS_FUNCTION(cx
, lval
)) {
2154 if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
2155 jsdtrace_function_entry(cx
, NULL
, fun
);
2156 if (JAVASCRIPT_FUNCTION_INFO_ENABLED())
2157 jsdtrace_function_info(cx
, NULL
, fp
, fun
);
2158 if (JAVASCRIPT_FUNCTION_ARGS_ENABLED())
2159 jsdtrace_function_args(cx
, fp
, fun
, argc
, vp
+2);
2163 JS_ASSERT(fun
->u
.n
.extra
== 0);
2164 JS_ASSERT(JSVAL_IS_OBJECT(vp
[1]) ||
2165 PRIMITIVE_THIS_TEST(fun
, vp
[1]));
2166 ok
= ((JSFastNative
) fun
->u
.n
.native
)(cx
, argc
, vp
);
2167 #ifdef INCLUDE_MOZILLA_DTRACE
2168 if (VALUE_IS_FUNCTION(cx
, lval
)) {
2169 if (JAVASCRIPT_FUNCTION_RVAL_ENABLED())
2170 jsdtrace_function_rval(cx
, NULL
, fun
, vp
);
2171 if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
2172 jsdtrace_function_return(cx
, NULL
, fun
);
2178 * If we are executing the JSOP_NEXTITER imacro and a Stopiteration
2179 * exception is raised, transform it into a JSVAL_HOLE return value.
2180 * The tracer generates equivalent code by calling CatchStopIteration_tn.
2182 if (fp
->imacpc
&& *fp
->imacpc
== JSOP_NEXTITER
&&
2183 cx
->throwing
&& js_ValueIsStopIteration(cx
->exception
)) {
2184 // pc may point to JSOP_DUP here due to bug 474854.
2185 JS_ASSERT(*regs
.pc
== JSOP_CALL
|| *regs
.pc
== JSOP_DUP
);
2186 cx
->throwing
= JS_FALSE
;
2187 cx
->exception
= JSVAL_VOID
;
2188 regs
.sp
[-1] = JSVAL_HOLE
;
2193 TRACE_0(NativeCallComplete
);
2198 ok
= js_Invoke(cx
, argc
, vp
, 0);
2200 CHECK_INTERRUPT_HANDLER();
2203 JS_RUNTIME_METER(rt
, nonInlineCalls
);
2204 TRACE_0(NativeCallComplete
);
2209 BEGIN_CASE(JSOP_SETCALL
)
2210 argc
= GET_ARGC(regs
.pc
);
2211 vp
= regs
.sp
- argc
- 2;
2212 if (js_Invoke(cx
, argc
, vp
, 0))
2213 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_BAD_LEFTSIDE_OF_ASS
);
2215 END_CASE(JSOP_SETCALL
)
2217 BEGIN_CASE(JSOP_NAME
)
2218 BEGIN_CASE(JSOP_CALLNAME
)
2220 JSPropCacheEntry
*entry
;
2222 obj
= fp
->scopeChain
;
2223 if (JS_LIKELY(OBJ_IS_NATIVE(obj
))) {
2224 PROPERTY_CACHE_TEST(cx
, regs
.pc
, obj
, obj2
, entry
, atom
);
2226 ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj
, obj2
, entry
);
2227 if (PCVAL_IS_OBJECT(entry
->vword
)) {
2228 rval
= PCVAL_OBJECT_TO_JSVAL(entry
->vword
);
2229 JS_UNLOCK_OBJ(cx
, obj2
);
2233 if (PCVAL_IS_SLOT(entry
->vword
)) {
2234 slot
= PCVAL_TO_SLOT(entry
->vword
);
2235 JS_ASSERT(slot
< OBJ_SCOPE(obj2
)->freeslot
);
2236 rval
= LOCKED_OBJ_GET_SLOT(obj2
, slot
);
2237 JS_UNLOCK_OBJ(cx
, obj2
);
2241 JS_ASSERT(PCVAL_IS_SPROP(entry
->vword
));
2242 sprop
= PCVAL_TO_SPROP(entry
->vword
);
2249 id
= ATOM_TO_JSID(atom
);
2250 if (!js_FindPropertyHelper(cx
, id
, true, &obj
, &obj2
, &prop
))
2253 /* Kludge to allow (typeof foo == "undefined") tests. */
2254 endpc
= script
->code
+ script
->length
;
2255 op2
= js_GetOpcode(cx
, script
, regs
.pc
+ JSOP_NAME_LENGTH
);
2256 if (op2
== JSOP_TYPEOF
) {
2257 PUSH_OPND(JSVAL_VOID
);
2258 len
= JSOP_NAME_LENGTH
;
2261 goto atom_not_defined
;
2264 /* Take the slow path if prop was not found in a native object. */
2265 if (!OBJ_IS_NATIVE(obj
) || !OBJ_IS_NATIVE(obj2
)) {
2266 obj2
->dropProperty(cx
, prop
);
2267 if (!obj
->getProperty(cx
, id
, &rval
))
2270 sprop
= (JSScopeProperty
*)prop
;
2272 NATIVE_GET(cx
, obj
, obj2
, sprop
, &rval
);
2273 obj2
->dropProperty(cx
, (JSProperty
*) sprop
);
2278 if (op
== JSOP_CALLNAME
)
2279 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
2283 BEGIN_CASE(JSOP_UINT16
)
2284 i
= (jsint
) GET_UINT16(regs
.pc
);
2285 rval
= INT_TO_JSVAL(i
);
2287 END_CASE(JSOP_UINT16
)
2289 BEGIN_CASE(JSOP_UINT24
)
2290 i
= (jsint
) GET_UINT24(regs
.pc
);
2291 rval
= INT_TO_JSVAL(i
);
2293 END_CASE(JSOP_UINT24
)
2295 BEGIN_CASE(JSOP_INT8
)
2296 i
= GET_INT8(regs
.pc
);
2297 rval
= INT_TO_JSVAL(i
);
2301 BEGIN_CASE(JSOP_INT32
)
2302 i
= GET_INT32(regs
.pc
);
2303 rval
= INT_TO_JSVAL(i
);
2305 END_CASE(JSOP_INT32
)
2307 BEGIN_CASE(JSOP_INDEXBASE
)
2309 * Here atoms can exceed script->atomMap.length as we use atoms
2310 * as a segment register for object literals as well.
2312 atoms
+= GET_INDEXBASE(regs
.pc
);
2313 END_CASE(JSOP_INDEXBASE
)
2315 BEGIN_CASE(JSOP_INDEXBASE1
)
2316 BEGIN_CASE(JSOP_INDEXBASE2
)
2317 BEGIN_CASE(JSOP_INDEXBASE3
)
2318 atoms
+= (op
- JSOP_INDEXBASE1
+ 1) << 16;
2319 END_CASE(JSOP_INDEXBASE3
)
2321 BEGIN_CASE(JSOP_RESETBASE0
)
2322 BEGIN_CASE(JSOP_RESETBASE
)
2323 atoms
= script
->atomMap
.vector
;
2324 END_CASE(JSOP_RESETBASE
)
2326 BEGIN_CASE(JSOP_DOUBLE
)
2327 BEGIN_CASE(JSOP_STRING
)
2329 PUSH_OPND(ATOM_KEY(atom
));
2330 END_CASE(JSOP_DOUBLE
)
2332 BEGIN_CASE(JSOP_OBJECT
)
2334 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
2335 END_CASE(JSOP_OBJECT
)
2337 BEGIN_CASE(JSOP_REGEXP
)
2342 * Push a regexp object for the atom mapped by the bytecode at pc,
2343 * cloning the literal's regexp object if necessary, to simulate in
2344 * the pre-compile/execute-later case what ECMA specifies for the
2345 * compile-and-go case: that scanning each regexp literal creates
2346 * a single corresponding RegExp object.
2348 * To support pre-compilation transparently, we must handle the
2349 * case where a regexp object literal is used in a different global
2350 * at execution time from the global with which it was scanned at
2351 * compile time. We do this by re-wrapping the JSRegExp private
2352 * data struct with a cloned object having the right prototype and
2353 * parent, and having its own lastIndex property value storage.
2355 * Unlike JSOP_DEFFUN and other prolog bytecodes that may clone
2356 * literal objects, we don't want to pay a script prolog execution
2357 * price for all regexp literals in a script (many may not be used
2358 * by a particular execution of that script, depending on control
2359 * flow), so we initialize lazily here.
2361 * XXX This code is specific to regular expression objects. If we
2362 * need a similar op for other kinds of object literals, we should
2363 * push cloning down under JSObjectOps and reuse code here.
2365 index
= GET_FULL_INDEX(0);
2366 JS_ASSERT(index
< JS_SCRIPT_REGEXPS(script
)->length
);
2371 * We're in function code, not global or eval code (in eval
2372 * code, JSOP_REGEXP is never emitted). The cloned funobj
2373 * contains JS_SCRIPT_REGEXPS(script)->length reserved slots
2374 * for the cloned regexps; see fun_reserveSlots, jsfun.c.
2376 funobj
= JSVAL_TO_OBJECT(fp
->argv
[-2]);
2377 slot
+= JSCLASS_RESERVED_SLOTS(&js_FunctionClass
);
2378 if (script
->upvarsOffset
!= 0)
2379 slot
+= JS_SCRIPT_UPVARS(script
)->length
;
2380 if (!JS_GetReservedSlot(cx
, funobj
, slot
, &rval
))
2382 if (JSVAL_IS_VOID(rval
))
2386 * We're in global code. The code generator reserved a slot
2387 * for the regexp among script->nfixed slots. All such slots
2388 * are initialized to null, not void, for faster testing in
2389 * JSOP_*GVAR cases. To simplify index calculations we count
2390 * regexps in the reverse order down from script->nslots - 1.
2392 JS_ASSERT(slot
< script
->nfixed
);
2393 slot
= script
->nfixed
- slot
- 1;
2394 rval
= fp
->slots
[slot
];
2396 funobj
= NULL
; /* suppress bogus gcc warnings */
2400 if (JSVAL_IS_NULL(rval
)) {
2401 /* Compute the current global object in obj2. */
2402 obj2
= fp
->scopeChain
;
2403 while ((parent
= OBJ_GET_PARENT(cx
, obj2
)) != NULL
)
2407 * If obj's parent is not obj2, we must clone obj so that it
2408 * has the right parent, and therefore, the right prototype.
2410 * Yes, this means we assume that the correct RegExp.prototype
2411 * to which regexp instances (including literals) delegate can
2412 * be distinguished solely by the instance's parent, which was
2413 * set to the parent of the RegExp constructor function object
2414 * when the instance was created. In other words,
2416 * (/x/.__parent__ == RegExp.__parent__) implies
2417 * (/x/.__proto__ == RegExp.prototype)
2419 * (unless you assign a different object to RegExp.prototype
2420 * at runtime, in which case, ECMA doesn't specify operation,
2421 * and you get what you deserve).
2423 * This same coupling between instance parent and constructor
2424 * parent turns up everywhere (see jsobj.c's FindClassObject,
2425 * js_ConstructObject, and js_NewObject). It's fundamental to
2426 * the design of the language when you consider multiple global
2427 * objects and separate compilation and execution, even though
2428 * it is not specified fully in ECMA.
2430 JS_GET_SCRIPT_REGEXP(script
, index
, obj
);
2431 if (OBJ_GET_PARENT(cx
, obj
) != obj2
) {
2432 obj
= js_CloneRegExpObject(cx
, obj
, obj2
);
2436 rval
= OBJECT_TO_JSVAL(obj
);
2438 /* Store the regexp object value in its cloneIndex slot. */
2440 if (!JS_SetReservedSlot(cx
, funobj
, slot
, rval
))
2443 fp
->slots
[slot
] = rval
;
2449 END_CASE(JSOP_REGEXP
)
2451 BEGIN_CASE(JSOP_ZERO
)
2452 PUSH_OPND(JSVAL_ZERO
);
2455 BEGIN_CASE(JSOP_ONE
)
2456 PUSH_OPND(JSVAL_ONE
);
2459 BEGIN_CASE(JSOP_NULL
)
2460 PUSH_OPND(JSVAL_NULL
);
2463 BEGIN_CASE(JSOP_FALSE
)
2464 PUSH_OPND(JSVAL_FALSE
);
2465 END_CASE(JSOP_FALSE
)
2467 BEGIN_CASE(JSOP_TRUE
)
2468 PUSH_OPND(JSVAL_TRUE
);
2471 BEGIN_CASE(JSOP_TABLESWITCH
)
2473 len
= GET_JUMP_OFFSET(pc2
);
2476 * ECMAv2+ forbids conversion of discriminant, so we will skip to
2477 * the default case if the discriminant isn't already an int jsval.
2478 * (This opcode is emitted only for dense jsint-domain switches.)
2481 if (JSVAL_IS_INT(rval
)) {
2482 i
= JSVAL_TO_INT(rval
);
2483 } else if (JSVAL_IS_DOUBLE(rval
) && *JSVAL_TO_DOUBLE(rval
) == 0) {
2484 /* Treat -0 (double) as 0. */
2490 pc2
+= JUMP_OFFSET_LEN
;
2491 low
= GET_JUMP_OFFSET(pc2
);
2492 pc2
+= JUMP_OFFSET_LEN
;
2493 high
= GET_JUMP_OFFSET(pc2
);
2496 if ((jsuint
)i
< (jsuint
)(high
- low
+ 1)) {
2497 pc2
+= JUMP_OFFSET_LEN
+ JUMP_OFFSET_LEN
* i
;
2498 off
= (jsint
) GET_JUMP_OFFSET(pc2
);
2504 BEGIN_CASE(JSOP_TABLESWITCHX
)
2506 len
= GET_JUMPX_OFFSET(pc2
);
2509 * ECMAv2+ forbids conversion of discriminant, so we will skip to
2510 * the default case if the discriminant isn't already an int jsval.
2511 * (This opcode is emitted only for dense jsint-domain switches.)
2514 if (JSVAL_IS_INT(rval
)) {
2515 i
= JSVAL_TO_INT(rval
);
2516 } else if (JSVAL_IS_DOUBLE(rval
) && *JSVAL_TO_DOUBLE(rval
) == 0) {
2517 /* Treat -0 (double) as 0. */
2523 pc2
+= JUMPX_OFFSET_LEN
;
2524 low
= GET_JUMP_OFFSET(pc2
);
2525 pc2
+= JUMP_OFFSET_LEN
;
2526 high
= GET_JUMP_OFFSET(pc2
);
2529 if ((jsuint
)i
< (jsuint
)(high
- low
+ 1)) {
2530 pc2
+= JUMP_OFFSET_LEN
+ JUMPX_OFFSET_LEN
* i
;
2531 off
= (jsint
) GET_JUMPX_OFFSET(pc2
);
2537 BEGIN_CASE(JSOP_LOOKUPSWITCHX
)
2538 off
= JUMPX_OFFSET_LEN
;
2539 goto do_lookup_switch
;
2541 BEGIN_CASE(JSOP_LOOKUPSWITCH
)
2542 off
= JUMP_OFFSET_LEN
;
2546 * JSOP_LOOKUPSWITCH and JSOP_LOOKUPSWITCHX are never used if
2547 * any atom index in it would exceed 64K limit.
2549 JS_ASSERT(atoms
== script
->atomMap
.vector
);
2553 if (!JSVAL_IS_NUMBER(lval
) &&
2554 !JSVAL_IS_STRING(lval
) &&
2555 !JSVAL_IS_BOOLEAN(lval
)) {
2556 goto end_lookup_switch
;
2560 npairs
= (jsint
) GET_UINT16(pc2
);
2562 JS_ASSERT(npairs
); /* empty switch uses JSOP_TABLESWITCH */
2564 #define SEARCH_PAIRS(MATCH_CODE) \
2566 JS_ASSERT(GET_INDEX(pc2) < script->atomMap.length); \
2567 atom = atoms[GET_INDEX(pc2)]; \
2568 rval = ATOM_KEY(atom); \
2574 if (--npairs == 0) { \
2579 if (JSVAL_IS_STRING(lval
)) {
2580 str
= JSVAL_TO_STRING(lval
);
2582 match
= (JSVAL_IS_STRING(rval
) &&
2583 ((str2
= JSVAL_TO_STRING(rval
)) == str
||
2584 js_EqualStrings(str2
, str
)));
2586 } else if (JSVAL_IS_DOUBLE(lval
)) {
2587 d
= *JSVAL_TO_DOUBLE(lval
);
2589 match
= (JSVAL_IS_DOUBLE(rval
) &&
2590 *JSVAL_TO_DOUBLE(rval
) == d
);
2594 match
= (lval
== rval
);
2600 len
= (op
== JSOP_LOOKUPSWITCH
)
2601 ? GET_JUMP_OFFSET(pc2
)
2602 : GET_JUMPX_OFFSET(pc2
);
2605 BEGIN_CASE(JSOP_TRAP
)
2607 JSTrapStatus status
;
2609 status
= JS_HandleTrap(cx
, script
, regs
.pc
, &rval
);
2618 cx
->throwing
= JS_TRUE
;
2619 cx
->exception
= rval
;
2624 JS_ASSERT(status
== JSTRAP_CONTINUE
);
2625 CHECK_INTERRUPT_HANDLER();
2626 JS_ASSERT(JSVAL_IS_INT(rval
));
2627 op
= (JSOp
) JSVAL_TO_INT(rval
);
2628 JS_ASSERT((uintN
)op
< (uintN
)JSOP_LIMIT
);
2632 BEGIN_CASE(JSOP_ARGUMENTS
)
2633 if (!js_GetArgsValue(cx
, fp
, &rval
))
2636 END_CASE(JSOP_ARGUMENTS
)
2638 BEGIN_CASE(JSOP_ARGSUB
)
2639 id
= INT_TO_JSID(GET_ARGNO(regs
.pc
));
2640 if (!js_GetArgsProperty(cx
, fp
, id
, &rval
))
2643 END_CASE(JSOP_ARGSUB
)
2645 BEGIN_CASE(JSOP_ARGCNT
)
2646 id
= ATOM_TO_JSID(rt
->atomState
.lengthAtom
);
2647 if (!js_GetArgsProperty(cx
, fp
, id
, &rval
))
2650 END_CASE(JSOP_ARGCNT
)
2652 BEGIN_CASE(JSOP_GETARG
)
2653 BEGIN_CASE(JSOP_CALLARG
)
2654 slot
= GET_ARGNO(regs
.pc
);
2655 JS_ASSERT(slot
< fp
->fun
->nargs
);
2656 METER_SLOT_OP(op
, slot
);
2657 PUSH_OPND(fp
->argv
[slot
]);
2658 if (op
== JSOP_CALLARG
)
2659 PUSH_OPND(JSVAL_NULL
);
2660 END_CASE(JSOP_GETARG
)
2662 BEGIN_CASE(JSOP_SETARG
)
2663 slot
= GET_ARGNO(regs
.pc
);
2664 JS_ASSERT(slot
< fp
->fun
->nargs
);
2665 METER_SLOT_OP(op
, slot
);
2666 vp
= &fp
->argv
[slot
];
2667 *vp
= FETCH_OPND(-1);
2668 END_SET_CASE(JSOP_SETARG
)
2670 BEGIN_CASE(JSOP_GETLOCAL
)
2671 slot
= GET_SLOTNO(regs
.pc
);
2672 JS_ASSERT(slot
< script
->nslots
);
2673 PUSH_OPND(fp
->slots
[slot
]);
2674 END_CASE(JSOP_GETLOCAL
)
2676 BEGIN_CASE(JSOP_CALLLOCAL
)
2677 slot
= GET_SLOTNO(regs
.pc
);
2678 JS_ASSERT(slot
< script
->nslots
);
2679 PUSH_OPND(fp
->slots
[slot
]);
2680 PUSH_OPND(JSVAL_NULL
);
2681 END_CASE(JSOP_CALLLOCAL
)
2683 BEGIN_CASE(JSOP_SETLOCAL
)
2684 slot
= GET_SLOTNO(regs
.pc
);
2685 JS_ASSERT(slot
< script
->nslots
);
2686 vp
= &fp
->slots
[slot
];
2687 *vp
= FETCH_OPND(-1);
2688 END_SET_CASE(JSOP_SETLOCAL
)
2690 BEGIN_CASE(JSOP_GETUPVAR
)
2691 BEGIN_CASE(JSOP_CALLUPVAR
)
2693 JSUpvarArray
*uva
= JS_SCRIPT_UPVARS(script
);
2695 index
= GET_UINT16(regs
.pc
);
2696 JS_ASSERT(index
< uva
->length
);
2698 rval
= js_GetUpvar(cx
, script
->staticLevel
, uva
->vector
[index
]);
2701 if (op
== JSOP_CALLUPVAR
)
2702 PUSH_OPND(JSVAL_NULL
);
2704 END_CASE(JSOP_GETUPVAR
)
2706 BEGIN_CASE(JSOP_GETUPVAR_DBG
)
2707 BEGIN_CASE(JSOP_CALLUPVAR_DBG
)
2709 JS_ASSERT(FUN_KIND(fun
) == JSFUN_INTERPRETED
);
2710 JS_ASSERT(fun
->u
.i
.wrapper
);
2712 /* Scope for tempPool mark and local names allocation in it. */
2714 void *mark
= JS_ARENA_MARK(&cx
->tempPool
);
2715 jsuword
*names
= js_GetLocalNameArray(cx
, fun
, &cx
->tempPool
);
2719 index
= fun
->countArgsAndVars() + GET_UINT16(regs
.pc
);
2720 atom
= JS_LOCAL_NAME_TO_ATOM(names
[index
]);
2721 id
= ATOM_TO_JSID(atom
);
2723 ok
= js_FindProperty(cx
, id
, &obj
, &obj2
, &prop
);
2724 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
2730 goto atom_not_defined
;
2732 /* Minimize footprint with generic code instead of NATIVE_GET. */
2733 obj2
->dropProperty(cx
, prop
);
2735 PUSH_OPND(JSVAL_NULL
);
2736 if (!obj
->getProperty(cx
, id
, vp
))
2739 if (op
== JSOP_CALLUPVAR_DBG
)
2740 PUSH_OPND(JSVAL_NULL
);
2741 END_CASE(JSOP_GETUPVAR_DBG
)
2743 BEGIN_CASE(JSOP_GETDSLOT
)
2744 BEGIN_CASE(JSOP_CALLDSLOT
)
2745 JS_ASSERT(fp
->argv
);
2746 obj
= JSVAL_TO_OBJECT(fp
->argv
[-2]);
2748 JS_ASSERT(obj
->dslots
);
2750 index
= GET_UINT16(regs
.pc
);
2751 JS_ASSERT(JS_INITIAL_NSLOTS
+ index
< jsatomid(obj
->dslots
[-1]));
2752 JS_ASSERT_IF(OBJ_SCOPE(obj
)->object
== obj
,
2753 JS_INITIAL_NSLOTS
+ index
< OBJ_SCOPE(obj
)->freeslot
);
2755 PUSH_OPND(obj
->dslots
[index
]);
2756 if (op
== JSOP_CALLDSLOT
)
2757 PUSH_OPND(JSVAL_NULL
);
2758 END_CASE(JSOP_GETDSLOT
)
2760 BEGIN_CASE(JSOP_GETGVAR
)
2761 BEGIN_CASE(JSOP_CALLGVAR
)
2762 slot
= GET_SLOTNO(regs
.pc
);
2763 JS_ASSERT(slot
< GlobalVarCount(fp
));
2764 METER_SLOT_OP(op
, slot
);
2765 lval
= fp
->slots
[slot
];
2766 if (JSVAL_IS_NULL(lval
)) {
2767 op
= (op
== JSOP_GETGVAR
) ? JSOP_NAME
: JSOP_CALLNAME
;
2771 slot
= JSVAL_TO_INT(lval
);
2772 rval
= OBJ_GET_SLOT(cx
, obj
, slot
);
2774 if (op
== JSOP_CALLGVAR
)
2775 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
2776 END_CASE(JSOP_GETGVAR
)
2778 BEGIN_CASE(JSOP_SETGVAR
)
2779 slot
= GET_SLOTNO(regs
.pc
);
2780 JS_ASSERT(slot
< GlobalVarCount(fp
));
2781 METER_SLOT_OP(op
, slot
);
2782 rval
= FETCH_OPND(-1);
2784 lval
= fp
->slots
[slot
];
2785 if (JSVAL_IS_NULL(lval
)) {
2787 * Inline-clone and deoptimize JSOP_SETNAME code here because
2788 * JSOP_SETGVAR has arity 1: [rval], not arity 2: [obj, rval]
2789 * as JSOP_SETNAME does, where [obj] is due to JSOP_BINDNAME.
2792 if (TRACE_RECORDER(cx
))
2793 js_AbortRecording(cx
, "SETGVAR with NULL slot");
2796 id
= ATOM_TO_JSID(atom
);
2797 if (!obj
->setProperty(cx
, id
, &rval
))
2800 slot
= JSVAL_TO_INT(lval
);
2801 JS_LOCK_OBJ(cx
, obj
);
2802 LOCKED_OBJ_WRITE_SLOT(cx
, obj
, slot
, rval
);
2803 JS_UNLOCK_OBJ(cx
, obj
);
2805 END_SET_CASE(JSOP_SETGVAR
)
2807 BEGIN_CASE(JSOP_DEFCONST
)
2808 BEGIN_CASE(JSOP_DEFVAR
)
2809 index
= GET_INDEX(regs
.pc
);
2810 atom
= atoms
[index
];
2813 * index is relative to atoms at this point but for global var
2814 * code below we need the absolute value.
2816 index
+= atoms
- script
->atomMap
.vector
;
2818 attrs
= JSPROP_ENUMERATE
;
2819 if (!(fp
->flags
& JSFRAME_EVAL
))
2820 attrs
|= JSPROP_PERMANENT
;
2821 if (op
== JSOP_DEFCONST
)
2822 attrs
|= JSPROP_READONLY
;
2824 /* Lookup id in order to check for redeclaration problems. */
2825 id
= ATOM_TO_JSID(atom
);
2827 if (!js_CheckRedeclaration(cx
, obj
, id
, attrs
, &obj2
, &prop
))
2830 /* Bind a variable only if it's not yet defined. */
2832 if (!obj
->defineProperty(cx
, id
, JSVAL_VOID
, JS_PropertyStub
, JS_PropertyStub
,
2841 * Try to optimize a property we either just created, or found
2842 * directly in the global object, that is permanent, has a slot,
2843 * and has stub getter and setter, into a "fast global" accessed
2844 * by the JSOP_*GVAR opcodes.
2847 index
< GlobalVarCount(fp
) &&
2849 OBJ_IS_NATIVE(obj
)) {
2850 sprop
= (JSScopeProperty
*) prop
;
2851 if ((sprop
->attrs
& JSPROP_PERMANENT
) &&
2852 SPROP_HAS_VALID_SLOT(sprop
, OBJ_SCOPE(obj
)) &&
2853 SPROP_HAS_STUB_GETTER(sprop
) &&
2854 SPROP_HAS_STUB_SETTER(sprop
)) {
2856 * Fast globals use frame variables to map the global
2857 * name's atom index to the permanent fp->varobj slot
2858 * number, tagged as a jsval. The atom index for the
2859 * global's name literal is identical to its variable
2862 fp
->slots
[index
] = INT_TO_JSVAL(sprop
->slot
);
2866 obj2
->dropProperty(cx
, prop
);
2867 END_CASE(JSOP_DEFVAR
)
2869 BEGIN_CASE(JSOP_DEFFUN
)
2871 JSPropertyOp getter
, setter
;
2878 * A top-level function defined in Global or Eval code (see
2879 * ECMA-262 Ed. 3), or else a SpiderMonkey extension: a named
2880 * function statement in a compound statement (not at the top
2881 * statement level of global code, or at the top level of a
2885 obj
= FUN_OBJECT(fun
);
2887 if (FUN_NULL_CLOSURE(fun
)) {
2889 * Even a null closure needs a parent for principals finding.
2890 * FIXME: bug 476950, although debugger users may also demand
2891 * some kind of scope link for debugger-assisted eval-in-frame.
2893 obj2
= fp
->scopeChain
;
2895 JS_ASSERT(!FUN_FLAT_CLOSURE(fun
));
2898 * Inline js_GetScopeChain a bit to optimize for the case of a
2899 * top-level function.
2901 if (!fp
->blockChain
) {
2902 obj2
= fp
->scopeChain
;
2904 obj2
= js_GetScopeChain(cx
, fp
);
2911 * If static link is not current scope, clone fun's object to link
2912 * to the current scope via parent. We do this to enable sharing of
2913 * compiled functions among multiple equivalent scopes, amortizing
2914 * the cost of compilation over a number of executions. Examples
2915 * include XUL scripts and event handlers shared among Firefox or
2916 * other Mozilla app chrome windows, and user-defined JS functions
2917 * precompiled and then shared among requests in server-side JS.
2919 if (OBJ_GET_PARENT(cx
, obj
) != obj2
) {
2920 obj
= js_CloneFunctionObject(cx
, fun
, obj2
);
2926 * Protect obj from any GC hiding below JSObject::setProperty or
2927 * JSObject::defineProperty. All paths from here must flow through
2928 * the "Restore fp->scopeChain" code below the
2929 * parent->defineProperty call.
2931 MUST_FLOW_THROUGH("restore_scope");
2932 fp
->scopeChain
= obj
;
2934 rval
= OBJECT_TO_JSVAL(obj
);
2937 * ECMA requires functions defined when entering Eval code to be
2940 attrs
= (fp
->flags
& JSFRAME_EVAL
)
2942 : JSPROP_ENUMERATE
| JSPROP_PERMANENT
;
2945 * Load function flags that are also property attributes. Getters
2946 * and setters do not need a slot, their value is stored elsewhere
2947 * in the property itself, not in obj slots.
2949 setter
= getter
= JS_PropertyStub
;
2950 flags
= JSFUN_GSFLAG2ATTR(fun
->flags
);
2952 /* Function cannot be both getter a setter. */
2953 JS_ASSERT(flags
== JSPROP_GETTER
|| flags
== JSPROP_SETTER
);
2954 attrs
|= flags
| JSPROP_SHARED
;
2956 if (flags
== JSPROP_GETTER
)
2957 getter
= js_CastAsPropertyOp(obj
);
2959 setter
= js_CastAsPropertyOp(obj
);
2963 * We define the function as a property of the variable object and
2964 * not the current scope chain even for the case of function
2965 * expression statements and functions defined by eval inside let
2968 parent
= fp
->varobj
;
2972 * Check for a const property of the same name -- or any kind
2973 * of property if executing with the strict option. We check
2974 * here at runtime as well as at compile-time, to handle eval
2975 * as well as multiple HTML script tags.
2977 id
= ATOM_TO_JSID(fun
->atom
);
2979 ok
= js_CheckRedeclaration(cx
, parent
, id
, attrs
, &pobj
, &prop
);
2984 * We deviate from 10.1.2 in ECMA 262 v3 and under eval use for
2985 * function declarations JSObject::setProperty, not
2986 * JSObject::defineProperty, to preserve the JSOP_PERMANENT
2987 * attribute of existing properties and make sure that such
2988 * properties cannot be deleted.
2990 * We also use JSObject::setProperty for the existing properties of
2991 * Call objects with matching attributes to preserve the native
2992 * getters and setters that store the value of the property in the
2993 * interpreter frame, see bug 467495.
2995 doSet
= (attrs
== JSPROP_ENUMERATE
);
2996 JS_ASSERT_IF(doSet
, fp
->flags
& JSFRAME_EVAL
);
2998 if (parent
== pobj
&&
2999 OBJ_GET_CLASS(cx
, parent
) == &js_CallClass
&&
3000 (old
= ((JSScopeProperty
*) prop
)->attrs
,
3001 !(old
& (JSPROP_GETTER
|JSPROP_SETTER
)) &&
3002 (old
& (JSPROP_ENUMERATE
|JSPROP_PERMANENT
)) == attrs
)) {
3004 * js_CheckRedeclaration must reject attempts to add a
3005 * getter or setter to an existing property without a
3008 JS_ASSERT(!(attrs
& ~(JSPROP_ENUMERATE
|JSPROP_PERMANENT
)));
3009 JS_ASSERT(!(old
& JSPROP_READONLY
));
3012 pobj
->dropProperty(cx
, prop
);
3015 ? parent
->setProperty(cx
, id
, &rval
)
3016 : parent
->defineProperty(cx
, id
, rval
, getter
, setter
, attrs
, NULL
);
3019 /* Restore fp->scopeChain now that obj is defined in fp->varobj. */
3020 fp
->scopeChain
= obj2
;
3022 cx
->weakRoots
.newborn
[GCX_OBJECT
] = NULL
;
3026 END_CASE(JSOP_DEFFUN
)
3028 BEGIN_CASE(JSOP_DEFFUN_FC
)
3029 BEGIN_CASE(JSOP_DEFFUN_DBGFC
)
3032 obj
= (op
== JSOP_DEFFUN_FC
)
3033 ? js_NewFlatClosure(cx
, fun
)
3034 : js_NewDebuggableFlatClosure(cx
, fun
);
3037 rval
= OBJECT_TO_JSVAL(obj
);
3039 attrs
= (fp
->flags
& JSFRAME_EVAL
)
3041 : JSPROP_ENUMERATE
| JSPROP_PERMANENT
;
3043 flags
= JSFUN_GSFLAG2ATTR(fun
->flags
);
3045 attrs
|= flags
| JSPROP_SHARED
;
3049 parent
= fp
->varobj
;
3052 id
= ATOM_TO_JSID(fun
->atom
);
3053 ok
= js_CheckRedeclaration(cx
, parent
, id
, attrs
, NULL
, NULL
);
3055 if (attrs
== JSPROP_ENUMERATE
) {
3056 JS_ASSERT(fp
->flags
& JSFRAME_EVAL
);
3057 ok
= parent
->setProperty(cx
, id
, &rval
);
3059 JS_ASSERT(attrs
& JSPROP_PERMANENT
);
3061 ok
= parent
->defineProperty(cx
, id
, rval
,
3062 (flags
& JSPROP_GETTER
)
3063 ? JS_EXTENSION (JSPropertyOp
) obj
3065 (flags
& JSPROP_SETTER
)
3066 ? JS_EXTENSION (JSPropertyOp
) obj
3074 cx
->weakRoots
.newborn
[GCX_OBJECT
] = NULL
;
3077 END_CASE(JSOP_DEFFUN_FC
)
3079 BEGIN_CASE(JSOP_DEFLOCALFUN
)
3081 * Define a local function (i.e., one nested at the top level of
3082 * another function), parented by the current scope chain, stored
3083 * in a local variable slot that the compiler allocated. This is
3084 * an optimization over JSOP_DEFFUN that avoids requiring a call
3085 * object for the outer function's activation.
3087 LOAD_FUNCTION(SLOTNO_LEN
);
3088 JS_ASSERT(FUN_INTERPRETED(fun
));
3089 JS_ASSERT(!FUN_FLAT_CLOSURE(fun
));
3090 obj
= FUN_OBJECT(fun
);
3092 if (FUN_NULL_CLOSURE(fun
)) {
3093 obj
= js_CloneFunctionObject(cx
, fun
, fp
->scopeChain
);
3097 parent
= js_GetScopeChain(cx
, fp
);
3101 if (OBJ_GET_PARENT(cx
, obj
) != parent
) {
3103 if (TRACE_RECORDER(cx
))
3104 js_AbortRecording(cx
, "DEFLOCALFUN for closure");
3106 obj
= js_CloneFunctionObject(cx
, fun
, parent
);
3112 slot
= GET_SLOTNO(regs
.pc
);
3113 TRACE_2(DefLocalFunSetSlot
, slot
, obj
);
3115 fp
->slots
[slot
] = OBJECT_TO_JSVAL(obj
);
3116 END_CASE(JSOP_DEFLOCALFUN
)
3118 BEGIN_CASE(JSOP_DEFLOCALFUN_FC
)
3119 LOAD_FUNCTION(SLOTNO_LEN
);
3121 obj
= js_NewFlatClosure(cx
, fun
);
3125 slot
= GET_SLOTNO(regs
.pc
);
3126 TRACE_2(DefLocalFunSetSlot
, slot
, obj
);
3128 fp
->slots
[slot
] = OBJECT_TO_JSVAL(obj
);
3129 END_CASE(JSOP_DEFLOCALFUN_FC
)
3131 BEGIN_CASE(JSOP_DEFLOCALFUN_DBGFC
)
3132 LOAD_FUNCTION(SLOTNO_LEN
);
3134 obj
= js_NewDebuggableFlatClosure(cx
, fun
);
3138 slot
= GET_SLOTNO(regs
.pc
);
3139 fp
->slots
[slot
] = OBJECT_TO_JSVAL(obj
);
3140 END_CASE(JSOP_DEFLOCALFUN_DBGFC
)
3142 BEGIN_CASE(JSOP_LAMBDA
)
3143 /* Load the specified function object literal. */
3145 obj
= FUN_OBJECT(fun
);
3147 if (FUN_NULL_CLOSURE(fun
)) {
3148 obj
= js_CloneFunctionObject(cx
, fun
, fp
->scopeChain
);
3152 parent
= js_GetScopeChain(cx
, fp
);
3157 * FIXME: bug 471214, Cloning here even when the compiler saw
3158 * the right parent is wasteful but we don't fully support
3159 * joined function objects, yet.
3161 obj
= js_CloneFunctionObject(cx
, fun
, parent
);
3166 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
3167 END_CASE(JSOP_LAMBDA
)
3169 BEGIN_CASE(JSOP_LAMBDA_FC
)
3172 obj
= js_NewFlatClosure(cx
, fun
);
3176 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
3177 END_CASE(JSOP_LAMBDA_FC
)
3179 BEGIN_CASE(JSOP_LAMBDA_DBGFC
)
3182 obj
= js_NewDebuggableFlatClosure(cx
, fun
);
3186 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
3187 END_CASE(JSOP_LAMBDA_DBGFC
)
3189 BEGIN_CASE(JSOP_CALLEE
)
3190 PUSH_OPND(fp
->argv
[-2]);
3191 END_CASE(JSOP_CALLEE
)
3193 #if JS_HAS_GETTER_SETTER
3194 BEGIN_CASE(JSOP_GETTER
)
3195 BEGIN_CASE(JSOP_SETTER
)
3197 op2
= (JSOp
) *++regs
.pc
;
3199 case JSOP_INDEXBASE
:
3200 atoms
+= GET_INDEXBASE(regs
.pc
);
3201 regs
.pc
+= JSOP_INDEXBASE_LENGTH
- 1;
3202 goto do_getter_setter
;
3203 case JSOP_INDEXBASE1
:
3204 case JSOP_INDEXBASE2
:
3205 case JSOP_INDEXBASE3
:
3206 atoms
+= (op2
- JSOP_INDEXBASE1
+ 1) << 16;
3207 goto do_getter_setter
;
3212 id
= ATOM_TO_JSID(atom
);
3213 rval
= FETCH_OPND(-1);
3218 rval
= FETCH_OPND(-1);
3222 FETCH_OBJECT(cx
, i
- 1, lval
, obj
);
3226 JS_ASSERT(regs
.sp
- StackBase(fp
) >= 2);
3227 rval
= FETCH_OPND(-1);
3230 id
= ATOM_TO_JSID(atom
);
3234 JS_ASSERT(op2
== JSOP_INITELEM
);
3236 JS_ASSERT(regs
.sp
- StackBase(fp
) >= 3);
3237 rval
= FETCH_OPND(-1);
3241 lval
= FETCH_OPND(i
-1);
3242 JS_ASSERT(JSVAL_IS_OBJECT(lval
));
3243 obj
= JSVAL_TO_OBJECT(lval
);
3247 /* Ensure that id has a type suitable for use with obj. */
3249 FETCH_ELEMENT_ID(obj
, i
, id
);
3251 if (JS_TypeOfValue(cx
, rval
) != JSTYPE_FUNCTION
) {
3252 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
3253 JSMSG_BAD_GETTER_OR_SETTER
,
3261 * Getters and setters are just like watchpoints from an access
3262 * control point of view.
3264 if (!obj
->checkAccess(cx
, id
, JSACC_WATCH
, &rtmp
, &attrs
))
3267 if (op
== JSOP_GETTER
) {
3268 getter
= JS_EXTENSION (JSPropertyOp
) JSVAL_TO_OBJECT(rval
);
3269 setter
= JS_PropertyStub
;
3270 attrs
= JSPROP_GETTER
;
3272 getter
= JS_PropertyStub
;
3273 setter
= JS_EXTENSION (JSPropertyOp
) JSVAL_TO_OBJECT(rval
);
3274 attrs
= JSPROP_SETTER
;
3276 attrs
|= JSPROP_ENUMERATE
| JSPROP_SHARED
;
3278 /* Check for a readonly or permanent property of the same name. */
3279 if (!js_CheckRedeclaration(cx
, obj
, id
, attrs
, NULL
, NULL
))
3282 if (!obj
->defineProperty(cx
, id
, JSVAL_VOID
, getter
, setter
, attrs
, NULL
))
3286 if (js_CodeSpec
[op2
].ndefs
)
3287 STORE_OPND(-1, rval
);
3288 len
= js_CodeSpec
[op2
].length
;
3290 #endif /* JS_HAS_GETTER_SETTER */
3292 BEGIN_CASE(JSOP_HOLE
)
3293 PUSH_OPND(JSVAL_HOLE
);
3296 BEGIN_CASE(JSOP_NEWARRAY
)
3297 len
= GET_UINT16(regs
.pc
);
3298 cx
->fp
->assertValidStackDepth(len
);
3299 obj
= js_NewArrayObject(cx
, len
, regs
.sp
- len
, JS_TRUE
);
3303 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
3304 END_CASE(JSOP_NEWARRAY
)
3306 BEGIN_CASE(JSOP_NEWINIT
)
3307 i
= GET_INT8(regs
.pc
);
3308 JS_ASSERT(i
== JSProto_Array
|| i
== JSProto_Object
);
3309 obj
= (i
== JSProto_Array
)
3310 ? js_NewArrayObject(cx
, 0, NULL
)
3311 : js_NewObject(cx
, &js_ObjectClass
, NULL
, NULL
);
3314 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
3316 CHECK_INTERRUPT_HANDLER();
3317 END_CASE(JSOP_NEWINIT
)
3319 BEGIN_CASE(JSOP_ENDINIT
)
3320 if (--fp
->sharpDepth
== 0)
3321 fp
->sharpArray
= NULL
;
3323 /* Re-set the newborn root to the top of this object tree. */
3324 JS_ASSERT(regs
.sp
- StackBase(fp
) >= 1);
3325 lval
= FETCH_OPND(-1);
3326 JS_ASSERT(JSVAL_IS_OBJECT(lval
));
3327 cx
->weakRoots
.newborn
[GCX_OBJECT
] = JSVAL_TO_GCTHING(lval
);
3328 END_CASE(JSOP_ENDINIT
)
3330 BEGIN_CASE(JSOP_INITPROP
)
3331 /* Load the property's initial value into rval. */
3332 JS_ASSERT(regs
.sp
- StackBase(fp
) >= 2);
3333 rval
= FETCH_OPND(-1);
3335 /* Load the object being initialized into lval/obj. */
3336 lval
= FETCH_OPND(-2);
3337 obj
= JSVAL_TO_OBJECT(lval
);
3338 JS_ASSERT(OBJ_IS_NATIVE(obj
));
3339 JS_ASSERT(!OBJ_GET_CLASS(cx
, obj
)->reserveSlots
);
3340 JS_ASSERT(!(LOCKED_OBJ_GET_CLASS(obj
)->flags
&
3341 JSCLASS_SHARE_ALL_PROPERTIES
));
3346 JSPropertyCache
*cache
;
3347 JSPropCacheEntry
*entry
;
3349 JS_LOCK_OBJ(cx
, obj
);
3350 scope
= OBJ_SCOPE(obj
);
3351 JS_ASSERT(!scope
->sealed());
3352 kshape
= scope
->shape
;
3353 cache
= &JS_PROPERTY_CACHE(cx
);
3354 entry
= &cache
->table
[PROPERTY_CACHE_HASH_PC(regs
.pc
, kshape
)];
3355 PCMETER(cache
->pctestentry
= entry
);
3356 PCMETER(cache
->tests
++);
3357 PCMETER(cache
->initests
++);
3359 if (entry
->kpc
== regs
.pc
&&
3360 entry
->kshape
== kshape
&&
3361 PCVCAP_SHAPE(entry
->vcap
) == rt
->protoHazardShape
) {
3362 JS_ASSERT(PCVCAP_TAG(entry
->vcap
) == 0);
3364 PCMETER(cache
->pchits
++);
3365 PCMETER(cache
->inipchits
++);
3367 JS_ASSERT(PCVAL_IS_SPROP(entry
->vword
));
3368 sprop
= PCVAL_TO_SPROP(entry
->vword
);
3369 JS_ASSERT(!(sprop
->attrs
& JSPROP_READONLY
));
3372 * If this property has a non-stub setter, it must be
3373 * __proto__, __parent__, or another "shared prototype"
3374 * built-in. Force a miss to save code size here and let
3375 * the standard code path take care of business.
3377 if (!SPROP_HAS_STUB_SETTER(sprop
))
3378 goto do_initprop_miss
;
3380 if (!scope
->owned()) {
3381 scope
= js_GetMutableScope(cx
, obj
);
3383 JS_UNLOCK_OBJ(cx
, obj
);
3389 * Detect a repeated property name and force a miss to
3390 * share the strict warning code and cope with complexity
3391 * managed by JSScope::add.
3393 if (sprop
->parent
!= scope
->lastProp
)
3394 goto do_initprop_miss
;
3397 * Otherwise this entry must be for a direct property of
3398 * obj, not a proto-property, and there cannot have been
3399 * any deletions of prior properties.
3401 JS_ASSERT(!scope
->hadMiddleDelete());
3402 JS_ASSERT_IF(scope
->table
, !scope
->has(sprop
));
3405 JS_ASSERT(slot
== scope
->freeslot
);
3406 if (slot
< STOBJ_NSLOTS(obj
)) {
3409 if (!js_AllocSlot(cx
, obj
, &slot
)) {
3410 JS_UNLOCK_SCOPE(cx
, scope
);
3413 JS_ASSERT(slot
== sprop
->slot
);
3416 JS_ASSERT(!scope
->lastProp
||
3417 scope
->shape
== scope
->lastProp
->shape
);
3419 JSScopeProperty
*sprop2
=
3420 scope
->add(cx
, sprop
->id
,
3421 sprop
->getter
, sprop
->setter
,
3423 sprop
->flags
, sprop
->shortid
);
3425 js_FreeSlot(cx
, obj
, slot
);
3426 JS_UNLOCK_SCOPE(cx
, scope
);
3429 JS_ASSERT(sprop2
== sprop
);
3431 JS_ASSERT(scope
->owned());
3432 js_LeaveTraceIfGlobalObject(cx
, obj
);
3433 scope
->shape
= sprop
->shape
;
3434 ++scope
->entryCount
;
3435 scope
->lastProp
= sprop
;
3438 LOCKED_OBJ_WRITE_BARRIER(cx
, obj
, slot
, rval
);
3439 TRACE_2(SetPropHit
, entry
, sprop
);
3440 LOCKED_OBJ_SET_SLOT(obj
, slot
, rval
);
3441 JS_UNLOCK_SCOPE(cx
, scope
);
3446 PCMETER(cache
->inipcmisses
++);
3447 JS_UNLOCK_SCOPE(cx
, scope
);
3449 /* Get the immediate property name into id. */
3451 id
= ATOM_TO_JSID(atom
);
3453 /* Set the property named by obj[id] to rval. */
3454 if (!js_CheckRedeclaration(cx
, obj
, id
, JSPROP_INITIALIZER
,
3459 if (!(JS_UNLIKELY(atom
== cx
->runtime
->atomState
.protoAtom
)
3460 ? js_SetPropertyHelper(cx
, obj
, id
, true, &rval
)
3461 : js_DefineNativeProperty(cx
, obj
, id
, rval
, NULL
, NULL
,
3462 JSPROP_ENUMERATE
, 0, 0, NULL
,
3463 JSDNP_CACHE_RESULT
)))
3467 /* Common tail for property cache hit and miss cases. */
3469 END_CASE(JSOP_INITPROP
);
3471 BEGIN_CASE(JSOP_INITELEM
)
3472 /* Pop the element's value into rval. */
3473 JS_ASSERT(regs
.sp
- StackBase(fp
) >= 3);
3474 rval
= FETCH_OPND(-1);
3476 /* Find the object being initialized at top of stack. */
3477 lval
= FETCH_OPND(-3);
3478 JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval
));
3479 obj
= JSVAL_TO_OBJECT(lval
);
3481 /* Fetch id now that we have obj. */
3482 FETCH_ELEMENT_ID(obj
, -2, id
);
3485 * Check for property redeclaration strict warning (we may be in
3486 * an object initialiser, not an array initialiser).
3488 if (!js_CheckRedeclaration(cx
, obj
, id
, JSPROP_INITIALIZER
, NULL
, NULL
))
3492 * If rval is a hole, do not call JSObject::defineProperty. In this case,
3493 * obj must be an array, so if the current op is the last element
3494 * initialiser, set the array length to one greater than id.
3496 if (rval
== JSVAL_HOLE
) {
3497 JS_ASSERT(OBJ_IS_ARRAY(cx
, obj
));
3498 JS_ASSERT(JSID_IS_INT(id
));
3499 JS_ASSERT(jsuint(JSID_TO_INT(id
)) < JS_ARGS_LENGTH_MAX
);
3500 if (js_GetOpcode(cx
, script
, regs
.pc
+ JSOP_INITELEM_LENGTH
) == JSOP_ENDINIT
&&
3501 !js_SetLengthProperty(cx
, obj
, (jsuint
) (JSID_TO_INT(id
) + 1))) {
3505 if (!obj
->defineProperty(cx
, id
, rval
, NULL
, NULL
, JSPROP_ENUMERATE
, NULL
))
3509 END_CASE(JSOP_INITELEM
)
3511 #if JS_HAS_SHARP_VARS
3512 BEGIN_CASE(JSOP_DEFSHARP
)
3513 obj
= fp
->sharpArray
;
3515 obj
= js_NewArrayObject(cx
, 0, NULL
);
3518 fp
->sharpArray
= obj
;
3520 i
= (jsint
) GET_UINT16(regs
.pc
);
3521 id
= INT_TO_JSID(i
);
3522 rval
= FETCH_OPND(-1);
3523 if (JSVAL_IS_PRIMITIVE(rval
)) {
3525 JS_snprintf(numBuf
, sizeof numBuf
, "%u", (unsigned) i
);
3526 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
3527 JSMSG_BAD_SHARP_DEF
, numBuf
);
3530 if (!obj
->defineProperty(cx
, id
, rval
, NULL
, NULL
, JSPROP_ENUMERATE
, NULL
))
3532 END_CASE(JSOP_DEFSHARP
)
3534 BEGIN_CASE(JSOP_USESHARP
)
3535 i
= (jsint
) GET_UINT16(regs
.pc
);
3536 id
= INT_TO_JSID(i
);
3537 obj
= fp
->sharpArray
;
3541 if (!obj
->getProperty(cx
, id
, &rval
))
3544 if (!JSVAL_IS_OBJECT(rval
)) {
3547 JS_snprintf(numBuf
, sizeof numBuf
, "%u", (unsigned) i
);
3548 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
3549 JSMSG_BAD_SHARP_USE
, numBuf
);
3553 END_CASE(JSOP_USESHARP
)
3554 #endif /* JS_HAS_SHARP_VARS */
3556 BEGIN_CASE(JSOP_GOSUB
)
3558 i
= (regs
.pc
- script
->main
) + JSOP_GOSUB_LENGTH
;
3559 PUSH(INT_TO_JSVAL(i
));
3560 len
= GET_JUMP_OFFSET(regs
.pc
);
3563 BEGIN_CASE(JSOP_GOSUBX
)
3565 i
= (regs
.pc
- script
->main
) + JSOP_GOSUBX_LENGTH
;
3566 len
= GET_JUMPX_OFFSET(regs
.pc
);
3567 PUSH(INT_TO_JSVAL(i
));
3570 BEGIN_CASE(JSOP_RETSUB
)
3571 /* Pop [exception or hole, retsub pc-index]. */
3574 JS_ASSERT(JSVAL_IS_BOOLEAN(lval
));
3575 if (JSVAL_TO_BOOLEAN(lval
)) {
3577 * Exception was pending during finally, throw it *before* we
3578 * adjust pc, because pc indexes into script->trynotes. This
3579 * turns out not to be necessary, but it seems clearer. And
3580 * it points out a FIXME: 350509, due to Igor Bukanov.
3582 cx
->throwing
= JS_TRUE
;
3583 cx
->exception
= rval
;
3586 JS_ASSERT(JSVAL_IS_INT(rval
));
3587 len
= JSVAL_TO_INT(rval
);
3588 regs
.pc
= script
->main
;
3591 BEGIN_CASE(JSOP_EXCEPTION
)
3592 JS_ASSERT(cx
->throwing
);
3593 PUSH(cx
->exception
);
3594 cx
->throwing
= JS_FALSE
;
3596 END_CASE(JSOP_EXCEPTION
)
3598 BEGIN_CASE(JSOP_FINALLY
)
3600 END_CASE(JSOP_FINALLY
)
3602 BEGIN_CASE(JSOP_THROWING
)
3603 JS_ASSERT(!cx
->throwing
);
3604 cx
->throwing
= JS_TRUE
;
3605 cx
->exception
= POP_OPND();
3606 END_CASE(JSOP_THROWING
)
3608 BEGIN_CASE(JSOP_THROW
)
3609 JS_ASSERT(!cx
->throwing
);
3611 cx
->throwing
= JS_TRUE
;
3612 cx
->exception
= POP_OPND();
3613 /* let the code at error try to catch the exception. */
3616 BEGIN_CASE(JSOP_SETLOCALPOP
)
3618 * The stack must have a block with at least one local slot below
3619 * the exception object.
3621 JS_ASSERT((size_t) (regs
.sp
- StackBase(fp
)) >= 2);
3622 slot
= GET_UINT16(regs
.pc
);
3623 JS_ASSERT(slot
+ 1 < script
->nslots
);
3624 fp
->slots
[slot
] = POP_OPND();
3625 END_CASE(JSOP_SETLOCALPOP
)
3627 BEGIN_CASE(JSOP_IFPRIMTOP
)
3629 * If the top of stack is of primitive type, jump to our target.
3630 * Otherwise advance to the next opcode.
3632 JS_ASSERT(regs
.sp
> StackBase(fp
));
3633 rval
= FETCH_OPND(-1);
3634 if (JSVAL_IS_PRIMITIVE(rval
)) {
3635 len
= GET_JUMP_OFFSET(regs
.pc
);
3638 END_CASE(JSOP_IFPRIMTOP
)
3640 BEGIN_CASE(JSOP_PRIMTOP
)
3641 JS_ASSERT(regs
.sp
> StackBase(fp
));
3642 lval
= FETCH_OPND(-1);
3643 i
= GET_INT8(regs
.pc
);
3644 if (!JSVAL_IS_PRIMITIVE(lval
)) {
3645 lval
= FETCH_OPND(-2);
3646 js_ReportValueError2(cx
, JSMSG_CANT_CONVERT_TO
,
3653 END_CASE(JSOP_PRIMTOP
)
3655 BEGIN_CASE(JSOP_OBJTOP
)
3656 lval
= FETCH_OPND(-1);
3657 if (JSVAL_IS_PRIMITIVE(lval
)) {
3658 js_ReportValueError(cx
, GET_UINT16(regs
.pc
), -1, lval
, NULL
);
3661 END_CASE(JSOP_OBJTOP
)
3663 BEGIN_CASE(JSOP_INSTANCEOF
)
3664 rval
= FETCH_OPND(-1);
3665 if (JSVAL_IS_PRIMITIVE(rval
) ||
3666 !(obj
= JSVAL_TO_OBJECT(rval
))->map
->ops
->hasInstance
) {
3667 js_ReportValueError(cx
, JSMSG_BAD_INSTANCEOF_RHS
,
3671 lval
= FETCH_OPND(-2);
3673 if (!obj
->map
->ops
->hasInstance(cx
, obj
, lval
, &cond
))
3676 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond
));
3677 END_CASE(JSOP_INSTANCEOF
)
3679 #if JS_HAS_DEBUGGER_KEYWORD
3680 BEGIN_CASE(JSOP_DEBUGGER
)
3682 JSTrapHandler handler
= cx
->debugHooks
->debuggerHandler
;
3684 switch (handler(cx
, script
, regs
.pc
, &rval
,
3685 cx
->debugHooks
->debuggerHandlerData
)) {
3688 case JSTRAP_CONTINUE
:
3695 cx
->throwing
= JS_TRUE
;
3696 cx
->exception
= rval
;
3700 CHECK_INTERRUPT_HANDLER();
3703 END_CASE(JSOP_DEBUGGER
)
3704 #endif /* JS_HAS_DEBUGGER_KEYWORD */
3706 #if JS_HAS_XML_SUPPORT
3707 BEGIN_CASE(JSOP_DEFXMLNS
)
3709 if (!js_SetDefaultXMLNamespace(cx
, rval
))
3711 END_CASE(JSOP_DEFXMLNS
)
3713 BEGIN_CASE(JSOP_ANYNAME
)
3714 if (!js_GetAnyName(cx
, &rval
))
3717 END_CASE(JSOP_ANYNAME
)
3719 BEGIN_CASE(JSOP_QNAMEPART
)
3721 PUSH_OPND(ATOM_KEY(atom
));
3722 END_CASE(JSOP_QNAMEPART
)
3724 BEGIN_CASE(JSOP_QNAMECONST
)
3726 rval
= ATOM_KEY(atom
);
3727 lval
= FETCH_OPND(-1);
3728 obj
= js_ConstructXMLQNameObject(cx
, lval
, rval
);
3731 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
3732 END_CASE(JSOP_QNAMECONST
)
3734 BEGIN_CASE(JSOP_QNAME
)
3735 rval
= FETCH_OPND(-1);
3736 lval
= FETCH_OPND(-2);
3737 obj
= js_ConstructXMLQNameObject(cx
, lval
, rval
);
3741 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
3742 END_CASE(JSOP_QNAME
)
3744 BEGIN_CASE(JSOP_TOATTRNAME
)
3745 rval
= FETCH_OPND(-1);
3746 if (!js_ToAttributeName(cx
, &rval
))
3748 STORE_OPND(-1, rval
);
3749 END_CASE(JSOP_TOATTRNAME
)
3751 BEGIN_CASE(JSOP_TOATTRVAL
)
3752 rval
= FETCH_OPND(-1);
3753 JS_ASSERT(JSVAL_IS_STRING(rval
));
3754 str
= js_EscapeAttributeValue(cx
, JSVAL_TO_STRING(rval
), JS_FALSE
);
3757 STORE_OPND(-1, STRING_TO_JSVAL(str
));
3758 END_CASE(JSOP_TOATTRVAL
)
3760 BEGIN_CASE(JSOP_ADDATTRNAME
)
3761 BEGIN_CASE(JSOP_ADDATTRVAL
)
3762 rval
= FETCH_OPND(-1);
3763 lval
= FETCH_OPND(-2);
3764 str
= JSVAL_TO_STRING(lval
);
3765 str2
= JSVAL_TO_STRING(rval
);
3766 str
= js_AddAttributePart(cx
, op
== JSOP_ADDATTRNAME
, str
, str2
);
3770 STORE_OPND(-1, STRING_TO_JSVAL(str
));
3771 END_CASE(JSOP_ADDATTRNAME
)
3773 BEGIN_CASE(JSOP_BINDXMLNAME
)
3774 lval
= FETCH_OPND(-1);
3775 if (!js_FindXMLProperty(cx
, lval
, &obj
, &id
))
3777 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
3778 PUSH_OPND(ID_TO_VALUE(id
));
3779 END_CASE(JSOP_BINDXMLNAME
)
3781 BEGIN_CASE(JSOP_SETXMLNAME
)
3782 obj
= JSVAL_TO_OBJECT(FETCH_OPND(-3));
3783 rval
= FETCH_OPND(-1);
3784 FETCH_ELEMENT_ID(obj
, -2, id
);
3785 if (!obj
->setProperty(cx
, id
, &rval
))
3787 rval
= FETCH_OPND(-1);
3789 STORE_OPND(-1, rval
);
3790 END_CASE(JSOP_SETXMLNAME
)
3792 BEGIN_CASE(JSOP_CALLXMLNAME
)
3793 BEGIN_CASE(JSOP_XMLNAME
)
3794 lval
= FETCH_OPND(-1);
3795 if (!js_FindXMLProperty(cx
, lval
, &obj
, &id
))
3797 if (!obj
->getProperty(cx
, id
, &rval
))
3799 STORE_OPND(-1, rval
);
3800 if (op
== JSOP_CALLXMLNAME
)
3801 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
3802 END_CASE(JSOP_XMLNAME
)
3804 BEGIN_CASE(JSOP_DESCENDANTS
)
3805 BEGIN_CASE(JSOP_DELDESC
)
3806 FETCH_OBJECT(cx
, -2, lval
, obj
);
3807 rval
= FETCH_OPND(-1);
3808 if (!js_GetXMLDescendants(cx
, obj
, rval
, &rval
))
3811 if (op
== JSOP_DELDESC
) {
3812 regs
.sp
[-1] = rval
; /* set local root */
3813 if (!js_DeleteXMLListElements(cx
, JSVAL_TO_OBJECT(rval
)))
3815 rval
= JSVAL_TRUE
; /* always succeed */
3819 STORE_OPND(-1, rval
);
3820 END_CASE(JSOP_DESCENDANTS
)
3822 BEGIN_CASE(JSOP_FILTER
)
3824 * We push the hole value before jumping to [enditer] so we can
3825 * detect the first iteration and direct js_StepXMLListFilter to
3826 * initialize filter's state.
3828 PUSH_OPND(JSVAL_HOLE
);
3829 len
= GET_JUMP_OFFSET(regs
.pc
);
3833 BEGIN_CASE(JSOP_ENDFILTER
)
3834 cond
= (regs
.sp
[-1] != JSVAL_HOLE
);
3836 /* Exit the "with" block left from the previous iteration. */
3839 if (!js_StepXMLListFilter(cx
, cond
))
3841 if (regs
.sp
[-1] != JSVAL_NULL
) {
3843 * Decrease sp after EnterWith returns as we use sp[-1] there
3844 * to root temporaries.
3846 JS_ASSERT(VALUE_IS_XML(cx
, regs
.sp
[-1]));
3847 if (!js_EnterWith(cx
, -2))
3850 len
= GET_JUMP_OFFSET(regs
.pc
);
3855 END_CASE(JSOP_ENDFILTER
);
3857 BEGIN_CASE(JSOP_TOXML
)
3858 rval
= FETCH_OPND(-1);
3859 obj
= js_ValueToXMLObject(cx
, rval
);
3862 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
3863 END_CASE(JSOP_TOXML
)
3865 BEGIN_CASE(JSOP_TOXMLLIST
)
3866 rval
= FETCH_OPND(-1);
3867 obj
= js_ValueToXMLListObject(cx
, rval
);
3870 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
3871 END_CASE(JSOP_TOXMLLIST
)
3873 BEGIN_CASE(JSOP_XMLTAGEXPR
)
3874 rval
= FETCH_OPND(-1);
3875 str
= js_ValueToString(cx
, rval
);
3878 STORE_OPND(-1, STRING_TO_JSVAL(str
));
3879 END_CASE(JSOP_XMLTAGEXPR
)
3881 BEGIN_CASE(JSOP_XMLELTEXPR
)
3882 rval
= FETCH_OPND(-1);
3883 if (VALUE_IS_XML(cx
, rval
)) {
3884 str
= js_ValueToXMLString(cx
, rval
);
3886 str
= js_ValueToString(cx
, rval
);
3888 str
= js_EscapeElementValue(cx
, str
);
3892 STORE_OPND(-1, STRING_TO_JSVAL(str
));
3893 END_CASE(JSOP_XMLELTEXPR
)
3895 BEGIN_CASE(JSOP_XMLOBJECT
)
3897 obj
= js_CloneXMLObject(cx
, obj
);
3900 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
3901 END_CASE(JSOP_XMLOBJECT
)
3903 BEGIN_CASE(JSOP_XMLCDATA
)
3905 str
= ATOM_TO_STRING(atom
);
3906 obj
= js_NewXMLSpecialObject(cx
, JSXML_CLASS_TEXT
, NULL
, str
);
3909 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
3910 END_CASE(JSOP_XMLCDATA
)
3912 BEGIN_CASE(JSOP_XMLCOMMENT
)
3914 str
= ATOM_TO_STRING(atom
);
3915 obj
= js_NewXMLSpecialObject(cx
, JSXML_CLASS_COMMENT
, NULL
, str
);
3918 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
3919 END_CASE(JSOP_XMLCOMMENT
)
3921 BEGIN_CASE(JSOP_XMLPI
)
3923 str
= ATOM_TO_STRING(atom
);
3924 rval
= FETCH_OPND(-1);
3925 str2
= JSVAL_TO_STRING(rval
);
3926 obj
= js_NewXMLSpecialObject(cx
,
3927 JSXML_CLASS_PROCESSING_INSTRUCTION
,
3931 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
3932 END_CASE(JSOP_XMLPI
)
3934 BEGIN_CASE(JSOP_GETFUNNS
)
3935 if (!js_GetFunctionNamespace(cx
, &rval
))
3938 END_CASE(JSOP_GETFUNNS
)
3939 #endif /* JS_HAS_XML_SUPPORT */
3941 BEGIN_CASE(JSOP_ENTERBLOCK
)
3943 JS_ASSERT(!OBJ_IS_CLONED_BLOCK(obj
));
3944 JS_ASSERT(StackBase(fp
) + OBJ_BLOCK_DEPTH(cx
, obj
) == regs
.sp
);
3945 vp
= regs
.sp
+ OBJ_BLOCK_COUNT(cx
, obj
);
3946 JS_ASSERT(regs
.sp
< vp
);
3947 JS_ASSERT(vp
<= fp
->slots
+ script
->nslots
);
3948 while (regs
.sp
< vp
) {
3949 STORE_OPND(0, JSVAL_VOID
);
3954 JS_ASSERT(fp
->blockChain
== OBJ_GET_PARENT(cx
, obj
));
3957 * The young end of fp->scopeChain may omit blocks if we
3958 * haven't closed over them, but if there are any closure
3959 * blocks on fp->scopeChain, they'd better be (clones of)
3960 * ancestors of the block we're entering now; anything
3961 * else we should have popped off fp->scopeChain when we
3962 * left its static scope.
3964 obj2
= fp
->scopeChain
;
3965 while ((clasp
= OBJ_GET_CLASS(cx
, obj2
)) == &js_WithClass
)
3966 obj2
= OBJ_GET_PARENT(cx
, obj2
);
3967 if (clasp
== &js_BlockClass
&&
3968 obj2
->getAssignedPrivate() == fp
) {
3969 JSObject
*youngestProto
= OBJ_GET_PROTO(cx
, obj2
);
3970 JS_ASSERT(!OBJ_IS_CLONED_BLOCK(youngestProto
));
3972 while ((parent
= OBJ_GET_PARENT(cx
, parent
)) != youngestProto
)
3977 fp
->blockChain
= obj
;
3978 END_CASE(JSOP_ENTERBLOCK
)
3980 BEGIN_CASE(JSOP_LEAVEBLOCKEXPR
)
3981 BEGIN_CASE(JSOP_LEAVEBLOCK
)
3984 JS_ASSERT(OBJ_GET_CLASS(cx
, fp
->blockChain
) == &js_BlockClass
);
3985 uintN blockDepth
= OBJ_BLOCK_DEPTH(cx
, fp
->blockChain
);
3987 JS_ASSERT(blockDepth
<= StackDepth(script
));
3990 * If we're about to leave the dynamic scope of a block that has
3991 * been cloned onto fp->scopeChain, clear its private data, move
3992 * its locals from the stack into the clone, and pop it off the
3995 obj
= fp
->scopeChain
;
3996 if (OBJ_GET_PROTO(cx
, obj
) == fp
->blockChain
) {
3997 JS_ASSERT (OBJ_GET_CLASS(cx
, obj
) == &js_BlockClass
);
3998 if (!js_PutBlockObject(cx
, JS_TRUE
))
4002 /* Pop the block chain, too. */
4003 fp
->blockChain
= OBJ_GET_PARENT(cx
, fp
->blockChain
);
4006 * We will move the result of the expression to the new topmost
4009 if (op
== JSOP_LEAVEBLOCKEXPR
)
4010 rval
= FETCH_OPND(-1);
4011 regs
.sp
-= GET_UINT16(regs
.pc
);
4012 if (op
== JSOP_LEAVEBLOCKEXPR
) {
4013 JS_ASSERT(StackBase(fp
) + blockDepth
== regs
.sp
- 1);
4014 STORE_OPND(-1, rval
);
4016 JS_ASSERT(StackBase(fp
) + blockDepth
== regs
.sp
);
4019 END_CASE(JSOP_LEAVEBLOCK
)
4021 BEGIN_CASE(JSOP_CALLBUILTIN
)
4023 obj
= js_GetBuiltinFunction(cx
, GET_INDEX(regs
.pc
));
4026 rval
= FETCH_OPND(-1);
4028 STORE_OPND(-2, OBJECT_TO_JSVAL(obj
));
4030 goto bad_opcode
; /* This is an imacro-only opcode. */
4032 END_CASE(JSOP_CALLBUILTIN
)
4034 #if JS_HAS_GENERATORS
4035 BEGIN_CASE(JSOP_GENERATOR
)
4036 ASSERT_NOT_THROWING(cx
);
4037 regs
.pc
+= JSOP_GENERATOR_LENGTH
;
4038 obj
= js_NewGenerator(cx
, fp
);
4041 JS_ASSERT(!fp
->callobj
&& !fp
->argsobj
);
4042 fp
->rval
= OBJECT_TO_JSVAL(obj
);
4044 if (inlineCallCount
!= 0)
4048 BEGIN_CASE(JSOP_YIELD
)
4049 ASSERT_NOT_THROWING(cx
);
4050 if (FRAME_TO_GENERATOR(fp
)->state
== JSGEN_CLOSING
) {
4051 js_ReportValueError(cx
, JSMSG_BAD_GENERATOR_YIELD
,
4052 JSDVG_SEARCH_STACK
, fp
->argv
[-2], NULL
);
4055 fp
->rval
= FETCH_OPND(-1);
4056 fp
->flags
|= JSFRAME_YIELDING
;
4057 regs
.pc
+= JSOP_YIELD_LENGTH
;
4061 BEGIN_CASE(JSOP_ARRAYPUSH
)
4062 slot
= GET_UINT16(regs
.pc
);
4063 JS_ASSERT(script
->nfixed
<= slot
);
4064 JS_ASSERT(slot
< script
->nslots
);
4065 lval
= fp
->slots
[slot
];
4066 obj
= JSVAL_TO_OBJECT(lval
);
4067 rval
= FETCH_OPND(-1);
4068 if (!js_ArrayCompPush(cx
, obj
, rval
))
4071 END_CASE(JSOP_ARRAYPUSH
)
4072 #endif /* JS_HAS_GENERATORS */
4074 BEGIN_CASE(JSOP_LOOP
)
4077 #if JS_THREADED_INTERP
4079 L_JSOP_BACKPATCH_POP
:
4081 # if !JS_HAS_GENERATORS
4087 # if !JS_HAS_SHARP_VARS
4092 # if !JS_HAS_DESTRUCTURING
4093 L_JSOP_ENUMCONSTELEM
:
4096 # if !JS_HAS_XML_SUPPORT
4098 L_JSOP_STARTXMLEXPR
:
4126 #endif /* !JS_THREADED_INTERP */