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 if (TraceRecorder
* tr
= TRACE_RECORDER(cx
)) {
78 AbortableRecordingStatus status
= tr
->monitorRecording(op
);
80 case ARECORD_CONTINUE
:
81 moreInterrupts
= true;
84 atoms
= COMMON_ATOMS_START(&rt
->atomState
);
86 DO_OP(); /* keep interrupting for op. */
89 // The code at 'error:' aborts the recording.
92 case ARECORD_COMPLETED
:
95 /* A 'stop' error should have already aborted recording. */
97 JS_NOT_REACHED("Bad recording status");
100 #endif /* !JS_TRACER */
102 #if JS_THREADED_INTERP
105 js_ExitTraceVisState(cx
, R_ABORT
);
107 jumpTable
= moreInterrupts
? interruptJumpTable
: normalJumpTable
;
108 JS_EXTENSION_(goto *normalJumpTable
[op
]);
110 switchMask
= moreInterrupts
? -1 : 0;
116 /* No-ops for ease of decompilation. */
117 ADD_EMPTY_CASE(JSOP_NOP
)
118 ADD_EMPTY_CASE(JSOP_CONDSWITCH
)
119 ADD_EMPTY_CASE(JSOP_TRY
)
120 ADD_EMPTY_CASE(JSOP_TRACE
)
121 #if JS_HAS_XML_SUPPORT
122 ADD_EMPTY_CASE(JSOP_STARTXML
)
123 ADD_EMPTY_CASE(JSOP_STARTXMLEXPR
)
127 /* ADD_EMPTY_CASE is not used here as JSOP_LINENO_LENGTH == 3. */
128 BEGIN_CASE(JSOP_LINENO
)
129 END_CASE(JSOP_LINENO
)
131 BEGIN_CASE(JSOP_PUSH
)
132 PUSH_OPND(JSVAL_VOID
);
139 BEGIN_CASE(JSOP_POPN
)
140 regs
.sp
-= GET_UINT16(regs
.pc
);
142 JS_ASSERT(StackBase(fp
) <= regs
.sp
);
143 obj
= fp
->blockChain
;
145 OBJ_BLOCK_DEPTH(cx
, obj
) + OBJ_BLOCK_COUNT(cx
, obj
)
146 <= (size_t) (regs
.sp
- StackBase(fp
)));
147 for (obj
= fp
->scopeChain
; obj
; obj
= OBJ_GET_PARENT(cx
, obj
)) {
148 clasp
= OBJ_GET_CLASS(cx
, obj
);
149 if (clasp
!= &js_BlockClass
&& clasp
!= &js_WithClass
)
151 if (obj
->getPrivate() != fp
)
153 JS_ASSERT(StackBase(fp
) + OBJ_BLOCK_DEPTH(cx
, obj
)
154 + ((clasp
== &js_BlockClass
)
155 ? OBJ_BLOCK_COUNT(cx
, obj
)
162 BEGIN_CASE(JSOP_SETRVAL
)
163 BEGIN_CASE(JSOP_POPV
)
164 ASSERT_NOT_THROWING(cx
);
165 fp
->rval
= POP_OPND();
168 BEGIN_CASE(JSOP_ENTERWITH
)
169 if (!js_EnterWith(cx
, -1))
173 * We must ensure that different "with" blocks have different stack depth
174 * associated with them. This allows the try handler search to properly
175 * recover the scope chain. Thus we must keep the stack at least at the
178 * We set sp[-1] to the current "with" object to help asserting the
179 * enter/leave balance in [leavewith].
181 regs
.sp
[-1] = OBJECT_TO_JSVAL(fp
->scopeChain
);
182 END_CASE(JSOP_ENTERWITH
)
184 BEGIN_CASE(JSOP_LEAVEWITH
)
185 JS_ASSERT(regs
.sp
[-1] == OBJECT_TO_JSVAL(fp
->scopeChain
));
188 END_CASE(JSOP_LEAVEWITH
)
190 BEGIN_CASE(JSOP_RETURN
)
191 fp
->rval
= POP_OPND();
194 BEGIN_CASE(JSOP_RETRVAL
) /* fp->rval already set */
195 BEGIN_CASE(JSOP_STOP
)
197 * When the inlined frame exits with an exception or an error, ok will be
198 * false after the inline_return label.
200 ASSERT_NOT_THROWING(cx
);
205 * If we are at the end of an imacro, return to its caller in the
208 JS_ASSERT(op
== JSOP_STOP
);
211 JS_ASSERT((uintN
)(regs
.sp
- fp
->slots
) <= script
->nslots
);
212 regs
.pc
= fp
->imacpc
+ js_CodeSpec
[*fp
->imacpc
].length
;
214 atoms
= script
->atomMap
.vector
;
219 JS_ASSERT(regs
.sp
== StackBase(fp
));
220 if ((fp
->flags
& JSFRAME_CONSTRUCTING
) &&
221 JSVAL_IS_PRIMITIVE(fp
->rval
)) {
223 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
224 JSMSG_BAD_NEW_RESULT
,
225 js_ValueToPrintableString(cx
, rval
));
228 fp
->rval
= fp
->thisv
;
234 JSInlineFrame
*ifp
= (JSInlineFrame
*) fp
;
235 void *hookData
= ifp
->hookData
;
237 JS_ASSERT(!fp
->blockChain
);
238 JS_ASSERT(!js_IsActiveWithOrBlock(cx
, fp
->scopeChain
, 0));
240 if (script
->staticLevel
< JS_DISPLAY_SIZE
)
241 cx
->display
[script
->staticLevel
] = fp
->displaySave
;
244 JSInterpreterHook hook
;
247 hook
= cx
->debugHooks
->callHook
;
250 * Do not pass &ok directly as exposing the address inhibits
251 * optimizations and uninitialised warnings.
254 hook(cx
, fp
, JS_FALSE
, &status
, hookData
);
256 CHECK_INTERRUPT_HANDLER();
261 * If fp has a call object, sync values and clear the back-
262 * pointer. This can happen for a lightweight function if it calls eval
263 * unexpectedly (in a way that is hidden from the compiler). See bug
266 fp
->putActivationObjects(cx
);
268 #ifdef INCLUDE_MOZILLA_DTRACE
269 /* DTrace function return, inlines */
270 if (JAVASCRIPT_FUNCTION_RVAL_ENABLED())
271 jsdtrace_function_rval(cx
, fp
, fp
->fun
, &fp
->rval
);
272 if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
273 jsdtrace_function_return(cx
, fp
, fp
->fun
);
276 /* Restore context version only if callee hasn't set version. */
277 if (JS_LIKELY(cx
->version
== currentVersion
)) {
278 currentVersion
= ifp
->callerVersion
;
279 if (currentVersion
!= cx
->version
)
280 js_SetVersion(cx
, currentVersion
);
284 * If inline-constructing, replace primitive rval with the new object
285 * passed in via |this|, and instrument this constructor invocation.
287 if (fp
->flags
& JSFRAME_CONSTRUCTING
) {
288 if (JSVAL_IS_PRIMITIVE(fp
->rval
))
289 fp
->rval
= fp
->thisv
;
290 JS_RUNTIME_METER(cx
->runtime
, constructs
);
293 /* Restore caller's registers. */
294 regs
= ifp
->callerRegs
;
296 /* Store the return value in the caller's operand frame. */
297 regs
.sp
-= 1 + (size_t) ifp
->frame
.argc
;
298 regs
.sp
[-1] = fp
->rval
;
300 bool recursive
= fp
->script
== fp
->down
->script
;
302 /* Restore cx->fp and release the inline frame's space. */
303 cx
->fp
= fp
= fp
->down
;
304 JS_ASSERT(fp
->regs
== &ifp
->callerRegs
);
306 JS_ARENA_RELEASE(&cx
->stackPool
, ifp
->mark
);
308 /* Restore the calling script's interpreter registers. */
310 atoms
= FrameAtomBase(cx
, fp
);
312 /* Resume execution in the calling frame. */
315 JS_ASSERT(js_CodeSpec
[js_GetOpcode(cx
, script
, regs
.pc
)].length
316 == JSOP_CALL_LENGTH
);
318 if (!TRACE_RECORDER(cx
) && recursive
) {
319 if (*(regs
.pc
+ JSOP_CALL_LENGTH
) == JSOP_TRACE
) {
320 regs
.pc
+= JSOP_CALL_LENGTH
;
321 MONITOR_BRANCH(Record_LeaveFrame
);
326 if (*(regs
.pc
+ JSOP_CALL_LENGTH
) == JSOP_TRACE
||
327 *(regs
.pc
+ JSOP_CALL_LENGTH
) == JSOP_NOP
) {
328 JS_STATIC_ASSERT(JSOP_TRACE_LENGTH
== JSOP_NOP_LENGTH
);
329 regs
.pc
+= JSOP_CALL_LENGTH
;
330 len
= JSOP_TRACE_LENGTH
;
332 len
= JSOP_CALL_LENGTH
;
340 BEGIN_CASE(JSOP_DEFAULT
)
343 BEGIN_CASE(JSOP_GOTO
)
344 len
= GET_JUMP_OFFSET(regs
.pc
);
348 BEGIN_CASE(JSOP_IFEQ
)
349 POP_BOOLEAN(cx
, rval
, cond
);
350 if (cond
== JS_FALSE
) {
351 len
= GET_JUMP_OFFSET(regs
.pc
);
356 BEGIN_CASE(JSOP_IFNE
)
357 POP_BOOLEAN(cx
, rval
, cond
);
358 if (cond
!= JS_FALSE
) {
359 len
= GET_JUMP_OFFSET(regs
.pc
);
365 POP_BOOLEAN(cx
, rval
, cond
);
366 if (cond
== JS_TRUE
) {
367 len
= GET_JUMP_OFFSET(regs
.pc
);
374 POP_BOOLEAN(cx
, rval
, cond
);
375 if (cond
== JS_FALSE
) {
376 len
= GET_JUMP_OFFSET(regs
.pc
);
382 BEGIN_CASE(JSOP_DEFAULTX
)
385 BEGIN_CASE(JSOP_GOTOX
)
386 len
= GET_JUMPX_OFFSET(regs
.pc
);
388 END_CASE(JSOP_GOTOX
);
390 BEGIN_CASE(JSOP_IFEQX
)
391 POP_BOOLEAN(cx
, rval
, cond
);
392 if (cond
== JS_FALSE
) {
393 len
= GET_JUMPX_OFFSET(regs
.pc
);
398 BEGIN_CASE(JSOP_IFNEX
)
399 POP_BOOLEAN(cx
, rval
, cond
);
400 if (cond
!= JS_FALSE
) {
401 len
= GET_JUMPX_OFFSET(regs
.pc
);
407 POP_BOOLEAN(cx
, rval
, cond
);
408 if (cond
== JS_TRUE
) {
409 len
= GET_JUMPX_OFFSET(regs
.pc
);
415 BEGIN_CASE(JSOP_ANDX
)
416 POP_BOOLEAN(cx
, rval
, cond
);
417 if (cond
== JS_FALSE
) {
418 len
= GET_JUMPX_OFFSET(regs
.pc
);
425 * If the index value at sp[n] is not an int that fits in a jsval, it could
426 * be an object (an XML QName, AttributeName, or AnyName), but only if we are
427 * compiling with JS_HAS_XML_SUPPORT. Otherwise convert the index value to a
430 #define FETCH_ELEMENT_ID(obj, n, id) \
432 jsval idval_ = FETCH_OPND(n); \
433 if (JSVAL_IS_INT(idval_)) { \
434 id = INT_JSVAL_TO_JSID(idval_); \
436 if (!js_InternNonIntElementId(cx, obj, idval_, &id)) \
438 regs.sp[n] = ID_TO_VALUE(id); \
442 #define TRY_BRANCH_AFTER_COND(cond,spdec) \
445 JS_ASSERT(js_CodeSpec[op].length == 1); \
446 diff_ = (uintN) regs.pc[1] - (uintN) JSOP_IFEQ; \
449 if (cond == (diff_ != 0)) { \
451 len = GET_JUMP_OFFSET(regs.pc); \
454 len = 1 + JSOP_IFEQ_LENGTH; \
460 rval
= FETCH_OPND(-1);
461 if (JSVAL_IS_PRIMITIVE(rval
)) {
462 js_ReportValueError(cx
, JSMSG_IN_NOT_OBJECT
, -1, rval
, NULL
);
465 obj
= JSVAL_TO_OBJECT(rval
);
466 FETCH_ELEMENT_ID(obj
, -2, id
);
467 if (!obj
->lookupProperty(cx
, id
, &obj2
, &prop
))
471 obj2
->dropProperty(cx
, prop
);
472 TRY_BRANCH_AFTER_COND(cond
, 2);
474 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond
));
477 BEGIN_CASE(JSOP_ITER
)
478 JS_ASSERT(regs
.sp
> StackBase(fp
));
480 if (!js_ValueToIterator(cx
, flags
, ®s
.sp
[-1]))
482 CHECK_INTERRUPT_HANDLER();
483 JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs
.sp
[-1]));
487 BEGIN_CASE(JSOP_NEXTITER
)
488 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
489 JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs
.sp
[-2]));
490 if (!js_CallIteratorNext(cx
, JSVAL_TO_OBJECT(regs
.sp
[-2]), ®s
.sp
[-1]))
492 CHECK_INTERRUPT_HANDLER();
493 rval
= BOOLEAN_TO_JSVAL(regs
.sp
[-1] != JSVAL_HOLE
);
495 END_CASE(JSOP_NEXTITER
)
497 BEGIN_CASE(JSOP_ENDITER
)
499 * Decrease the stack pointer even when !ok -- see comments in the
500 * exception capturing code for details.
502 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
503 ok
= js_CloseIterator(cx
, regs
.sp
[-2]);
507 END_CASE(JSOP_ENDITER
)
509 BEGIN_CASE(JSOP_FORARG
)
510 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
511 slot
= GET_ARGNO(regs
.pc
);
512 JS_ASSERT(slot
< fp
->fun
->nargs
);
513 fp
->argv
[slot
] = regs
.sp
[-1];
514 END_CASE(JSOP_FORARG
)
516 BEGIN_CASE(JSOP_FORLOCAL
)
517 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
518 slot
= GET_SLOTNO(regs
.pc
);
519 JS_ASSERT(slot
< fp
->script
->nslots
);
520 fp
->slots
[slot
] = regs
.sp
[-1];
521 END_CASE(JSOP_FORLOCAL
)
523 BEGIN_CASE(JSOP_FORNAME
)
524 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
526 id
= ATOM_TO_JSID(atom
);
527 if (!js_FindProperty(cx
, id
, &obj
, &obj2
, &prop
))
530 obj2
->dropProperty(cx
, prop
);
531 ok
= obj
->setProperty(cx
, id
, ®s
.sp
[-1]);
534 END_CASE(JSOP_FORNAME
)
536 BEGIN_CASE(JSOP_FORPROP
)
537 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
539 id
= ATOM_TO_JSID(atom
);
540 FETCH_OBJECT(cx
, -1, lval
, obj
);
541 ok
= obj
->setProperty(cx
, id
, ®s
.sp
[-2]);
545 END_CASE(JSOP_FORPROP
)
547 BEGIN_CASE(JSOP_FORELEM
)
549 * JSOP_FORELEM simply dups the property identifier at top of stack and
550 * lets the subsequent JSOP_ENUMELEM opcode sequence handle the left-hand
551 * side expression evaluation and assignment. This opcode exists solely to
552 * help the decompiler.
554 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
555 rval
= FETCH_OPND(-1);
557 END_CASE(JSOP_FORELEM
)
560 JS_ASSERT(regs
.sp
> StackBase(fp
));
561 rval
= FETCH_OPND(-1);
565 BEGIN_CASE(JSOP_DUP2
)
566 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
567 lval
= FETCH_OPND(-2);
568 rval
= FETCH_OPND(-1);
573 BEGIN_CASE(JSOP_SWAP
)
574 JS_ASSERT(regs
.sp
- 2 >= StackBase(fp
));
575 lval
= FETCH_OPND(-2);
576 rval
= FETCH_OPND(-1);
577 STORE_OPND(-1, lval
);
578 STORE_OPND(-2, rval
);
581 BEGIN_CASE(JSOP_PICK
)
583 JS_ASSERT(regs
.sp
- (i
+1) >= StackBase(fp
));
584 lval
= regs
.sp
[-(i
+1)];
585 memmove(regs
.sp
- (i
+1), regs
.sp
- i
, sizeof(jsval
)*i
);
589 #define PROPERTY_OP(n, call) \
591 /* Fetch the left part and resolve it to a non-null object. */ \
592 FETCH_OBJECT(cx, n, lval, obj); \
594 /* Get or set the property. */ \
599 #define ELEMENT_OP(n, call) \
601 /* Fetch the left part and resolve it to a non-null object. */ \
602 FETCH_OBJECT(cx, n - 1, lval, obj); \
604 /* Fetch index and convert it to id suitable for use with obj. */ \
605 FETCH_ELEMENT_ID(obj, n, id); \
607 /* Get or set the element. */ \
612 #define NATIVE_GET(cx,obj,pobj,sprop,getHow,vp) \
614 if (SPROP_HAS_STUB_GETTER(sprop)) { \
615 /* Fast path for Object instance properties. */ \
616 JS_ASSERT((sprop)->slot != SPROP_INVALID_SLOT || \
617 !SPROP_HAS_STUB_SETTER(sprop)); \
618 *vp = ((sprop)->slot != SPROP_INVALID_SLOT) \
619 ? LOCKED_OBJ_GET_SLOT(pobj, (sprop)->slot) \
622 if (!js_NativeGet(cx, obj, pobj, sprop, getHow, vp)) \
627 #define NATIVE_SET(cx,obj,sprop,entry,vp) \
629 TRACE_2(SetPropHit, entry, sprop); \
630 if (SPROP_HAS_STUB_SETTER(sprop) && \
631 (sprop)->slot != SPROP_INVALID_SLOT && \
632 !OBJ_SCOPE(obj)->branded()) { \
633 /* Fast path for, e.g., plain Object instance properties. */ \
634 LOCKED_OBJ_SET_SLOT(obj, (sprop)->slot, *vp); \
636 if (!js_NativeSet(cx, obj, sprop, false, vp)) \
642 * Skip the JSOP_POP typically found after a JSOP_SET* opcode, where oplen is
643 * the constant length of the SET opcode sequence, and spdec is the constant
644 * by which to decrease the stack pointer to pop all of the SET op's operands.
646 * NB: unlike macros that could conceivably be replaced by functions (ignoring
647 * goto error), where a call should not have to be braced in order to expand
648 * correctly (e.g., in if (cond) FOO(); else BAR()), these three macros lack
649 * JS_{BEGIN,END}_MACRO brackets. They are also indented so as to align with
650 * nearby opcode code.
652 #define SKIP_POP_AFTER_SET(oplen,spdec) \
653 if (regs.pc[oplen] == JSOP_POP) { \
655 regs.pc += oplen + JSOP_POP_LENGTH; \
656 op = (JSOp) *regs.pc; \
660 #define END_SET_CASE(OP) \
661 SKIP_POP_AFTER_SET(OP##_LENGTH, 1); \
664 #define END_SET_CASE_STORE_RVAL(OP,spdec) \
665 SKIP_POP_AFTER_SET(OP##_LENGTH, spdec); \
666 rval = FETCH_OPND(-1); \
667 regs.sp -= (spdec) - 1; \
668 STORE_OPND(-1, rval); \
671 BEGIN_CASE(JSOP_SETCONST
)
674 rval
= FETCH_OPND(-1);
675 if (!obj
->defineProperty(cx
, ATOM_TO_JSID(atom
), rval
,
676 JS_PropertyStub
, JS_PropertyStub
,
677 JSPROP_ENUMERATE
| JSPROP_PERMANENT
| JSPROP_READONLY
)) {
680 END_SET_CASE(JSOP_SETCONST
);
682 #if JS_HAS_DESTRUCTURING
683 BEGIN_CASE(JSOP_ENUMCONSTELEM
)
684 rval
= FETCH_OPND(-3);
685 FETCH_OBJECT(cx
, -2, lval
, obj
);
686 FETCH_ELEMENT_ID(obj
, -1, id
);
687 if (!obj
->defineProperty(cx
, id
, rval
,
688 JS_PropertyStub
, JS_PropertyStub
,
689 JSPROP_ENUMERATE
| JSPROP_PERMANENT
| JSPROP_READONLY
)) {
693 END_CASE(JSOP_ENUMCONSTELEM
)
696 BEGIN_CASE(JSOP_BINDNAME
)
698 JSPropCacheEntry
*entry
;
701 * We can skip the property lookup for the global object. If the
702 * property does not exist anywhere on the scope chain, JSOP_SETNAME
703 * adds the property to the global.
705 * As a consequence of this optimization for the global object we run
706 * its JSRESOLVE_ASSIGNING-tolerant resolve hooks only in JSOP_SETNAME,
707 * after the interpreter evaluates the right- hand-side of the
708 * assignment, and not here.
710 * This should be transparent to the hooks because the script, instead
711 * of name = rhs, could have used global.name = rhs given a global
712 * object reference, which also calls the hooks only after evaluating
713 * the rhs. We desire such resolve hook equivalence between the two
716 obj
= fp
->scopeChain
;
717 if (!OBJ_GET_PARENT(cx
, obj
))
719 if (JS_LIKELY(OBJ_IS_NATIVE(obj
))) {
720 PROPERTY_CACHE_TEST(cx
, regs
.pc
, obj
, obj2
, entry
, atom
);
722 ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj
, obj2
, entry
);
723 JS_UNLOCK_OBJ(cx
, obj2
);
730 id
= ATOM_TO_JSID(atom
);
731 obj
= js_FindIdentifierBase(cx
, fp
->scopeChain
, id
);
735 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
736 END_CASE(JSOP_BINDNAME
)
738 BEGIN_CASE(JSOP_IMACOP
)
739 JS_ASSERT(JS_UPTRDIFF(fp
->imacpc
, script
->code
) < script
->length
);
740 op
= JSOp(*fp
->imacpc
);
743 #define BITWISE_OP(OP) \
745 FETCH_INT(cx, -2, i); \
746 FETCH_INT(cx, -1, j); \
749 STORE_INT(cx, -1, i); \
752 BEGIN_CASE(JSOP_BITOR
)
756 BEGIN_CASE(JSOP_BITXOR
)
758 END_CASE(JSOP_BITXOR
)
760 BEGIN_CASE(JSOP_BITAND
)
762 END_CASE(JSOP_BITAND
)
764 #define RELATIONAL_OP(OP) \
766 rval = FETCH_OPND(-1); \
767 lval = FETCH_OPND(-2); \
768 /* Optimize for two int-tagged operands (typical loop control). */ \
769 if ((lval & rval) & JSVAL_INT) { \
770 cond = JSVAL_TO_INT(lval) OP JSVAL_TO_INT(rval); \
772 if (!JSVAL_IS_PRIMITIVE(lval)) \
773 DEFAULT_VALUE(cx, -2, JSTYPE_NUMBER, lval); \
774 if (!JSVAL_IS_PRIMITIVE(rval)) \
775 DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \
776 if (JSVAL_IS_STRING(lval) && JSVAL_IS_STRING(rval)) { \
777 str = JSVAL_TO_STRING(lval); \
778 str2 = JSVAL_TO_STRING(rval); \
779 cond = js_CompareStrings(str, str2) OP 0; \
781 VALUE_TO_NUMBER(cx, -2, lval, d); \
782 VALUE_TO_NUMBER(cx, -1, rval, d2); \
783 cond = JSDOUBLE_COMPARE(d, OP, d2, JS_FALSE); \
786 TRY_BRANCH_AFTER_COND(cond, 2); \
788 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
792 * NB: These macros can't use JS_BEGIN_MACRO/JS_END_MACRO around their bodies
793 * because they begin if/else chains, so callers must not put semicolons after
794 * the call expressions!
796 #if JS_HAS_XML_SUPPORT
797 #define XML_EQUALITY_OP(OP) \
798 if ((ltmp == JSVAL_OBJECT && \
799 (obj2 = JSVAL_TO_OBJECT(lval)) && \
800 OBJECT_IS_XML(cx, obj2)) || \
801 (rtmp == JSVAL_OBJECT && \
802 (obj2 = JSVAL_TO_OBJECT(rval)) && \
803 OBJECT_IS_XML(cx, obj2))) { \
804 if (JSVAL_IS_OBJECT(rval) && obj2 == JSVAL_TO_OBJECT(rval)) \
806 if (!js_TestXMLEquality(cx, obj2, rval, &cond)) \
808 cond = cond OP JS_TRUE; \
811 #define EXTENDED_EQUALITY_OP(OP) \
812 if (ltmp == JSVAL_OBJECT && \
813 (obj2 = JSVAL_TO_OBJECT(lval)) && \
814 ((clasp = OBJ_GET_CLASS(cx, obj2))->flags & JSCLASS_IS_EXTENDED)) { \
815 JSExtendedClass *xclasp; \
817 xclasp = (JSExtendedClass *) clasp; \
818 if (!xclasp->equality(cx, obj2, rval, &cond)) \
820 cond = cond OP JS_TRUE; \
823 #define XML_EQUALITY_OP(OP) /* nothing */
824 #define EXTENDED_EQUALITY_OP(OP) /* nothing */
827 #define EQUALITY_OP(OP, IFNAN) \
829 rval = FETCH_OPND(-1); \
830 lval = FETCH_OPND(-2); \
831 ltmp = JSVAL_TAG(lval); \
832 rtmp = JSVAL_TAG(rval); \
833 XML_EQUALITY_OP(OP) \
834 if (ltmp == rtmp) { \
835 if (ltmp == JSVAL_STRING) { \
836 str = JSVAL_TO_STRING(lval); \
837 str2 = JSVAL_TO_STRING(rval); \
838 cond = js_EqualStrings(str, str2) OP JS_TRUE; \
839 } else if (ltmp == JSVAL_DOUBLE) { \
840 d = *JSVAL_TO_DOUBLE(lval); \
841 d2 = *JSVAL_TO_DOUBLE(rval); \
842 cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN); \
844 EXTENDED_EQUALITY_OP(OP) \
845 /* Handle all undefined (=>NaN) and int combinations. */ \
846 cond = lval OP rval; \
849 if (JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval)) { \
850 cond = (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) OP 1; \
851 } else if (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) { \
854 if (ltmp == JSVAL_OBJECT) { \
855 DEFAULT_VALUE(cx, -2, JSTYPE_VOID, lval); \
856 ltmp = JSVAL_TAG(lval); \
857 } else if (rtmp == JSVAL_OBJECT) { \
858 DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval); \
859 rtmp = JSVAL_TAG(rval); \
861 if (ltmp == JSVAL_STRING && rtmp == JSVAL_STRING) { \
862 str = JSVAL_TO_STRING(lval); \
863 str2 = JSVAL_TO_STRING(rval); \
864 cond = js_EqualStrings(str, str2) OP JS_TRUE; \
866 VALUE_TO_NUMBER(cx, -2, lval, d); \
867 VALUE_TO_NUMBER(cx, -1, rval, d2); \
868 cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN); \
872 TRY_BRANCH_AFTER_COND(cond, 2); \
874 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
878 EQUALITY_OP(==, JS_FALSE
);
882 EQUALITY_OP(!=, JS_TRUE
);
885 #define STRICT_EQUALITY_OP(OP) \
887 rval = FETCH_OPND(-1); \
888 lval = FETCH_OPND(-2); \
889 cond = js_StrictlyEqual(cx, lval, rval) OP JS_TRUE; \
891 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
894 BEGIN_CASE(JSOP_STRICTEQ
)
895 STRICT_EQUALITY_OP(==);
896 END_CASE(JSOP_STRICTEQ
)
898 BEGIN_CASE(JSOP_STRICTNE
)
899 STRICT_EQUALITY_OP(!=);
900 END_CASE(JSOP_STRICTNE
)
902 BEGIN_CASE(JSOP_CASE
)
903 STRICT_EQUALITY_OP(==);
906 len
= GET_JUMP_OFFSET(regs
.pc
);
912 BEGIN_CASE(JSOP_CASEX
)
913 STRICT_EQUALITY_OP(==);
916 len
= GET_JUMPX_OFFSET(regs
.pc
);
941 #define SIGNED_SHIFT_OP(OP) \
943 FETCH_INT(cx, -2, i); \
944 FETCH_INT(cx, -1, j); \
947 STORE_INT(cx, -1, i); \
958 BEGIN_CASE(JSOP_URSH
)
962 FETCH_UINT(cx
, -2, u
);
963 FETCH_INT(cx
, -1, j
);
966 STORE_UINT(cx
, -1, u
);
971 #undef SIGNED_SHIFT_OP
974 rval
= FETCH_OPND(-1);
975 lval
= FETCH_OPND(-2);
976 #if JS_HAS_XML_SUPPORT
977 if (!JSVAL_IS_PRIMITIVE(lval
) &&
978 (obj2
= JSVAL_TO_OBJECT(lval
), OBJECT_IS_XML(cx
, obj2
)) &&
979 VALUE_IS_XML(cx
, rval
)) {
980 if (!js_ConcatenateXML(cx
, obj2
, rval
, &rval
))
983 STORE_OPND(-1, rval
);
987 if (!JSVAL_IS_PRIMITIVE(lval
))
988 DEFAULT_VALUE(cx
, -2, JSTYPE_VOID
, lval
);
989 if (!JSVAL_IS_PRIMITIVE(rval
))
990 DEFAULT_VALUE(cx
, -1, JSTYPE_VOID
, rval
);
991 if ((cond
= JSVAL_IS_STRING(lval
)) || JSVAL_IS_STRING(rval
)) {
993 str
= JSVAL_TO_STRING(lval
);
994 str2
= js_ValueToString(cx
, rval
);
997 regs
.sp
[-1] = STRING_TO_JSVAL(str2
);
999 str2
= JSVAL_TO_STRING(rval
);
1000 str
= js_ValueToString(cx
, lval
);
1003 regs
.sp
[-2] = STRING_TO_JSVAL(str
);
1005 str
= js_ConcatStrings(cx
, str
, str2
);
1009 STORE_OPND(-1, STRING_TO_JSVAL(str
));
1011 VALUE_TO_NUMBER(cx
, -2, lval
, d
);
1012 VALUE_TO_NUMBER(cx
, -1, rval
, d2
);
1015 STORE_NUMBER(cx
, -1, d
);
1020 BEGIN_CASE(JSOP_CONCATN
)
1023 JS_ASSERT_IF(fp
->imacpc
,
1024 *fp
->imacpc
== JSOP_CONCATN
&& *regs
.pc
== JSOP_IMACOP
);
1027 * This instruction can be executed in three contexts. (1) is normal
1028 * execution. (2) is while recording, during an imacro 'imacop'. (3) is
1029 * during a failed recording or when trace execution aborts during a
1031 * 1. !imacro : N args on stack, pc is regs.pc
1032 * 2. imacro && recording : N args on stack, pc is fp->imacpc
1033 * 3. imacro && !recording : N+2 args on stack, pc is fp->imacpc
1035 bool imacro
= fp
->imacpc
!= NULL
;
1036 bool recording
= TRACE_RECORDER(cx
) != NULL
;
1038 argc
= GET_ARGC(fp
->imacpc
);
1040 js_ConcatPostImacroStackCleanup(argc
, regs
, NULL
);
1042 #endif /* JS_TRACER */
1043 argc
= GET_ARGC(regs
.pc
);
1046 #endif /* JS_TRACER */
1048 JSCharBuffer
buf(cx
);
1049 for (vp
= regs
.sp
- argc
; vp
< regs
.sp
; vp
++) {
1050 if ((!JSVAL_IS_PRIMITIVE(*vp
) &&
1051 !JSVAL_TO_OBJECT(*vp
)->defaultValue(cx
, JSTYPE_VOID
, vp
)) ||
1052 !js_ValueToCharBuffer(cx
, *vp
, buf
)) {
1057 str
= js_NewStringFromCharBuffer(cx
, buf
);
1061 regs
.sp
-= argc
- 1;
1062 STORE_OPND(-1, STRING_TO_JSVAL(str
));
1066 /* END_CASE does pc += CONCATN_LENGTH. (IMACOP YOU IDIOT!) */
1067 regs
.pc
-= JSOP_CONCATN_LENGTH
- JSOP_IMACOP_LENGTH
;
1069 #endif /* JS_TRACER */
1071 END_CASE(JSOP_CONCATN
)
1073 #define BINARY_OP(OP) \
1075 FETCH_NUMBER(cx, -2, d); \
1076 FETCH_NUMBER(cx, -1, d2); \
1079 STORE_NUMBER(cx, -1, d); \
1082 BEGIN_CASE(JSOP_SUB
)
1086 BEGIN_CASE(JSOP_MUL
)
1090 BEGIN_CASE(JSOP_DIV
)
1091 FETCH_NUMBER(cx
, -1, d2
);
1092 FETCH_NUMBER(cx
, -2, d
);
1096 /* XXX MSVC miscompiles such that (NaN == 0) */
1097 if (JSDOUBLE_IS_NaN(d2
))
1098 rval
= rt
->NaNValue
;
1101 if (d
== 0 || JSDOUBLE_IS_NaN(d
))
1102 rval
= rt
->NaNValue
;
1103 else if (JSDOUBLE_IS_NEG(d
) != JSDOUBLE_IS_NEG(d2
))
1104 rval
= rt
->negativeInfinityValue
;
1106 rval
= rt
->positiveInfinityValue
;
1107 STORE_OPND(-1, rval
);
1110 STORE_NUMBER(cx
, -1, d
);
1114 BEGIN_CASE(JSOP_MOD
)
1115 FETCH_NUMBER(cx
, -1, d2
);
1116 FETCH_NUMBER(cx
, -2, d
);
1119 STORE_OPND(-1, rt
->NaNValue
);
1122 STORE_NUMBER(cx
, -1, d
);
1126 BEGIN_CASE(JSOP_NOT
)
1127 POP_BOOLEAN(cx
, rval
, cond
);
1128 PUSH_OPND(BOOLEAN_TO_JSVAL(!cond
));
1131 BEGIN_CASE(JSOP_BITNOT
)
1132 FETCH_INT(cx
, -1, i
);
1134 STORE_INT(cx
, -1, i
);
1135 END_CASE(JSOP_BITNOT
)
1137 BEGIN_CASE(JSOP_NEG
)
1139 * When the operand is int jsval, INT_FITS_IN_JSVAL(i) implies
1140 * INT_FITS_IN_JSVAL(-i) unless i is 0 or JSVAL_INT_MIN when the
1141 * results, -0.0 or JSVAL_INT_MAX + 1, are jsdouble values.
1143 rval
= FETCH_OPND(-1);
1144 if (JSVAL_IS_INT(rval
) &&
1145 rval
!= INT_TO_JSVAL(JSVAL_INT_MIN
) &&
1146 (i
= JSVAL_TO_INT(rval
)) != 0) {
1147 JS_STATIC_ASSERT(!INT_FITS_IN_JSVAL(-JSVAL_INT_MIN
));
1149 JS_ASSERT(INT_FITS_IN_JSVAL(i
));
1150 regs
.sp
[-1] = INT_TO_JSVAL(i
);
1152 if (JSVAL_IS_DOUBLE(rval
)) {
1153 d
= *JSVAL_TO_DOUBLE(rval
);
1155 d
= js_ValueToNumber(cx
, ®s
.sp
[-1]);
1156 if (JSVAL_IS_NULL(regs
.sp
[-1]))
1158 JS_ASSERT(JSVAL_IS_NUMBER(regs
.sp
[-1]) ||
1159 regs
.sp
[-1] == JSVAL_TRUE
);
1162 if (!js_NewNumberInRootedValue(cx
, d
, ®s
.sp
[-1]))
1167 BEGIN_CASE(JSOP_POS
)
1168 rval
= FETCH_OPND(-1);
1169 if (!JSVAL_IS_NUMBER(rval
)) {
1170 d
= js_ValueToNumber(cx
, ®s
.sp
[-1]);
1172 if (JSVAL_IS_NULL(rval
))
1174 if (rval
== JSVAL_TRUE
) {
1175 if (!js_NewNumberInRootedValue(cx
, d
, ®s
.sp
[-1]))
1178 JS_ASSERT(JSVAL_IS_NUMBER(rval
));
1183 BEGIN_CASE(JSOP_DELNAME
)
1185 id
= ATOM_TO_JSID(atom
);
1186 if (!js_FindProperty(cx
, id
, &obj
, &obj2
, &prop
))
1189 /* ECMA says to return true if name is undefined or inherited. */
1190 PUSH_OPND(JSVAL_TRUE
);
1192 obj2
->dropProperty(cx
, prop
);
1193 if (!obj
->deleteProperty(cx
, id
, ®s
.sp
[-1]))
1196 END_CASE(JSOP_DELNAME
)
1198 BEGIN_CASE(JSOP_DELPROP
)
1200 id
= ATOM_TO_JSID(atom
);
1201 PROPERTY_OP(-1, obj
->deleteProperty(cx
, id
, &rval
));
1202 STORE_OPND(-1, rval
);
1203 END_CASE(JSOP_DELPROP
)
1205 BEGIN_CASE(JSOP_DELELEM
)
1206 ELEMENT_OP(-1, obj
->deleteProperty(cx
, id
, &rval
));
1208 STORE_OPND(-1, rval
);
1209 END_CASE(JSOP_DELELEM
)
1211 BEGIN_CASE(JSOP_TYPEOFEXPR
)
1212 BEGIN_CASE(JSOP_TYPEOF
)
1213 rval
= FETCH_OPND(-1);
1214 type
= JS_TypeOfValue(cx
, rval
);
1215 atom
= rt
->atomState
.typeAtoms
[type
];
1216 STORE_OPND(-1, ATOM_KEY(atom
));
1217 END_CASE(JSOP_TYPEOF
)
1219 BEGIN_CASE(JSOP_VOID
)
1220 STORE_OPND(-1, JSVAL_VOID
);
1223 BEGIN_CASE(JSOP_INCELEM
)
1224 BEGIN_CASE(JSOP_DECELEM
)
1225 BEGIN_CASE(JSOP_ELEMINC
)
1226 BEGIN_CASE(JSOP_ELEMDEC
)
1228 * Delay fetching of id until we have the object to ensure the proper
1229 * evaluation order. See bug 372331.
1233 goto fetch_incop_obj
;
1235 BEGIN_CASE(JSOP_INCPROP
)
1236 BEGIN_CASE(JSOP_DECPROP
)
1237 BEGIN_CASE(JSOP_PROPINC
)
1238 BEGIN_CASE(JSOP_PROPDEC
)
1240 id
= ATOM_TO_JSID(atom
);
1244 FETCH_OBJECT(cx
, i
, lval
, obj
);
1246 FETCH_ELEMENT_ID(obj
, -1, id
);
1249 BEGIN_CASE(JSOP_INCNAME
)
1250 BEGIN_CASE(JSOP_DECNAME
)
1251 BEGIN_CASE(JSOP_NAMEINC
)
1252 BEGIN_CASE(JSOP_NAMEDEC
)
1254 JSPropCacheEntry
*entry
;
1256 obj
= fp
->scopeChain
;
1257 if (JS_LIKELY(OBJ_IS_NATIVE(obj
))) {
1258 PROPERTY_CACHE_TEST(cx
, regs
.pc
, obj
, obj2
, entry
, atom
);
1260 ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj
, obj2
, entry
);
1261 if (obj
== obj2
&& PCVAL_IS_SLOT(entry
->vword
)) {
1262 slot
= PCVAL_TO_SLOT(entry
->vword
);
1263 JS_ASSERT(slot
< OBJ_SCOPE(obj
)->freeslot
);
1264 rval
= LOCKED_OBJ_GET_SLOT(obj
, slot
);
1265 if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval
))) {
1267 rval
+= (js_CodeSpec
[op
].format
& JOF_INC
) ? 2 : -2;
1268 if (!(js_CodeSpec
[op
].format
& JOF_POST
))
1270 LOCKED_OBJ_SET_SLOT(obj
, slot
, rval
);
1271 JS_UNLOCK_OBJ(cx
, obj
);
1273 len
= JSOP_INCNAME_LENGTH
;
1277 JS_UNLOCK_OBJ(cx
, obj2
);
1283 id
= ATOM_TO_JSID(atom
);
1284 if (!js_FindPropertyHelper(cx
, id
, true, &obj
, &obj2
, &prop
))
1287 goto atom_not_defined
;
1288 obj2
->dropProperty(cx
, prop
);
1293 const JSCodeSpec
*cs
;
1297 * We need a root to store the value to leave on the stack until
1298 * we have done with obj->setProperty.
1300 PUSH_OPND(JSVAL_NULL
);
1301 if (!obj
->getProperty(cx
, id
, ®s
.sp
[-1]))
1304 cs
= &js_CodeSpec
[op
];
1305 JS_ASSERT(cs
->ndefs
== 1);
1306 JS_ASSERT((cs
->format
& JOF_TMPSLOT_MASK
) == JOF_TMPSLOT2
);
1308 if (JS_LIKELY(CAN_DO_FAST_INC_DEC(v
))) {
1311 incr
= (cs
->format
& JOF_INC
) ? 2 : -2;
1312 if (cs
->format
& JOF_POST
) {
1313 regs
.sp
[-1] = v
+ incr
;
1318 fp
->flags
|= JSFRAME_ASSIGNING
;
1319 ok
= obj
->setProperty(cx
, id
, ®s
.sp
[-1]);
1320 fp
->flags
&= ~JSFRAME_ASSIGNING
;
1325 * We must set regs.sp[-1] to v for both post and pre increments
1326 * as the setter overwrites regs.sp[-1].
1330 /* We need an extra root for the result. */
1331 PUSH_OPND(JSVAL_NULL
);
1332 if (!js_DoIncDec(cx
, cs
, ®s
.sp
[-2], ®s
.sp
[-1]))
1334 fp
->flags
|= JSFRAME_ASSIGNING
;
1335 ok
= obj
->setProperty(cx
, id
, ®s
.sp
[-1]);
1336 fp
->flags
&= ~JSFRAME_ASSIGNING
;
1342 if (cs
->nuses
== 0) {
1343 /* regs.sp[-1] already contains the result of name increment. */
1346 regs
.sp
-= cs
->nuses
;
1356 /* Position cases so the most frequent i++ does not need a jump. */
1357 BEGIN_CASE(JSOP_DECARG
)
1358 incr
= -2; incr2
= -2; goto do_arg_incop
;
1359 BEGIN_CASE(JSOP_ARGDEC
)
1360 incr
= -2; incr2
= 0; goto do_arg_incop
;
1361 BEGIN_CASE(JSOP_INCARG
)
1362 incr
= 2; incr2
= 2; goto do_arg_incop
;
1363 BEGIN_CASE(JSOP_ARGINC
)
1364 incr
= 2; incr2
= 0;
1367 slot
= GET_ARGNO(regs
.pc
);
1368 JS_ASSERT(slot
< fp
->fun
->nargs
);
1369 METER_SLOT_OP(op
, slot
);
1370 vp
= fp
->argv
+ slot
;
1371 goto do_int_fast_incop
;
1373 BEGIN_CASE(JSOP_DECLOCAL
)
1374 incr
= -2; incr2
= -2; goto do_local_incop
;
1375 BEGIN_CASE(JSOP_LOCALDEC
)
1376 incr
= -2; incr2
= 0; goto do_local_incop
;
1377 BEGIN_CASE(JSOP_INCLOCAL
)
1378 incr
= 2; incr2
= 2; goto do_local_incop
;
1379 BEGIN_CASE(JSOP_LOCALINC
)
1380 incr
= 2; incr2
= 0;
1383 * do_local_incop comes right before do_int_fast_incop as we want to
1384 * avoid an extra jump for variable cases as local++ is more frequent
1388 slot
= GET_SLOTNO(regs
.pc
);
1389 JS_ASSERT(slot
< fp
->script
->nslots
);
1390 vp
= fp
->slots
+ slot
;
1391 METER_SLOT_OP(op
, slot
);
1392 vp
= fp
->slots
+ slot
;
1396 if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval
))) {
1398 JS_ASSERT(JSOP_INCARG_LENGTH
== js_CodeSpec
[op
].length
);
1399 SKIP_POP_AFTER_SET(JSOP_INCARG_LENGTH
, 0);
1400 PUSH_OPND(rval
+ incr2
);
1403 if (!js_DoIncDec(cx
, &js_CodeSpec
[op
], ®s
.sp
[-1], vp
))
1406 len
= JSOP_INCARG_LENGTH
;
1407 JS_ASSERT(len
== js_CodeSpec
[op
].length
);
1411 /* NB: This macro doesn't use JS_BEGIN_MACRO/JS_END_MACRO around its body. */
1412 #define FAST_GLOBAL_INCREMENT_OP(SLOWOP,INCR,INCR2) \
1416 goto do_global_incop
1421 BEGIN_CASE(JSOP_DECGVAR
)
1422 FAST_GLOBAL_INCREMENT_OP(JSOP_DECNAME
, -2, -2);
1423 BEGIN_CASE(JSOP_GVARDEC
)
1424 FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEDEC
, -2, 0);
1425 BEGIN_CASE(JSOP_INCGVAR
)
1426 FAST_GLOBAL_INCREMENT_OP(JSOP_INCNAME
, 2, 2);
1427 BEGIN_CASE(JSOP_GVARINC
)
1428 FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEINC
, 2, 0);
1430 #undef FAST_GLOBAL_INCREMENT_OP
1433 JS_ASSERT((js_CodeSpec
[op
].format
& JOF_TMPSLOT_MASK
) ==
1435 slot
= GET_SLOTNO(regs
.pc
);
1436 JS_ASSERT(slot
< GlobalVarCount(fp
));
1437 METER_SLOT_OP(op
, slot
);
1438 lval
= fp
->slots
[slot
];
1439 if (JSVAL_IS_NULL(lval
)) {
1443 slot
= JSVAL_TO_INT(lval
);
1444 rval
= OBJ_GET_SLOT(cx
, fp
->varobj
, slot
);
1445 if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval
))) {
1446 PUSH_OPND(rval
+ incr2
);
1450 PUSH_OPND(JSVAL_NULL
); /* Extra root */
1451 if (!js_DoIncDec(cx
, &js_CodeSpec
[op
], ®s
.sp
[-2], ®s
.sp
[-1]))
1456 OBJ_SET_SLOT(cx
, fp
->varobj
, slot
, rval
);
1457 len
= JSOP_INCGVAR_LENGTH
; /* all gvar incops are same length */
1458 JS_ASSERT(len
== js_CodeSpec
[op
].length
);
1462 #define COMPUTE_THIS(cx, fp, obj) \
1464 if (!(obj = js_ComputeThisForFrame(cx, fp))) \
1468 BEGIN_CASE(JSOP_THIS
)
1469 COMPUTE_THIS(cx
, fp
, obj
);
1470 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
1473 BEGIN_CASE(JSOP_GETTHISPROP
)
1475 COMPUTE_THIS(cx
, fp
, obj
);
1477 goto do_getprop_with_obj
;
1481 BEGIN_CASE(JSOP_GETARGPROP
)
1483 slot
= GET_ARGNO(regs
.pc
);
1484 JS_ASSERT(slot
< fp
->fun
->nargs
);
1485 PUSH_OPND(fp
->argv
[slot
]);
1486 goto do_getprop_body
;
1488 BEGIN_CASE(JSOP_GETLOCALPROP
)
1490 slot
= GET_SLOTNO(regs
.pc
);
1491 JS_ASSERT(slot
< script
->nslots
);
1492 PUSH_OPND(fp
->slots
[slot
]);
1493 goto do_getprop_body
;
1495 BEGIN_CASE(JSOP_GETPROP
)
1496 BEGIN_CASE(JSOP_GETXPROP
)
1500 lval
= FETCH_OPND(-1);
1502 do_getprop_with_lval
:
1503 VALUE_TO_OBJECT(cx
, -1, lval
, obj
);
1505 do_getprop_with_obj
:
1508 JSPropCacheEntry
*entry
;
1511 * We do not impose the method read barrier if in an imacro,
1512 * assuming any property gets it does (e.g., for 'toString'
1513 * from JSOP_NEW) will not be leaked to the calling script.
1515 aobj
= js_GetProtoIfDenseArray(cx
, obj
);
1516 if (JS_LIKELY(aobj
->map
->ops
->getProperty
== js_GetProperty
)) {
1517 PROPERTY_CACHE_TEST(cx
, regs
.pc
, aobj
, obj2
, entry
, atom
);
1519 ASSERT_VALID_PROPERTY_CACHE_HIT(i
, aobj
, obj2
, entry
);
1520 if (PCVAL_IS_OBJECT(entry
->vword
)) {
1521 rval
= PCVAL_OBJECT_TO_JSVAL(entry
->vword
);
1522 } else if (PCVAL_IS_SLOT(entry
->vword
)) {
1523 slot
= PCVAL_TO_SLOT(entry
->vword
);
1524 JS_ASSERT(slot
< OBJ_SCOPE(obj2
)->freeslot
);
1525 rval
= LOCKED_OBJ_GET_SLOT(obj2
, slot
);
1527 JS_ASSERT(PCVAL_IS_SPROP(entry
->vword
));
1528 sprop
= PCVAL_TO_SPROP(entry
->vword
);
1529 NATIVE_GET(cx
, obj
, obj2
, sprop
,
1530 fp
->imacpc
? JSGET_NO_METHOD_BARRIER
: JSGET_METHOD_BARRIER
,
1533 JS_UNLOCK_OBJ(cx
, obj2
);
1539 atom
= rt
->atomState
.lengthAtom
;
1543 id
= ATOM_TO_JSID(atom
);
1545 ? !js_GetPropertyHelper(cx
, obj
, id
,
1547 ? JSGET_CACHE_RESULT
| JSGET_NO_METHOD_BARRIER
1548 : JSGET_CACHE_RESULT
| JSGET_METHOD_BARRIER
,
1550 : !obj
->getProperty(cx
, id
, &rval
)) {
1555 STORE_OPND(-1, rval
);
1556 JS_ASSERT(JSOP_GETPROP_LENGTH
+ i
== js_CodeSpec
[op
].length
);
1557 len
= JSOP_GETPROP_LENGTH
+ i
;
1560 BEGIN_CASE(JSOP_LENGTH
)
1561 lval
= FETCH_OPND(-1);
1562 if (JSVAL_IS_STRING(lval
)) {
1563 str
= JSVAL_TO_STRING(lval
);
1564 regs
.sp
[-1] = INT_TO_JSVAL(str
->length());
1565 } else if (!JSVAL_IS_PRIMITIVE(lval
) &&
1566 (obj
= JSVAL_TO_OBJECT(lval
), OBJ_IS_ARRAY(cx
, obj
))) {
1570 * We know that the array is created with only its 'length' private
1571 * data in a fixed slot at JSSLOT_ARRAY_LENGTH. See also
1572 * JSOP_ARRAYPUSH, far below.
1574 length
= obj
->fslots
[JSSLOT_ARRAY_LENGTH
];
1575 if (length
<= JSVAL_INT_MAX
) {
1576 regs
.sp
[-1] = INT_TO_JSVAL(length
);
1577 } else if (!js_NewDoubleInRootedValue(cx
, (jsdouble
) length
,
1583 goto do_getprop_with_lval
;
1585 END_CASE(JSOP_LENGTH
)
1587 BEGIN_CASE(JSOP_CALLPROP
)
1590 JSPropCacheEntry
*entry
;
1592 lval
= FETCH_OPND(-1);
1593 if (!JSVAL_IS_PRIMITIVE(lval
)) {
1594 obj
= JSVAL_TO_OBJECT(lval
);
1596 if (JSVAL_IS_STRING(lval
)) {
1598 } else if (JSVAL_IS_NUMBER(lval
)) {
1600 } else if (JSVAL_IS_BOOLEAN(lval
)) {
1601 i
= JSProto_Boolean
;
1603 JS_ASSERT(JSVAL_IS_NULL(lval
) || JSVAL_IS_VOID(lval
));
1604 js_ReportIsNullOrUndefined(cx
, -1, lval
, NULL
);
1608 if (!js_GetClassPrototype(cx
, NULL
, INT_TO_JSID(i
), &obj
))
1612 aobj
= js_GetProtoIfDenseArray(cx
, obj
);
1613 if (JS_LIKELY(aobj
->map
->ops
->getProperty
== js_GetProperty
)) {
1614 PROPERTY_CACHE_TEST(cx
, regs
.pc
, aobj
, obj2
, entry
, atom
);
1616 ASSERT_VALID_PROPERTY_CACHE_HIT(0, aobj
, obj2
, entry
);
1617 if (PCVAL_IS_OBJECT(entry
->vword
)) {
1618 rval
= PCVAL_OBJECT_TO_JSVAL(entry
->vword
);
1619 } else if (PCVAL_IS_SLOT(entry
->vword
)) {
1620 slot
= PCVAL_TO_SLOT(entry
->vword
);
1621 JS_ASSERT(slot
< OBJ_SCOPE(obj2
)->freeslot
);
1622 rval
= LOCKED_OBJ_GET_SLOT(obj2
, slot
);
1624 JS_ASSERT(PCVAL_IS_SPROP(entry
->vword
));
1625 sprop
= PCVAL_TO_SPROP(entry
->vword
);
1626 NATIVE_GET(cx
, obj
, obj2
, sprop
, JSGET_NO_METHOD_BARRIER
, &rval
);
1628 JS_UNLOCK_OBJ(cx
, obj2
);
1629 STORE_OPND(-1, rval
);
1639 * Cache miss: use the immediate atom that was loaded for us under
1640 * PROPERTY_CACHE_TEST.
1642 id
= ATOM_TO_JSID(atom
);
1644 if (!JSVAL_IS_PRIMITIVE(lval
)) {
1645 if (!js_GetMethod(cx
, obj
, id
,
1647 ? JSGET_CACHE_RESULT
| JSGET_NO_METHOD_BARRIER
1648 : JSGET_NO_METHOD_BARRIER
,
1652 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
1653 STORE_OPND(-2, rval
);
1655 JS_ASSERT(obj
->map
->ops
->getProperty
== js_GetProperty
);
1656 if (!js_GetPropertyHelper(cx
, obj
, id
,
1657 JSGET_CACHE_RESULT
| JSGET_NO_METHOD_BARRIER
,
1661 STORE_OPND(-1, lval
);
1662 STORE_OPND(-2, rval
);
1666 /* Wrap primitive lval in object clothing if necessary. */
1667 if (JSVAL_IS_PRIMITIVE(lval
)) {
1668 /* FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=412571 */
1669 if (!VALUE_IS_FUNCTION(cx
, rval
) ||
1670 (obj
= JSVAL_TO_OBJECT(rval
),
1671 fun
= GET_FUNCTION_PRIVATE(cx
, obj
),
1672 !PRIMITIVE_THIS_TEST(fun
, lval
))) {
1673 if (!js_PrimitiveToObject(cx
, ®s
.sp
[-1]))
1677 #if JS_HAS_NO_SUCH_METHOD
1678 if (JS_UNLIKELY(JSVAL_IS_VOID(rval
))) {
1680 regs
.sp
[-2] = ATOM_KEY(atom
);
1681 if (!js_OnUnknownMethod(cx
, regs
.sp
- 2))
1686 END_CASE(JSOP_CALLPROP
)
1688 BEGIN_CASE(JSOP_SETNAME
)
1689 BEGIN_CASE(JSOP_SETPROP
)
1690 BEGIN_CASE(JSOP_SETMETHOD
)
1691 rval
= FETCH_OPND(-1);
1692 JS_ASSERT_IF(op
== JSOP_SETMETHOD
, VALUE_IS_FUNCTION(cx
, rval
));
1693 lval
= FETCH_OPND(-2);
1694 JS_ASSERT_IF(op
== JSOP_SETNAME
, !JSVAL_IS_PRIMITIVE(lval
));
1695 VALUE_TO_OBJECT(cx
, -2, lval
, obj
);
1698 JSPropCacheEntry
*entry
;
1702 if (JS_LIKELY(obj
->map
->ops
->setProperty
== js_SetProperty
)) {
1703 JSPropertyCache
*cache
= &JS_PROPERTY_CACHE(cx
);
1704 uint32 kshape
= OBJ_SHAPE(obj
);
1707 * Open-code PROPERTY_CACHE_TEST, specializing for two important
1708 * set-property cases. First:
1710 * function f(a, b, c) {
1711 * var o = {p:a, q:b, r:c};
1715 * or similar real-world cases, which evolve a newborn native
1716 * object predicatably through some bounded number of property
1717 * additions. And second:
1721 * in a frequently executed method or loop body, where p will
1722 * (possibly after the first iteration) always exist in native
1725 entry
= &cache
->table
[PROPERTY_CACHE_HASH_PC(regs
.pc
, kshape
)];
1726 PCMETER(cache
->pctestentry
= entry
);
1727 PCMETER(cache
->tests
++);
1728 PCMETER(cache
->settests
++);
1729 if (entry
->kpc
== regs
.pc
&& entry
->kshape
== kshape
) {
1730 JS_ASSERT(PCVCAP_TAG(entry
->vcap
) <= 1);
1731 if (JS_LOCK_OBJ_IF_SHAPE(cx
, obj
, kshape
)) {
1732 JS_ASSERT(PCVAL_IS_SPROP(entry
->vword
));
1733 sprop
= PCVAL_TO_SPROP(entry
->vword
);
1734 JS_ASSERT(!(sprop
->attrs
& JSPROP_READONLY
));
1735 JS_ASSERT_IF(!(sprop
->attrs
& JSPROP_SHARED
),
1736 PCVCAP_TAG(entry
->vcap
) == 0);
1738 JSScope
*scope
= OBJ_SCOPE(obj
);
1739 JS_ASSERT(!scope
->sealed());
1742 * Fastest path: check whether the cached sprop is already
1743 * in scope and call NATIVE_SET and break to get out of the
1744 * do-while(0). But we can call NATIVE_SET only if obj owns
1745 * scope or sprop is shared.
1748 if (sprop
->attrs
& JSPROP_SHARED
) {
1749 if (PCVCAP_TAG(entry
->vcap
) == 0 ||
1750 ((obj2
= OBJ_GET_PROTO(cx
, obj
)) &&
1751 OBJ_IS_NATIVE(obj2
) &&
1752 OBJ_SHAPE(obj2
) == PCVCAP_SHAPE(entry
->vcap
))) {
1753 goto fast_set_propcache_hit
;
1756 /* The cache entry doesn't apply. vshape mismatch. */
1757 checkForAdd
= false;
1758 } else if (scope
->owned()) {
1759 if (sprop
== scope
->lastProp
|| scope
->has(sprop
)) {
1760 fast_set_propcache_hit
:
1761 PCMETER(cache
->pchits
++);
1762 PCMETER(cache
->setpchits
++);
1763 NATIVE_SET(cx
, obj
, sprop
, entry
, &rval
);
1764 JS_UNLOCK_SCOPE(cx
, scope
);
1768 !(sprop
->attrs
& JSPROP_SHARED
) &&
1769 sprop
->parent
== scope
->lastProp
&&
1770 !scope
->hadMiddleDelete();
1772 scope
= js_GetMutableScope(cx
, obj
);
1774 JS_UNLOCK_OBJ(cx
, obj
);
1777 checkForAdd
= !sprop
->parent
;
1781 SPROP_HAS_STUB_SETTER(sprop
) &&
1782 (slot
= sprop
->slot
) == scope
->freeslot
) {
1784 * Fast path: adding a plain old property that was once
1785 * at the frontier of the property tree, whose slot is
1786 * next to claim among the allocated slots in obj,
1787 * where scope->table has not been created yet.
1789 * We may want to remove hazard conditions above and
1790 * inline compensation code here, depending on
1791 * real-world workloads.
1793 JS_ASSERT(!(obj
->getClass()->flags
&
1794 JSCLASS_SHARE_ALL_PROPERTIES
));
1796 PCMETER(cache
->pchits
++);
1797 PCMETER(cache
->addpchits
++);
1800 * Beware classes such as Function that use the
1801 * reserveSlots hook to allocate a number of reserved
1802 * slots that may vary with obj.
1804 if (slot
< STOBJ_NSLOTS(obj
) &&
1805 !OBJ_GET_CLASS(cx
, obj
)->reserveSlots
) {
1808 if (!js_AllocSlot(cx
, obj
, &slot
)) {
1809 JS_UNLOCK_SCOPE(cx
, scope
);
1815 * If this obj's number of reserved slots differed, or
1816 * if something created a hash table for scope, we must
1817 * pay the price of JSScope::add.
1819 * If slot does not match the cached sprop's slot,
1820 * update the cache entry in the hope that obj and
1821 * other instances with the same number of reserved
1822 * slots are now "hot".
1824 if (slot
!= sprop
->slot
|| scope
->table
) {
1825 JSScopeProperty
*sprop2
=
1826 scope
->add(cx
, sprop
->id
,
1827 sprop
->getter
, sprop
->setter
,
1829 sprop
->flags
, sprop
->shortid
);
1831 js_FreeSlot(cx
, obj
, slot
);
1832 JS_UNLOCK_SCOPE(cx
, scope
);
1835 if (sprop2
!= sprop
) {
1836 PCMETER(cache
->slotchanges
++);
1837 JS_ASSERT(slot
!= sprop
->slot
&&
1838 slot
== sprop2
->slot
&&
1839 sprop2
->id
== sprop
->id
);
1840 entry
->vword
= SPROP_TO_PCVAL(sprop2
);
1844 scope
->extend(cx
, sprop
);
1848 * No method change check here because here we are
1849 * adding a new property, not updating an existing
1850 * slot's value that might contain a method of a
1853 TRACE_2(SetPropHit
, entry
, sprop
);
1854 LOCKED_OBJ_SET_SLOT(obj
, slot
, rval
);
1855 JS_UNLOCK_SCOPE(cx
, scope
);
1858 * Purge the property cache of the id we may have just
1859 * shadowed in obj's scope and proto chains. We do this
1860 * after unlocking obj's scope to avoid lock nesting.
1862 js_PurgeScopeChain(cx
, obj
, sprop
->id
);
1865 JS_UNLOCK_SCOPE(cx
, scope
);
1866 PCMETER(cache
->setpcmisses
++);
1870 atom
= js_FullTestPropertyCache(cx
, regs
.pc
, &obj
, &obj2
,
1873 PCMETER(cache
->misses
++);
1874 PCMETER(cache
->setmisses
++);
1876 ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj
, obj2
, entry
);
1879 JS_ASSERT(PCVAL_IS_SPROP(entry
->vword
));
1880 sprop
= PCVAL_TO_SPROP(entry
->vword
);
1881 JS_ASSERT(!(sprop
->attrs
& JSPROP_READONLY
));
1882 JS_ASSERT(!OBJ_SCOPE(obj2
)->sealed());
1883 NATIVE_SET(cx
, obj
, sprop
, entry
, &rval
);
1885 JS_UNLOCK_OBJ(cx
, obj2
);
1893 id
= ATOM_TO_JSID(atom
);
1895 uintN defineHow
= (op
== JSOP_SETMETHOD
)
1896 ? JSDNP_CACHE_RESULT
| JSDNP_SET_METHOD
1897 : JSDNP_CACHE_RESULT
;
1898 if (!js_SetPropertyHelper(cx
, obj
, id
, defineHow
, &rval
))
1901 if (!obj
->setProperty(cx
, id
, &rval
))
1903 ABORT_RECORDING(cx
, "Non-native set");
1906 END_SET_CASE_STORE_RVAL(JSOP_SETPROP
, 2);
1908 BEGIN_CASE(JSOP_GETELEM
)
1909 /* Open-coded ELEMENT_OP optimized for strings and dense arrays. */
1910 lval
= FETCH_OPND(-2);
1911 rval
= FETCH_OPND(-1);
1912 if (JSVAL_IS_STRING(lval
) && JSVAL_IS_INT(rval
)) {
1913 str
= JSVAL_TO_STRING(lval
);
1914 i
= JSVAL_TO_INT(rval
);
1915 if ((size_t)i
< str
->length()) {
1916 str
= JSString::getUnitString(cx
, str
, size_t(i
));
1919 rval
= STRING_TO_JSVAL(str
);
1924 VALUE_TO_OBJECT(cx
, -2, lval
, obj
);
1925 if (JSVAL_IS_INT(rval
)) {
1926 if (OBJ_IS_DENSE_ARRAY(cx
, obj
)) {
1929 length
= js_DenseArrayCapacity(obj
);
1930 i
= JSVAL_TO_INT(rval
);
1931 if ((jsuint
)i
< length
&&
1932 i
< obj
->fslots
[JSSLOT_ARRAY_LENGTH
]) {
1933 rval
= obj
->dslots
[i
];
1934 if (rval
!= JSVAL_HOLE
)
1937 /* Reload rval from the stack in the rare hole case. */
1938 rval
= FETCH_OPND(-1);
1941 id
= INT_JSVAL_TO_JSID(rval
);
1943 if (!js_InternNonIntElementId(cx
, obj
, rval
, &id
))
1947 if (!obj
->getProperty(cx
, id
, &rval
))
1951 STORE_OPND(-1, rval
);
1952 END_CASE(JSOP_GETELEM
)
1954 BEGIN_CASE(JSOP_CALLELEM
)
1955 ELEMENT_OP(-1, js_GetMethod(cx
, obj
, id
, JSGET_NO_METHOD_BARRIER
, &rval
));
1956 #if JS_HAS_NO_SUCH_METHOD
1957 if (JS_UNLIKELY(JSVAL_IS_VOID(rval
))) {
1958 regs
.sp
[-2] = regs
.sp
[-1];
1959 regs
.sp
[-1] = OBJECT_TO_JSVAL(obj
);
1960 if (!js_OnUnknownMethod(cx
, regs
.sp
- 2))
1965 STORE_OPND(-2, rval
);
1966 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
1968 END_CASE(JSOP_CALLELEM
)
1970 BEGIN_CASE(JSOP_SETELEM
)
1971 rval
= FETCH_OPND(-1);
1972 FETCH_OBJECT(cx
, -3, lval
, obj
);
1973 FETCH_ELEMENT_ID(obj
, -2, id
);
1975 if (OBJ_IS_DENSE_ARRAY(cx
, obj
) && JSID_IS_INT(id
)) {
1978 length
= js_DenseArrayCapacity(obj
);
1979 i
= JSID_TO_INT(id
);
1980 if ((jsuint
)i
< length
) {
1981 if (obj
->dslots
[i
] == JSVAL_HOLE
) {
1982 if (js_PrototypeHasIndexedProperties(cx
, obj
))
1984 if (i
>= obj
->fslots
[JSSLOT_ARRAY_LENGTH
])
1985 obj
->fslots
[JSSLOT_ARRAY_LENGTH
] = i
+ 1;
1986 obj
->fslots
[JSSLOT_ARRAY_COUNT
]++;
1988 obj
->dslots
[i
] = rval
;
1993 if (!obj
->setProperty(cx
, id
, &rval
))
1996 END_SET_CASE_STORE_RVAL(JSOP_SETELEM
, 3)
1998 BEGIN_CASE(JSOP_ENUMELEM
)
1999 /* Funky: the value to set is under the [obj, id] pair. */
2000 rval
= FETCH_OPND(-3);
2001 FETCH_OBJECT(cx
, -2, lval
, obj
);
2002 FETCH_ELEMENT_ID(obj
, -1, id
);
2003 if (!obj
->setProperty(cx
, id
, &rval
))
2006 END_CASE(JSOP_ENUMELEM
)
2008 BEGIN_CASE(JSOP_NEW
)
2009 /* Get immediate argc and find the constructor function. */
2010 argc
= GET_ARGC(regs
.pc
);
2011 vp
= regs
.sp
- (2 + argc
);
2012 JS_ASSERT(vp
>= StackBase(fp
));
2015 * Assign lval, obj, and fun exactly as the code at inline_call: expects to
2016 * find them, to avoid nesting a js_Interpret call via js_InvokeConstructor.
2019 if (VALUE_IS_FUNCTION(cx
, lval
)) {
2020 obj
= JSVAL_TO_OBJECT(lval
);
2021 fun
= GET_FUNCTION_PRIVATE(cx
, obj
);
2022 if (FUN_INTERPRETED(fun
)) {
2023 /* Root as we go using vp[1]. */
2024 if (!obj
->getProperty(cx
,
2025 ATOM_TO_JSID(cx
->runtime
->atomState
.classPrototypeAtom
),
2030 obj2
= js_NewObject(cx
, &js_ObjectClass
,
2031 JSVAL_IS_OBJECT(rval
) ? JSVAL_TO_OBJECT(rval
) : NULL
,
2032 OBJ_GET_PARENT(cx
, obj
));
2036 if (fun
->u
.i
.script
->isEmpty()) {
2037 *vp
= OBJECT_TO_JSVAL(obj2
);
2042 vp
[1] = OBJECT_TO_JSVAL(obj2
);
2043 flags
= JSFRAME_CONSTRUCTING
;
2048 if (!js_InvokeConstructor(cx
, argc
, JS_FALSE
, vp
))
2051 CHECK_INTERRUPT_HANDLER();
2052 TRACE_0(NativeCallComplete
);
2057 BEGIN_CASE(JSOP_CALL
)
2058 BEGIN_CASE(JSOP_EVAL
)
2059 BEGIN_CASE(JSOP_APPLY
)
2060 argc
= GET_ARGC(regs
.pc
);
2061 vp
= regs
.sp
- (argc
+ 2);
2064 if (VALUE_IS_FUNCTION(cx
, lval
)) {
2065 obj
= JSVAL_TO_OBJECT(lval
);
2066 fun
= GET_FUNCTION_PRIVATE(cx
, obj
);
2068 /* Clear frame flags since this is not a constructor call. */
2070 if (FUN_INTERPRETED(fun
))
2073 uintN nframeslots
, nvars
, missing
;
2078 JSInlineFrame
*newifp
;
2079 JSInterpreterHook hook
;
2081 script
= fun
->u
.i
.script
;
2082 if (script
->isEmpty()) {
2083 script
= fp
->script
;
2089 /* Restrict recursion of lightweight functions. */
2090 if (inlineCallCount
>= JS_MAX_INLINE_CALL_COUNT
) {
2091 js_ReportOverRecursed(cx
);
2092 script
= fp
->script
;
2096 /* Compute the total number of stack slots needed by fun. */
2097 nframeslots
= JS_HOWMANY(sizeof(JSInlineFrame
), sizeof(jsval
));
2098 atoms
= script
->atomMap
.vector
;
2099 nbytes
= (nframeslots
+ script
->nslots
) * sizeof(jsval
);
2101 /* Allocate missing expected args adjacent to actuals. */
2102 a
= cx
->stackPool
.current
;
2103 newmark
= (void *) a
->avail
;
2104 if (fun
->nargs
<= argc
) {
2107 newsp
= vp
+ 2 + fun
->nargs
;
2108 JS_ASSERT(newsp
> regs
.sp
);
2109 if ((jsuword
) newsp
<= a
->limit
) {
2110 if ((jsuword
) newsp
> a
->avail
)
2111 a
->avail
= (jsuword
) newsp
;
2112 jsval
*argsp
= newsp
;
2114 *--argsp
= JSVAL_VOID
;
2115 } while (argsp
!= regs
.sp
);
2118 missing
= fun
->nargs
- argc
;
2119 nbytes
+= (2 + fun
->nargs
) * sizeof(jsval
);
2123 /* Allocate the inline frame with its slots and operands. */
2124 if (a
->avail
+ nbytes
<= a
->limit
) {
2125 newsp
= (jsval
*) a
->avail
;
2127 JS_ASSERT(missing
== 0);
2129 JS_ARENA_ALLOCATE_CAST(newsp
, jsval
*, &cx
->stackPool
,
2132 js_ReportOutOfScriptQuota(cx
);
2133 goto bad_inline_call
;
2137 * Move args if the missing ones overflow arena a, then push
2138 * undefined for the missing args.
2141 memcpy(newsp
, vp
, (2 + argc
) * sizeof(jsval
));
2143 newsp
= vp
+ 2 + argc
;
2145 *newsp
++ = JSVAL_VOID
;
2146 } while (--missing
!= 0);
2150 /* Claim space for the stack frame and initialize it. */
2151 newifp
= (JSInlineFrame
*) newsp
;
2152 newsp
+= nframeslots
;
2153 newifp
->frame
.callobj
= NULL
;
2154 newifp
->frame
.argsobj
= NULL
;
2155 newifp
->frame
.varobj
= NULL
;
2156 newifp
->frame
.script
= script
;
2157 newifp
->frame
.fun
= fun
;
2158 newifp
->frame
.argc
= argc
;
2159 newifp
->frame
.argv
= vp
+ 2;
2160 newifp
->frame
.rval
= JSVAL_VOID
;
2161 newifp
->frame
.down
= fp
;
2162 newifp
->frame
.annotation
= NULL
;
2163 newifp
->frame
.scopeChain
= parent
= OBJ_GET_PARENT(cx
, obj
);
2164 newifp
->frame
.flags
= flags
;
2165 newifp
->frame
.dormantNext
= NULL
;
2166 newifp
->frame
.blockChain
= NULL
;
2167 if (script
->staticLevel
< JS_DISPLAY_SIZE
) {
2168 JSStackFrame
**disp
= &cx
->display
[script
->staticLevel
];
2169 newifp
->frame
.displaySave
= *disp
;
2170 *disp
= &newifp
->frame
;
2172 newifp
->mark
= newmark
;
2174 /* Compute the 'this' parameter now that argv is set. */
2175 JS_ASSERT(!JSFUN_BOUND_METHOD_TEST(fun
->flags
));
2176 newifp
->frame
.thisv
= vp
[1];
2178 newifp
->frame
.regs
= NULL
;
2179 newifp
->frame
.imacpc
= NULL
;
2180 newifp
->frame
.slots
= newsp
;
2182 /* Push void to initialize local variables. */
2183 nvars
= fun
->u
.i
.nvars
;
2185 *newsp
++ = JSVAL_VOID
;
2187 /* Scope with a call object parented by callee's parent. */
2188 if (JSFUN_HEAVYWEIGHT_TEST(fun
->flags
) &&
2189 !js_GetCallObject(cx
, &newifp
->frame
)) {
2190 goto bad_inline_call
;
2193 /* Switch version if currentVersion wasn't overridden. */
2194 newifp
->callerVersion
= (JSVersion
) cx
->version
;
2195 if (JS_LIKELY(cx
->version
== currentVersion
)) {
2196 currentVersion
= (JSVersion
) script
->version
;
2197 if (currentVersion
!= cx
->version
)
2198 js_SetVersion(cx
, currentVersion
);
2201 /* Push the frame and set interpreter registers. */
2202 newifp
->callerRegs
= regs
;
2203 fp
->regs
= &newifp
->callerRegs
;
2205 regs
.pc
= script
->code
;
2206 newifp
->frame
.regs
= ®s
;
2207 cx
->fp
= fp
= &newifp
->frame
;
2209 /* Call the debugger hook if present. */
2210 hook
= cx
->debugHooks
->callHook
;
2212 newifp
->hookData
= hook(cx
, &newifp
->frame
, JS_TRUE
, 0,
2213 cx
->debugHooks
->callHookData
);
2214 CHECK_INTERRUPT_HANDLER();
2216 newifp
->hookData
= NULL
;
2220 JS_RUNTIME_METER(rt
, inlineCalls
);
2222 #ifdef INCLUDE_MOZILLA_DTRACE
2223 /* DTrace function entry, inlines */
2224 if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
2225 jsdtrace_function_entry(cx
, fp
, fun
);
2226 if (JAVASCRIPT_FUNCTION_INFO_ENABLED())
2227 jsdtrace_function_info(cx
, fp
, fp
->down
, fun
);
2228 if (JAVASCRIPT_FUNCTION_ARGS_ENABLED())
2229 jsdtrace_function_args(cx
, fp
, fun
, fp
->argc
, fp
->argv
);
2233 if (TRACE_RECORDER(cx
)) {
2234 TRACE_1(EnterFrame
, inlineCallCount
);
2235 RESTORE_INTERP_VARS();
2236 } else if (fp
->script
== fp
->down
->script
&&
2237 *fp
->down
->regs
->pc
== JSOP_CALL
&&
2238 *fp
->regs
->pc
== JSOP_TRACE
) {
2239 MONITOR_BRANCH(Record_EnterFrame
);
2243 /* Load first op and dispatch it (safe since JSOP_STOP). */
2244 op
= (JSOp
) *regs
.pc
;
2248 JS_ASSERT(fp
->regs
== ®s
);
2249 script
= fp
->script
;
2250 atoms
= script
->atomMap
.vector
;
2251 js_FreeRawStack(cx
, newmark
);
2255 if (fun
->flags
& JSFUN_FAST_NATIVE
) {
2256 #ifdef INCLUDE_MOZILLA_DTRACE
2257 /* DTrace function entry, non-inlines */
2258 if (VALUE_IS_FUNCTION(cx
, lval
)) {
2259 if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
2260 jsdtrace_function_entry(cx
, NULL
, fun
);
2261 if (JAVASCRIPT_FUNCTION_INFO_ENABLED())
2262 jsdtrace_function_info(cx
, NULL
, fp
, fun
);
2263 if (JAVASCRIPT_FUNCTION_ARGS_ENABLED())
2264 jsdtrace_function_args(cx
, fp
, fun
, argc
, vp
+2);
2268 JS_ASSERT(fun
->u
.n
.extra
== 0);
2269 JS_ASSERT(JSVAL_IS_OBJECT(vp
[1]) ||
2270 PRIMITIVE_THIS_TEST(fun
, vp
[1]));
2271 ok
= ((JSFastNative
) fun
->u
.n
.native
)(cx
, argc
, vp
);
2272 #ifdef INCLUDE_MOZILLA_DTRACE
2273 if (VALUE_IS_FUNCTION(cx
, lval
)) {
2274 if (JAVASCRIPT_FUNCTION_RVAL_ENABLED())
2275 jsdtrace_function_rval(cx
, NULL
, fun
, vp
);
2276 if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
2277 jsdtrace_function_return(cx
, NULL
, fun
);
2283 * If we are executing the JSOP_NEXTITER imacro and a
2284 * Stopiteration exception is raised, transform it into a
2285 * JSVAL_HOLE return value. The tracer generates equivalent
2286 * code by calling CatchStopIteration_tn.
2288 if (fp
->imacpc
&& *fp
->imacpc
== JSOP_NEXTITER
&&
2289 cx
->throwing
&& js_ValueIsStopIteration(cx
->exception
)) {
2290 // pc may point to JSOP_DUP here due to bug 474854.
2291 JS_ASSERT(*regs
.pc
== JSOP_CALL
||
2292 *regs
.pc
== JSOP_DUP
);
2293 cx
->throwing
= JS_FALSE
;
2294 cx
->exception
= JSVAL_VOID
;
2295 regs
.sp
[-1] = JSVAL_HOLE
;
2300 TRACE_0(NativeCallComplete
);
2305 ok
= js_Invoke(cx
, argc
, vp
, 0);
2307 CHECK_INTERRUPT_HANDLER();
2310 JS_RUNTIME_METER(rt
, nonInlineCalls
);
2311 TRACE_0(NativeCallComplete
);
2316 BEGIN_CASE(JSOP_SETCALL
)
2317 argc
= GET_ARGC(regs
.pc
);
2318 vp
= regs
.sp
- argc
- 2;
2319 if (js_Invoke(cx
, argc
, vp
, 0))
2320 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_BAD_LEFTSIDE_OF_ASS
);
2322 END_CASE(JSOP_SETCALL
)
2324 BEGIN_CASE(JSOP_NAME
)
2325 BEGIN_CASE(JSOP_CALLNAME
)
2327 JSPropCacheEntry
*entry
;
2329 obj
= fp
->scopeChain
;
2330 if (JS_LIKELY(OBJ_IS_NATIVE(obj
))) {
2331 PROPERTY_CACHE_TEST(cx
, regs
.pc
, obj
, obj2
, entry
, atom
);
2333 ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj
, obj2
, entry
);
2334 if (PCVAL_IS_OBJECT(entry
->vword
)) {
2335 rval
= PCVAL_OBJECT_TO_JSVAL(entry
->vword
);
2336 JS_UNLOCK_OBJ(cx
, obj2
);
2340 if (PCVAL_IS_SLOT(entry
->vword
)) {
2341 slot
= PCVAL_TO_SLOT(entry
->vword
);
2342 JS_ASSERT(slot
< OBJ_SCOPE(obj2
)->freeslot
);
2343 rval
= LOCKED_OBJ_GET_SLOT(obj2
, slot
);
2344 JS_UNLOCK_OBJ(cx
, obj2
);
2348 JS_ASSERT(PCVAL_IS_SPROP(entry
->vword
));
2349 sprop
= PCVAL_TO_SPROP(entry
->vword
);
2356 id
= ATOM_TO_JSID(atom
);
2357 if (!js_FindPropertyHelper(cx
, id
, true, &obj
, &obj2
, &prop
))
2360 /* Kludge to allow (typeof foo == "undefined") tests. */
2361 endpc
= script
->code
+ script
->length
;
2362 op2
= js_GetOpcode(cx
, script
, regs
.pc
+ JSOP_NAME_LENGTH
);
2363 if (op2
== JSOP_TYPEOF
) {
2364 PUSH_OPND(JSVAL_VOID
);
2365 len
= JSOP_NAME_LENGTH
;
2368 goto atom_not_defined
;
2371 /* Take the slow path if prop was not found in a native object. */
2372 if (!OBJ_IS_NATIVE(obj
) || !OBJ_IS_NATIVE(obj2
)) {
2373 obj2
->dropProperty(cx
, prop
);
2374 if (!obj
->getProperty(cx
, id
, &rval
))
2377 sprop
= (JSScopeProperty
*)prop
;
2379 NATIVE_GET(cx
, obj
, obj2
, sprop
, JSGET_METHOD_BARRIER
, &rval
);
2380 obj2
->dropProperty(cx
, (JSProperty
*) sprop
);
2385 if (op
== JSOP_CALLNAME
)
2386 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
2390 BEGIN_CASE(JSOP_UINT16
)
2391 i
= (jsint
) GET_UINT16(regs
.pc
);
2392 rval
= INT_TO_JSVAL(i
);
2394 END_CASE(JSOP_UINT16
)
2396 BEGIN_CASE(JSOP_UINT24
)
2397 i
= (jsint
) GET_UINT24(regs
.pc
);
2398 rval
= INT_TO_JSVAL(i
);
2400 END_CASE(JSOP_UINT24
)
2402 BEGIN_CASE(JSOP_INT8
)
2403 i
= GET_INT8(regs
.pc
);
2404 rval
= INT_TO_JSVAL(i
);
2408 BEGIN_CASE(JSOP_INT32
)
2409 i
= GET_INT32(regs
.pc
);
2410 rval
= INT_TO_JSVAL(i
);
2412 END_CASE(JSOP_INT32
)
2414 BEGIN_CASE(JSOP_INDEXBASE
)
2416 * Here atoms can exceed script->atomMap.length as we use atoms as a
2417 * segment register for object literals as well.
2419 atoms
+= GET_INDEXBASE(regs
.pc
);
2420 END_CASE(JSOP_INDEXBASE
)
2422 BEGIN_CASE(JSOP_INDEXBASE1
)
2423 BEGIN_CASE(JSOP_INDEXBASE2
)
2424 BEGIN_CASE(JSOP_INDEXBASE3
)
2425 atoms
+= (op
- JSOP_INDEXBASE1
+ 1) << 16;
2426 END_CASE(JSOP_INDEXBASE3
)
2428 BEGIN_CASE(JSOP_RESETBASE0
)
2429 BEGIN_CASE(JSOP_RESETBASE
)
2430 atoms
= script
->atomMap
.vector
;
2431 END_CASE(JSOP_RESETBASE
)
2433 BEGIN_CASE(JSOP_DOUBLE
)
2434 JS_ASSERT(!fp
->imacpc
);
2435 JS_ASSERT(size_t(atoms
- script
->atomMap
.vector
) < script
->atomMap
.length
);
2438 BEGIN_CASE(JSOP_STRING
)
2440 PUSH_OPND(ATOM_KEY(atom
));
2441 END_CASE(JSOP_DOUBLE
)
2443 BEGIN_CASE(JSOP_OBJECT
)
2445 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
2446 END_CASE(JSOP_OBJECT
)
2448 BEGIN_CASE(JSOP_REGEXP
)
2453 * Push a regexp object for the atom mapped by the bytecode at pc, cloning
2454 * the literal's regexp object if necessary, to simulate in the
2455 * pre-compile/execute-later case what ECMA specifies for the
2456 * compile-and-go case: that scanning each regexp literal creates a single
2457 * corresponding RegExp object.
2459 * To support pre-compilation transparently, we must handle the case where
2460 * a regexp object literal is used in a different global at execution time
2461 * from the global with which it was scanned at compile time. We do this
2462 * by re-wrapping the JSRegExp private data struct with a cloned object
2463 * having the right prototype and parent, and having its own lastIndex
2464 * property value storage.
2466 * Unlike JSOP_DEFFUN and other prolog bytecodes that may clone literal
2467 * objects, we don't want to pay a script prolog execution price for all
2468 * regexp literals in a script (many may not be used by a particular
2469 * execution of that script, depending on control flow), so we initialize
2472 * XXX This code is specific to regular expression objects. If we need a
2473 * similar op for other kinds of object literals, we should push cloning
2474 * down under JSObjectOps and reuse code here.
2476 index
= GET_FULL_INDEX(0);
2477 JS_ASSERT(index
< script
->regexps()->length
);
2482 * We're in function code, not global or eval code (in eval code,
2483 * JSOP_REGEXP is never emitted). The cloned funobj contains
2484 * script->regexps()->length reserved slots for the cloned regexps; see
2485 * fun_reserveSlots, jsfun.c.
2487 funobj
= JSVAL_TO_OBJECT(fp
->argv
[-2]);
2488 slot
+= JSCLASS_RESERVED_SLOTS(&js_FunctionClass
);
2489 if (script
->upvarsOffset
!= 0)
2490 slot
+= script
->upvars()->length
;
2491 if (!JS_GetReservedSlot(cx
, funobj
, slot
, &rval
))
2493 if (JSVAL_IS_VOID(rval
))
2497 * We're in global code. The code generator reserved a slot for the
2498 * regexp among script->nfixed slots. All such slots are initialized to
2499 * null, not void, for faster testing in JSOP_*GVAR cases. To simplify
2500 * index calculations we count regexps in the reverse order down from
2501 * script->nslots - 1.
2503 JS_ASSERT(slot
< script
->nfixed
);
2504 slot
= script
->nfixed
- slot
- 1;
2505 rval
= fp
->slots
[slot
];
2507 funobj
= NULL
; /* suppress bogus gcc warnings */
2511 if (JSVAL_IS_NULL(rval
)) {
2512 /* Compute the current global object in obj2. */
2513 obj2
= fp
->scopeChain
;
2514 while ((parent
= OBJ_GET_PARENT(cx
, obj2
)) != NULL
)
2518 * If obj's parent is not obj2, we must clone obj so that it has the
2519 * right parent, and therefore, the right prototype.
2521 * Yes, this means we assume that the correct RegExp.prototype to which
2522 * regexp instances (including literals) delegate can be distinguished
2523 * solely by the instance's parent, which was set to the parent of the
2524 * RegExp constructor function object when the instance was created.
2527 * (/x/.__parent__ == RegExp.__parent__) implies
2528 * (/x/.__proto__ == RegExp.prototype)
2530 * (unless you assign a different object to RegExp.prototype at
2531 * runtime, in which case, ECMA doesn't specify operation, and you get
2532 * what you deserve).
2534 * This same coupling between instance parent and constructor parent
2535 * turns up everywhere (see jsobj.c's FindClassObject,
2536 * js_ConstructObject, and js_NewObject). It's fundamental to the
2537 * design of the language when you consider multiple global objects and
2538 * separate compilation and execution, even though it is not specified
2541 obj
= script
->getRegExp(index
);
2542 if (OBJ_GET_PARENT(cx
, obj
) != obj2
) {
2543 obj
= js_CloneRegExpObject(cx
, obj
, obj2
);
2547 rval
= OBJECT_TO_JSVAL(obj
);
2549 /* Store the regexp object value in its cloneIndex slot. */
2551 if (!JS_SetReservedSlot(cx
, funobj
, slot
, rval
))
2554 fp
->slots
[slot
] = rval
;
2560 END_CASE(JSOP_REGEXP
)
2562 BEGIN_CASE(JSOP_ZERO
)
2563 PUSH_OPND(JSVAL_ZERO
);
2566 BEGIN_CASE(JSOP_ONE
)
2567 PUSH_OPND(JSVAL_ONE
);
2570 BEGIN_CASE(JSOP_NULL
)
2571 PUSH_OPND(JSVAL_NULL
);
2574 BEGIN_CASE(JSOP_FALSE
)
2575 PUSH_OPND(JSVAL_FALSE
);
2576 END_CASE(JSOP_FALSE
)
2578 BEGIN_CASE(JSOP_TRUE
)
2579 PUSH_OPND(JSVAL_TRUE
);
2582 BEGIN_CASE(JSOP_TABLESWITCH
)
2584 len
= GET_JUMP_OFFSET(pc2
);
2587 * ECMAv2+ forbids conversion of discriminant, so we will skip to the
2588 * default case if the discriminant isn't already an int jsval. (This
2589 * opcode is emitted only for dense jsint-domain switches.)
2592 if (JSVAL_IS_INT(rval
)) {
2593 i
= JSVAL_TO_INT(rval
);
2594 } else if (JSVAL_IS_DOUBLE(rval
) && *JSVAL_TO_DOUBLE(rval
) == 0) {
2595 /* Treat -0 (double) as 0. */
2601 pc2
+= JUMP_OFFSET_LEN
;
2602 low
= GET_JUMP_OFFSET(pc2
);
2603 pc2
+= JUMP_OFFSET_LEN
;
2604 high
= GET_JUMP_OFFSET(pc2
);
2607 if ((jsuint
)i
< (jsuint
)(high
- low
+ 1)) {
2608 pc2
+= JUMP_OFFSET_LEN
+ JUMP_OFFSET_LEN
* i
;
2609 off
= (jsint
) GET_JUMP_OFFSET(pc2
);
2615 BEGIN_CASE(JSOP_TABLESWITCHX
)
2617 len
= GET_JUMPX_OFFSET(pc2
);
2620 * ECMAv2+ forbids conversion of discriminant, so we will skip to the
2621 * default case if the discriminant isn't already an int jsval. (This
2622 * opcode is emitted only for dense jsint-domain switches.)
2625 if (JSVAL_IS_INT(rval
)) {
2626 i
= JSVAL_TO_INT(rval
);
2627 } else if (JSVAL_IS_DOUBLE(rval
) && *JSVAL_TO_DOUBLE(rval
) == 0) {
2628 /* Treat -0 (double) as 0. */
2634 pc2
+= JUMPX_OFFSET_LEN
;
2635 low
= GET_JUMP_OFFSET(pc2
);
2636 pc2
+= JUMP_OFFSET_LEN
;
2637 high
= GET_JUMP_OFFSET(pc2
);
2640 if ((jsuint
)i
< (jsuint
)(high
- low
+ 1)) {
2641 pc2
+= JUMP_OFFSET_LEN
+ JUMPX_OFFSET_LEN
* i
;
2642 off
= (jsint
) GET_JUMPX_OFFSET(pc2
);
2648 BEGIN_CASE(JSOP_LOOKUPSWITCHX
)
2649 off
= JUMPX_OFFSET_LEN
;
2650 goto do_lookup_switch
;
2652 BEGIN_CASE(JSOP_LOOKUPSWITCH
)
2653 off
= JUMP_OFFSET_LEN
;
2657 * JSOP_LOOKUPSWITCH and JSOP_LOOKUPSWITCHX are never used if any atom
2658 * index in it would exceed 64K limit.
2660 JS_ASSERT(!fp
->imacpc
);
2661 JS_ASSERT(atoms
== script
->atomMap
.vector
);
2665 if (!JSVAL_IS_NUMBER(lval
) &&
2666 !JSVAL_IS_STRING(lval
) &&
2667 !JSVAL_IS_BOOLEAN(lval
)) {
2668 goto end_lookup_switch
;
2672 npairs
= (jsint
) GET_UINT16(pc2
);
2674 JS_ASSERT(npairs
); /* empty switch uses JSOP_TABLESWITCH */
2676 #define SEARCH_PAIRS(MATCH_CODE) \
2678 JS_ASSERT(GET_INDEX(pc2) < script->atomMap.length); \
2679 atom = atoms[GET_INDEX(pc2)]; \
2680 rval = ATOM_KEY(atom); \
2686 if (--npairs == 0) { \
2692 if (JSVAL_IS_STRING(lval
)) {
2693 str
= JSVAL_TO_STRING(lval
);
2695 match
= (JSVAL_IS_STRING(rval
) &&
2696 ((str2
= JSVAL_TO_STRING(rval
)) == str
||
2697 js_EqualStrings(str2
, str
)));
2699 } else if (JSVAL_IS_DOUBLE(lval
)) {
2700 d
= *JSVAL_TO_DOUBLE(lval
);
2702 match
= (JSVAL_IS_DOUBLE(rval
) &&
2703 *JSVAL_TO_DOUBLE(rval
) == d
);
2707 match
= (lval
== rval
);
2713 len
= (op
== JSOP_LOOKUPSWITCH
)
2714 ? GET_JUMP_OFFSET(pc2
)
2715 : GET_JUMPX_OFFSET(pc2
);
2718 BEGIN_CASE(JSOP_TRAP
)
2720 JSTrapStatus status
;
2722 status
= JS_HandleTrap(cx
, script
, regs
.pc
, &rval
);
2731 cx
->throwing
= JS_TRUE
;
2732 cx
->exception
= rval
;
2737 JS_ASSERT(status
== JSTRAP_CONTINUE
);
2738 CHECK_INTERRUPT_HANDLER();
2739 JS_ASSERT(JSVAL_IS_INT(rval
));
2740 op
= (JSOp
) JSVAL_TO_INT(rval
);
2741 JS_ASSERT((uintN
)op
< (uintN
)JSOP_LIMIT
);
2745 BEGIN_CASE(JSOP_ARGUMENTS
)
2746 if (!js_GetArgsValue(cx
, fp
, &rval
))
2749 END_CASE(JSOP_ARGUMENTS
)
2751 BEGIN_CASE(JSOP_ARGSUB
)
2752 id
= INT_TO_JSID(GET_ARGNO(regs
.pc
));
2753 if (!js_GetArgsProperty(cx
, fp
, id
, &rval
))
2756 END_CASE(JSOP_ARGSUB
)
2758 BEGIN_CASE(JSOP_ARGCNT
)
2759 id
= ATOM_TO_JSID(rt
->atomState
.lengthAtom
);
2760 if (!js_GetArgsProperty(cx
, fp
, id
, &rval
))
2763 END_CASE(JSOP_ARGCNT
)
2765 BEGIN_CASE(JSOP_GETARG
)
2766 BEGIN_CASE(JSOP_CALLARG
)
2767 slot
= GET_ARGNO(regs
.pc
);
2768 JS_ASSERT(slot
< fp
->fun
->nargs
);
2769 METER_SLOT_OP(op
, slot
);
2770 PUSH_OPND(fp
->argv
[slot
]);
2771 if (op
== JSOP_CALLARG
)
2772 PUSH_OPND(JSVAL_NULL
);
2773 END_CASE(JSOP_GETARG
)
2775 BEGIN_CASE(JSOP_SETARG
)
2776 slot
= GET_ARGNO(regs
.pc
);
2777 JS_ASSERT(slot
< fp
->fun
->nargs
);
2778 METER_SLOT_OP(op
, slot
);
2779 vp
= &fp
->argv
[slot
];
2780 *vp
= FETCH_OPND(-1);
2781 END_SET_CASE(JSOP_SETARG
)
2783 BEGIN_CASE(JSOP_GETLOCAL
)
2784 slot
= GET_SLOTNO(regs
.pc
);
2785 JS_ASSERT(slot
< script
->nslots
);
2786 PUSH_OPND(fp
->slots
[slot
]);
2787 END_CASE(JSOP_GETLOCAL
)
2789 BEGIN_CASE(JSOP_CALLLOCAL
)
2790 slot
= GET_SLOTNO(regs
.pc
);
2791 JS_ASSERT(slot
< script
->nslots
);
2792 PUSH_OPND(fp
->slots
[slot
]);
2793 PUSH_OPND(JSVAL_NULL
);
2794 END_CASE(JSOP_CALLLOCAL
)
2796 BEGIN_CASE(JSOP_SETLOCAL
)
2797 slot
= GET_SLOTNO(regs
.pc
);
2798 JS_ASSERT(slot
< script
->nslots
);
2799 vp
= &fp
->slots
[slot
];
2800 *vp
= FETCH_OPND(-1);
2801 END_SET_CASE(JSOP_SETLOCAL
)
2803 BEGIN_CASE(JSOP_GETUPVAR
)
2804 BEGIN_CASE(JSOP_CALLUPVAR
)
2806 JSUpvarArray
*uva
= script
->upvars();
2808 index
= GET_UINT16(regs
.pc
);
2809 JS_ASSERT(index
< uva
->length
);
2811 rval
= js_GetUpvar(cx
, script
->staticLevel
, uva
->vector
[index
]);
2814 if (op
== JSOP_CALLUPVAR
)
2815 PUSH_OPND(JSVAL_NULL
);
2817 END_CASE(JSOP_GETUPVAR
)
2819 BEGIN_CASE(JSOP_GETUPVAR_DBG
)
2820 BEGIN_CASE(JSOP_CALLUPVAR_DBG
)
2822 JS_ASSERT(FUN_KIND(fun
) == JSFUN_INTERPRETED
);
2823 JS_ASSERT(fun
->u
.i
.wrapper
);
2825 /* Scope for tempPool mark and local names allocation in it. */
2827 void *mark
= JS_ARENA_MARK(&cx
->tempPool
);
2828 jsuword
*names
= js_GetLocalNameArray(cx
, fun
, &cx
->tempPool
);
2832 index
= fun
->countArgsAndVars() + GET_UINT16(regs
.pc
);
2833 atom
= JS_LOCAL_NAME_TO_ATOM(names
[index
]);
2834 id
= ATOM_TO_JSID(atom
);
2836 ok
= js_FindProperty(cx
, id
, &obj
, &obj2
, &prop
);
2837 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
2843 goto atom_not_defined
;
2845 /* Minimize footprint with generic code instead of NATIVE_GET. */
2846 obj2
->dropProperty(cx
, prop
);
2848 PUSH_OPND(JSVAL_NULL
);
2849 if (!obj
->getProperty(cx
, id
, vp
))
2852 if (op
== JSOP_CALLUPVAR_DBG
)
2853 PUSH_OPND(JSVAL_NULL
);
2854 END_CASE(JSOP_GETUPVAR_DBG
)
2856 BEGIN_CASE(JSOP_GETDSLOT
)
2857 BEGIN_CASE(JSOP_CALLDSLOT
)
2858 JS_ASSERT(fp
->argv
);
2859 obj
= JSVAL_TO_OBJECT(fp
->argv
[-2]);
2861 JS_ASSERT(obj
->dslots
);
2863 index
= GET_UINT16(regs
.pc
);
2864 JS_ASSERT(JS_INITIAL_NSLOTS
+ index
< jsatomid(obj
->dslots
[-1]));
2865 JS_ASSERT_IF(OBJ_SCOPE(obj
)->object
== obj
,
2866 JS_INITIAL_NSLOTS
+ index
< OBJ_SCOPE(obj
)->freeslot
);
2868 PUSH_OPND(obj
->dslots
[index
]);
2869 if (op
== JSOP_CALLDSLOT
)
2870 PUSH_OPND(JSVAL_NULL
);
2871 END_CASE(JSOP_GETDSLOT
)
2873 BEGIN_CASE(JSOP_GETGVAR
)
2874 BEGIN_CASE(JSOP_CALLGVAR
)
2875 slot
= GET_SLOTNO(regs
.pc
);
2876 JS_ASSERT(slot
< GlobalVarCount(fp
));
2877 METER_SLOT_OP(op
, slot
);
2878 lval
= fp
->slots
[slot
];
2879 if (JSVAL_IS_NULL(lval
)) {
2880 op
= (op
== JSOP_GETGVAR
) ? JSOP_NAME
: JSOP_CALLNAME
;
2884 slot
= JSVAL_TO_INT(lval
);
2885 rval
= OBJ_GET_SLOT(cx
, obj
, slot
);
2887 if (op
== JSOP_CALLGVAR
)
2888 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
2889 END_CASE(JSOP_GETGVAR
)
2891 BEGIN_CASE(JSOP_SETGVAR
)
2892 slot
= GET_SLOTNO(regs
.pc
);
2893 JS_ASSERT(slot
< GlobalVarCount(fp
));
2894 METER_SLOT_OP(op
, slot
);
2895 rval
= FETCH_OPND(-1);
2897 lval
= fp
->slots
[slot
];
2898 if (JSVAL_IS_NULL(lval
)) {
2900 * Inline-clone and deoptimize JSOP_SETNAME code here because
2901 * JSOP_SETGVAR has arity 1: [rval], not arity 2: [obj, rval]
2902 * as JSOP_SETNAME does, where [obj] is due to JSOP_BINDNAME.
2905 if (TRACE_RECORDER(cx
))
2906 js_AbortRecording(cx
, "SETGVAR with NULL slot");
2909 id
= ATOM_TO_JSID(atom
);
2910 if (!obj
->setProperty(cx
, id
, &rval
))
2913 slot
= JSVAL_TO_INT(lval
);
2914 JS_LOCK_OBJ(cx
, obj
);
2915 JSScope
*scope
= OBJ_SCOPE(obj
);
2916 if (!scope
->methodWriteBarrier(cx
, slot
, rval
)) {
2917 JS_UNLOCK_SCOPE(cx
, scope
);
2920 LOCKED_OBJ_SET_SLOT(obj
, slot
, rval
);
2921 JS_UNLOCK_SCOPE(cx
, scope
);
2923 END_SET_CASE(JSOP_SETGVAR
)
2925 BEGIN_CASE(JSOP_DEFCONST
)
2926 BEGIN_CASE(JSOP_DEFVAR
)
2927 index
= GET_INDEX(regs
.pc
);
2928 atom
= atoms
[index
];
2931 * index is relative to atoms at this point but for global var
2932 * code below we need the absolute value.
2934 index
+= atoms
- script
->atomMap
.vector
;
2936 JS_ASSERT(obj
->map
->ops
->defineProperty
== js_DefineProperty
);
2937 attrs
= JSPROP_ENUMERATE
;
2938 if (!(fp
->flags
& JSFRAME_EVAL
))
2939 attrs
|= JSPROP_PERMANENT
;
2940 if (op
== JSOP_DEFCONST
)
2941 attrs
|= JSPROP_READONLY
;
2943 /* Lookup id in order to check for redeclaration problems. */
2944 id
= ATOM_TO_JSID(atom
);
2946 if (!js_CheckRedeclaration(cx
, obj
, id
, attrs
, &obj2
, &prop
))
2949 /* Bind a variable only if it's not yet defined. */
2951 if (!js_DefineNativeProperty(cx
, obj
, id
, JSVAL_VOID
, JS_PropertyStub
, JS_PropertyStub
,
2952 attrs
, 0, 0, &prop
)) {
2960 * Try to optimize a property we either just created, or found
2961 * directly in the global object, that is permanent, has a slot,
2962 * and has stub getter and setter, into a "fast global" accessed
2963 * by the JSOP_*GVAR opcodes.
2966 index
< GlobalVarCount(fp
) &&
2968 OBJ_IS_NATIVE(obj
)) {
2969 sprop
= (JSScopeProperty
*) prop
;
2970 if ((sprop
->attrs
& JSPROP_PERMANENT
) &&
2971 SPROP_HAS_VALID_SLOT(sprop
, OBJ_SCOPE(obj
)) &&
2972 SPROP_HAS_STUB_GETTER_OR_IS_METHOD(sprop
) &&
2973 SPROP_HAS_STUB_SETTER(sprop
)) {
2975 * Fast globals use frame variables to map the global
2976 * name's atom index to the permanent fp->varobj slot
2977 * number, tagged as a jsval. The atom index for the
2978 * global's name literal is identical to its variable
2981 fp
->slots
[index
] = INT_TO_JSVAL(sprop
->slot
);
2985 obj2
->dropProperty(cx
, prop
);
2986 END_CASE(JSOP_DEFVAR
)
2988 BEGIN_CASE(JSOP_DEFFUN
)
2990 JSPropertyOp getter
, setter
;
2997 * A top-level function defined in Global or Eval code (see ECMA-262
2998 * Ed. 3), or else a SpiderMonkey extension: a named function statement in
2999 * a compound statement (not at the top statement level of global code, or
3000 * at the top level of a function body).
3003 obj
= FUN_OBJECT(fun
);
3005 if (FUN_NULL_CLOSURE(fun
)) {
3007 * Even a null closure needs a parent for principals finding.
3008 * FIXME: bug 476950, although debugger users may also demand some kind
3009 * of scope link for debugger-assisted eval-in-frame.
3011 obj2
= fp
->scopeChain
;
3013 JS_ASSERT(!FUN_FLAT_CLOSURE(fun
));
3016 * Inline js_GetScopeChain a bit to optimize for the case of a
3017 * top-level function.
3019 if (!fp
->blockChain
) {
3020 obj2
= fp
->scopeChain
;
3022 obj2
= js_GetScopeChain(cx
, fp
);
3029 * If static link is not current scope, clone fun's object to link to the
3030 * current scope via parent. We do this to enable sharing of compiled
3031 * functions among multiple equivalent scopes, amortizing the cost of
3032 * compilation over a number of executions. Examples include XUL scripts
3033 * and event handlers shared among Firefox or other Mozilla app chrome
3034 * windows, and user-defined JS functions precompiled and then shared among
3035 * requests in server-side JS.
3037 if (OBJ_GET_PARENT(cx
, obj
) != obj2
) {
3038 obj
= js_CloneFunctionObject(cx
, fun
, obj2
);
3044 * Protect obj from any GC hiding below JSObject::setProperty or
3045 * JSObject::defineProperty. All paths from here must flow through the
3046 * fp->scopeChain code below the parent->defineProperty call.
3048 MUST_FLOW_THROUGH("restore_scope");
3049 fp
->scopeChain
= obj
;
3051 rval
= OBJECT_TO_JSVAL(obj
);
3054 * ECMA requires functions defined when entering Eval code to be
3057 attrs
= (fp
->flags
& JSFRAME_EVAL
)
3059 : JSPROP_ENUMERATE
| JSPROP_PERMANENT
;
3062 * Load function flags that are also property attributes. Getters and
3063 * setters do not need a slot, their value is stored elsewhere in the
3064 * property itself, not in obj slots.
3066 getter
= setter
= JS_PropertyStub
;
3067 flags
= JSFUN_GSFLAG2ATTR(fun
->flags
);
3069 /* Function cannot be both getter a setter. */
3070 JS_ASSERT(flags
== JSPROP_GETTER
|| flags
== JSPROP_SETTER
);
3071 attrs
|= flags
| JSPROP_SHARED
;
3073 if (flags
== JSPROP_GETTER
)
3074 getter
= js_CastAsPropertyOp(obj
);
3076 setter
= js_CastAsPropertyOp(obj
);
3080 * We define the function as a property of the variable object and not the
3081 * current scope chain even for the case of function expression statements
3082 * and functions defined by eval inside let or with blocks.
3084 parent
= fp
->varobj
;
3088 * Check for a const property of the same name -- or any kind of property
3089 * if executing with the strict option. We check here at runtime as well
3090 * as at compile-time, to handle eval as well as multiple HTML script tags.
3092 id
= ATOM_TO_JSID(fun
->atom
);
3094 ok
= js_CheckRedeclaration(cx
, parent
, id
, attrs
, &pobj
, &prop
);
3099 * We deviate from 10.1.2 in ECMA 262 v3 and under eval use for function
3100 * declarations JSObject::setProperty, not JSObject::defineProperty, to
3101 * preserve the JSOP_PERMANENT attribute of existing properties and make
3102 * sure that such properties cannot be deleted.
3104 * We also use JSObject::setProperty for the existing properties of Call
3105 * objects with matching attributes to preserve the native getters and
3106 * setters that store the value of the property in the interpreter frame,
3109 doSet
= (attrs
== JSPROP_ENUMERATE
);
3110 JS_ASSERT_IF(doSet
, fp
->flags
& JSFRAME_EVAL
);
3112 if (parent
== pobj
&&
3113 OBJ_GET_CLASS(cx
, parent
) == &js_CallClass
&&
3114 (old
= ((JSScopeProperty
*) prop
)->attrs
,
3115 !(old
& (JSPROP_GETTER
|JSPROP_SETTER
)) &&
3116 (old
& (JSPROP_ENUMERATE
|JSPROP_PERMANENT
)) == attrs
)) {
3118 * js_CheckRedeclaration must reject attempts to add a getter or
3119 * setter to an existing property without a getter or setter.
3121 JS_ASSERT(!(attrs
& ~(JSPROP_ENUMERATE
|JSPROP_PERMANENT
)));
3122 JS_ASSERT(!(old
& JSPROP_READONLY
));
3125 pobj
->dropProperty(cx
, prop
);
3128 ? parent
->setProperty(cx
, id
, &rval
)
3129 : parent
->defineProperty(cx
, id
, rval
, getter
, setter
, attrs
);
3132 /* Restore fp->scopeChain now that obj is defined in fp->varobj. */
3133 fp
->scopeChain
= obj2
;
3137 END_CASE(JSOP_DEFFUN
)
3139 BEGIN_CASE(JSOP_DEFFUN_FC
)
3140 BEGIN_CASE(JSOP_DEFFUN_DBGFC
)
3143 obj
= (op
== JSOP_DEFFUN_FC
)
3144 ? js_NewFlatClosure(cx
, fun
)
3145 : js_NewDebuggableFlatClosure(cx
, fun
);
3148 rval
= OBJECT_TO_JSVAL(obj
);
3150 attrs
= (fp
->flags
& JSFRAME_EVAL
)
3152 : JSPROP_ENUMERATE
| JSPROP_PERMANENT
;
3154 flags
= JSFUN_GSFLAG2ATTR(fun
->flags
);
3156 attrs
|= flags
| JSPROP_SHARED
;
3160 parent
= fp
->varobj
;
3163 id
= ATOM_TO_JSID(fun
->atom
);
3164 ok
= js_CheckRedeclaration(cx
, parent
, id
, attrs
, NULL
, NULL
);
3166 if (attrs
== JSPROP_ENUMERATE
) {
3167 JS_ASSERT(fp
->flags
& JSFRAME_EVAL
);
3168 ok
= parent
->setProperty(cx
, id
, &rval
);
3170 JS_ASSERT(attrs
& JSPROP_PERMANENT
);
3172 ok
= parent
->defineProperty(cx
, id
, rval
,
3173 (flags
& JSPROP_GETTER
)
3174 ? js_CastAsPropertyOp(obj
)
3176 (flags
& JSPROP_SETTER
)
3177 ? js_CastAsPropertyOp(obj
)
3185 END_CASE(JSOP_DEFFUN_FC
)
3187 BEGIN_CASE(JSOP_DEFLOCALFUN
)
3189 * Define a local function (i.e., one nested at the top level of another
3190 * function), parented by the current scope chain, stored in a local
3191 * variable slot that the compiler allocated. This is an optimization over
3192 * JSOP_DEFFUN that avoids requiring a call object for the outer function's
3195 LOAD_FUNCTION(SLOTNO_LEN
);
3196 JS_ASSERT(FUN_INTERPRETED(fun
));
3197 JS_ASSERT(!FUN_FLAT_CLOSURE(fun
));
3198 obj
= FUN_OBJECT(fun
);
3200 if (FUN_NULL_CLOSURE(fun
)) {
3201 obj
= js_CloneFunctionObject(cx
, fun
, fp
->scopeChain
);
3205 parent
= js_GetScopeChain(cx
, fp
);
3209 if (OBJ_GET_PARENT(cx
, obj
) != parent
) {
3211 if (TRACE_RECORDER(cx
))
3212 js_AbortRecording(cx
, "DEFLOCALFUN for closure");
3214 obj
= js_CloneFunctionObject(cx
, fun
, parent
);
3220 slot
= GET_SLOTNO(regs
.pc
);
3221 TRACE_2(DefLocalFunSetSlot
, slot
, obj
);
3223 fp
->slots
[slot
] = OBJECT_TO_JSVAL(obj
);
3224 END_CASE(JSOP_DEFLOCALFUN
)
3226 BEGIN_CASE(JSOP_DEFLOCALFUN_FC
)
3227 LOAD_FUNCTION(SLOTNO_LEN
);
3229 obj
= js_NewFlatClosure(cx
, fun
);
3233 slot
= GET_SLOTNO(regs
.pc
);
3234 TRACE_2(DefLocalFunSetSlot
, slot
, obj
);
3236 fp
->slots
[slot
] = OBJECT_TO_JSVAL(obj
);
3237 END_CASE(JSOP_DEFLOCALFUN_FC
)
3239 BEGIN_CASE(JSOP_DEFLOCALFUN_DBGFC
)
3240 LOAD_FUNCTION(SLOTNO_LEN
);
3242 obj
= js_NewDebuggableFlatClosure(cx
, fun
);
3246 slot
= GET_SLOTNO(regs
.pc
);
3247 fp
->slots
[slot
] = OBJECT_TO_JSVAL(obj
);
3248 END_CASE(JSOP_DEFLOCALFUN_DBGFC
)
3250 BEGIN_CASE(JSOP_LAMBDA
)
3251 /* Load the specified function object literal. */
3253 obj
= FUN_OBJECT(fun
);
3255 /* do-while(0) so we can break instead of using a goto. */
3257 if (FUN_NULL_CLOSURE(fun
)) {
3258 parent
= fp
->scopeChain
;
3260 if (OBJ_GET_PARENT(cx
, obj
) == parent
) {
3261 op
= JSOp(regs
.pc
[JSOP_LAMBDA_LENGTH
]);
3264 * Optimize ({method: function () { ... }, ...}) and
3265 * this.method = function () { ... }; bytecode sequences.
3267 if (op
== JSOP_SETMETHOD
) {
3269 op2
= JSOp(regs
.pc
[JSOP_LAMBDA_LENGTH
+ JSOP_SETMETHOD_LENGTH
]);
3270 JS_ASSERT(op2
== JSOP_POP
|| op2
== JSOP_POPV
);
3273 lval
= FETCH_OPND(-1);
3274 if (JSVAL_IS_OBJECT(lval
) &&
3275 (obj2
= JSVAL_TO_OBJECT(lval
)) &&
3276 OBJ_GET_CLASS(cx
, obj2
) == &js_ObjectClass
) {
3279 } else if (op
== JSOP_INITMETHOD
) {
3280 lval
= FETCH_OPND(-1);
3281 JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval
));
3282 obj2
= JSVAL_TO_OBJECT(lval
);
3283 JS_ASSERT(OBJ_GET_CLASS(cx
, obj2
) == &js_ObjectClass
);
3284 JS_ASSERT(OBJ_SCOPE(obj2
)->object
== obj2
);
3289 parent
= js_GetScopeChain(cx
, fp
);
3294 obj
= js_CloneFunctionObject(cx
, fun
, parent
);
3299 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
3300 END_CASE(JSOP_LAMBDA
)
3302 BEGIN_CASE(JSOP_LAMBDA_FC
)
3305 obj
= js_NewFlatClosure(cx
, fun
);
3309 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
3310 END_CASE(JSOP_LAMBDA_FC
)
3312 BEGIN_CASE(JSOP_LAMBDA_DBGFC
)
3315 obj
= js_NewDebuggableFlatClosure(cx
, fun
);
3319 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
3320 END_CASE(JSOP_LAMBDA_DBGFC
)
3322 BEGIN_CASE(JSOP_CALLEE
)
3323 PUSH_OPND(fp
->argv
[-2]);
3324 END_CASE(JSOP_CALLEE
)
3326 #if JS_HAS_GETTER_SETTER
3327 BEGIN_CASE(JSOP_GETTER
)
3328 BEGIN_CASE(JSOP_SETTER
)
3330 op2
= (JSOp
) *++regs
.pc
;
3332 case JSOP_INDEXBASE
:
3333 atoms
+= GET_INDEXBASE(regs
.pc
);
3334 regs
.pc
+= JSOP_INDEXBASE_LENGTH
- 1;
3335 goto do_getter_setter
;
3336 case JSOP_INDEXBASE1
:
3337 case JSOP_INDEXBASE2
:
3338 case JSOP_INDEXBASE3
:
3339 atoms
+= (op2
- JSOP_INDEXBASE1
+ 1) << 16;
3340 goto do_getter_setter
;
3345 id
= ATOM_TO_JSID(atom
);
3346 rval
= FETCH_OPND(-1);
3351 rval
= FETCH_OPND(-1);
3355 FETCH_OBJECT(cx
, i
- 1, lval
, obj
);
3359 JS_ASSERT(regs
.sp
- StackBase(fp
) >= 2);
3360 rval
= FETCH_OPND(-1);
3363 id
= ATOM_TO_JSID(atom
);
3367 JS_ASSERT(op2
== JSOP_INITELEM
);
3369 JS_ASSERT(regs
.sp
- StackBase(fp
) >= 3);
3370 rval
= FETCH_OPND(-1);
3374 lval
= FETCH_OPND(i
-1);
3375 JS_ASSERT(JSVAL_IS_OBJECT(lval
));
3376 obj
= JSVAL_TO_OBJECT(lval
);
3380 /* Ensure that id has a type suitable for use with obj. */
3382 FETCH_ELEMENT_ID(obj
, i
, id
);
3384 if (JS_TypeOfValue(cx
, rval
) != JSTYPE_FUNCTION
) {
3385 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
3386 JSMSG_BAD_GETTER_OR_SETTER
,
3394 * Getters and setters are just like watchpoints from an access control
3397 if (!obj
->checkAccess(cx
, id
, JSACC_WATCH
, &rtmp
, &attrs
))
3400 if (op
== JSOP_GETTER
) {
3401 getter
= js_CastAsPropertyOp(JSVAL_TO_OBJECT(rval
));
3402 setter
= JS_PropertyStub
;
3403 attrs
= JSPROP_GETTER
;
3405 getter
= JS_PropertyStub
;
3406 setter
= js_CastAsPropertyOp(JSVAL_TO_OBJECT(rval
));
3407 attrs
= JSPROP_SETTER
;
3409 attrs
|= JSPROP_ENUMERATE
| JSPROP_SHARED
;
3411 /* Check for a readonly or permanent property of the same name. */
3412 if (!js_CheckRedeclaration(cx
, obj
, id
, attrs
, NULL
, NULL
))
3415 if (!obj
->defineProperty(cx
, id
, JSVAL_VOID
, getter
, setter
, attrs
))
3419 if (js_CodeSpec
[op2
].ndefs
> js_CodeSpec
[op2
].nuses
) {
3420 JS_ASSERT(js_CodeSpec
[op2
].ndefs
== js_CodeSpec
[op2
].nuses
+ 1);
3421 STORE_OPND(-1, rval
);
3423 len
= js_CodeSpec
[op2
].length
;
3425 #endif /* JS_HAS_GETTER_SETTER */
3427 BEGIN_CASE(JSOP_HOLE
)
3428 PUSH_OPND(JSVAL_HOLE
);
3431 BEGIN_CASE(JSOP_NEWARRAY
)
3432 len
= GET_UINT16(regs
.pc
);
3433 cx
->fp
->assertValidStackDepth(len
);
3434 obj
= js_NewArrayObject(cx
, len
, regs
.sp
- len
, JS_TRUE
);
3438 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
3439 END_CASE(JSOP_NEWARRAY
)
3441 BEGIN_CASE(JSOP_NEWINIT
)
3442 i
= GET_INT8(regs
.pc
);
3443 JS_ASSERT(i
== JSProto_Array
|| i
== JSProto_Object
);
3444 if (i
== JSProto_Array
) {
3445 obj
= js_NewArrayObject(cx
, 0, NULL
);
3449 obj
= js_NewObject(cx
, &js_ObjectClass
, NULL
, NULL
);
3453 if (regs
.pc
[JSOP_NEWINIT_LENGTH
] != JSOP_ENDINIT
) {
3454 JS_LOCK_OBJ(cx
, obj
);
3455 JSScope
*scope
= js_GetMutableScope(cx
, obj
);
3457 JS_UNLOCK_OBJ(cx
, obj
);
3460 JS_UNLOCK_SCOPE(cx
, scope
);
3464 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
3465 CHECK_INTERRUPT_HANDLER();
3466 END_CASE(JSOP_NEWINIT
)
3468 BEGIN_CASE(JSOP_ENDINIT
)
3469 /* Re-set the newborn root to the top of this object tree. */
3470 JS_ASSERT(regs
.sp
- StackBase(fp
) >= 1);
3471 lval
= FETCH_OPND(-1);
3472 JS_ASSERT(JSVAL_IS_OBJECT(lval
));
3473 cx
->weakRoots
.finalizableNewborns
[FINALIZE_OBJECT
] = JSVAL_TO_OBJECT(lval
);
3474 END_CASE(JSOP_ENDINIT
)
3476 BEGIN_CASE(JSOP_INITPROP
)
3477 BEGIN_CASE(JSOP_INITMETHOD
)
3478 /* Load the property's initial value into rval. */
3479 JS_ASSERT(regs
.sp
- StackBase(fp
) >= 2);
3480 rval
= FETCH_OPND(-1);
3482 /* Load the object being initialized into lval/obj. */
3483 lval
= FETCH_OPND(-2);
3484 obj
= JSVAL_TO_OBJECT(lval
);
3485 JS_ASSERT(OBJ_IS_NATIVE(obj
));
3486 JS_ASSERT(!OBJ_GET_CLASS(cx
, obj
)->reserveSlots
);
3487 JS_ASSERT(!(obj
->getClass()->flags
& JSCLASS_SHARE_ALL_PROPERTIES
));
3492 JSPropertyCache
*cache
;
3493 JSPropCacheEntry
*entry
;
3495 JS_LOCK_OBJ(cx
, obj
);
3496 scope
= OBJ_SCOPE(obj
);
3497 // FIXME: bug 513291 -- uncomment this assertion and remove the
3498 // (!scope->owned()) => js_GetMutableScope code further
3500 // JS_ASSERT(scope->object == obj);
3501 JS_ASSERT(!scope
->sealed());
3502 kshape
= scope
->shape
;
3503 cache
= &JS_PROPERTY_CACHE(cx
);
3504 entry
= &cache
->table
[PROPERTY_CACHE_HASH_PC(regs
.pc
, kshape
)];
3505 PCMETER(cache
->pctestentry
= entry
);
3506 PCMETER(cache
->tests
++);
3507 PCMETER(cache
->initests
++);
3509 if (entry
->kpc
== regs
.pc
&&
3510 entry
->kshape
== kshape
&&
3511 PCVCAP_SHAPE(entry
->vcap
) == rt
->protoHazardShape
) {
3512 JS_ASSERT(PCVCAP_TAG(entry
->vcap
) == 0);
3514 PCMETER(cache
->pchits
++);
3515 PCMETER(cache
->inipchits
++);
3517 JS_ASSERT(PCVAL_IS_SPROP(entry
->vword
));
3518 sprop
= PCVAL_TO_SPROP(entry
->vword
);
3519 JS_ASSERT(!(sprop
->attrs
& JSPROP_READONLY
));
3522 * If this property has a non-stub setter, it must be __proto__,
3523 * __parent__, or another "shared prototype" built-in. Force a miss
3524 * to save code size here and let the standard code path take care
3527 if (!SPROP_HAS_STUB_SETTER(sprop
))
3528 goto do_initprop_miss
;
3530 if (!scope
->owned()) {
3531 scope
= js_GetMutableScope(cx
, obj
);
3533 JS_UNLOCK_OBJ(cx
, obj
);
3539 * Detect a repeated property name and force a miss to share the
3540 * strict warning code and cope with complexity managed by
3543 if (sprop
->parent
!= scope
->lastProp
)
3544 goto do_initprop_miss
;
3547 * Otherwise this entry must be for a direct property of obj, not a
3548 * proto-property, and there cannot have been any deletions of
3551 JS_ASSERT(!scope
->hadMiddleDelete());
3552 JS_ASSERT_IF(scope
->table
, !scope
->has(sprop
));
3555 JS_ASSERT(slot
== scope
->freeslot
);
3556 if (slot
< STOBJ_NSLOTS(obj
)) {
3559 if (!js_AllocSlot(cx
, obj
, &slot
)) {
3560 JS_UNLOCK_SCOPE(cx
, scope
);
3563 JS_ASSERT(slot
== sprop
->slot
);
3566 JS_ASSERT(!scope
->lastProp
||
3567 scope
->shape
== scope
->lastProp
->shape
);
3569 JSScopeProperty
*sprop2
=
3570 scope
->add(cx
, sprop
->id
,
3571 sprop
->getter
, sprop
->setter
,
3573 sprop
->flags
, sprop
->shortid
);
3575 js_FreeSlot(cx
, obj
, slot
);
3576 JS_UNLOCK_SCOPE(cx
, scope
);
3579 JS_ASSERT(sprop2
== sprop
);
3581 JS_ASSERT(scope
->owned());
3582 scope
->extend(cx
, sprop
);
3586 * No method change check here because here we are adding a new
3587 * property, not updating an existing slot's value that might
3588 * contain a method of a branded scope.
3590 TRACE_2(SetPropHit
, entry
, sprop
);
3591 LOCKED_OBJ_SET_SLOT(obj
, slot
, rval
);
3592 JS_UNLOCK_SCOPE(cx
, scope
);
3597 PCMETER(cache
->inipcmisses
++);
3598 JS_UNLOCK_SCOPE(cx
, scope
);
3600 /* Get the immediate property name into id. */
3602 id
= ATOM_TO_JSID(atom
);
3604 /* Set the property named by obj[id] to rval. */
3605 if (!js_CheckRedeclaration(cx
, obj
, id
, JSPROP_INITIALIZER
,
3610 uintN defineHow
= (op
== JSOP_INITMETHOD
)
3611 ? JSDNP_CACHE_RESULT
| JSDNP_SET_METHOD
3612 : JSDNP_CACHE_RESULT
;
3613 if (!(JS_UNLIKELY(atom
== cx
->runtime
->atomState
.protoAtom
)
3614 ? js_SetPropertyHelper(cx
, obj
, id
, defineHow
, &rval
)
3615 : js_DefineNativeProperty(cx
, obj
, id
, rval
, NULL
, NULL
,
3616 JSPROP_ENUMERATE
, 0, 0, NULL
,
3622 /* Common tail for property cache hit and miss cases. */
3624 END_CASE(JSOP_INITPROP
);
3626 BEGIN_CASE(JSOP_INITELEM
)
3627 /* Pop the element's value into rval. */
3628 JS_ASSERT(regs
.sp
- StackBase(fp
) >= 3);
3629 rval
= FETCH_OPND(-1);
3631 /* Find the object being initialized at top of stack. */
3632 lval
= FETCH_OPND(-3);
3633 JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval
));
3634 obj
= JSVAL_TO_OBJECT(lval
);
3636 /* Fetch id now that we have obj. */
3637 FETCH_ELEMENT_ID(obj
, -2, id
);
3640 * Check for property redeclaration strict warning (we may be in an object
3641 * initialiser, not an array initialiser).
3643 if (!js_CheckRedeclaration(cx
, obj
, id
, JSPROP_INITIALIZER
, NULL
, NULL
))
3647 * If rval is a hole, do not call JSObject::defineProperty. In this case,
3648 * obj must be an array, so if the current op is the last element
3649 * initialiser, set the array length to one greater than id.
3651 if (rval
== JSVAL_HOLE
) {
3652 JS_ASSERT(OBJ_IS_ARRAY(cx
, obj
));
3653 JS_ASSERT(JSID_IS_INT(id
));
3654 JS_ASSERT(jsuint(JSID_TO_INT(id
)) < JS_ARGS_LENGTH_MAX
);
3655 if (js_GetOpcode(cx
, script
, regs
.pc
+ JSOP_INITELEM_LENGTH
) == JSOP_ENDINIT
&&
3656 !js_SetLengthProperty(cx
, obj
, (jsuint
) (JSID_TO_INT(id
) + 1))) {
3660 if (!obj
->defineProperty(cx
, id
, rval
, NULL
, NULL
, JSPROP_ENUMERATE
))
3664 END_CASE(JSOP_INITELEM
)
3666 #if JS_HAS_SHARP_VARS
3668 BEGIN_CASE(JSOP_DEFSHARP
)
3669 slot
= GET_UINT16(regs
.pc
);
3670 JS_ASSERT(slot
+ 1 < fp
->script
->nfixed
);
3671 lval
= fp
->slots
[slot
];
3672 if (!JSVAL_IS_PRIMITIVE(lval
)) {
3673 obj
= JSVAL_TO_OBJECT(lval
);
3675 JS_ASSERT(JSVAL_IS_VOID(lval
));
3676 obj
= js_NewArrayObject(cx
, 0, NULL
);
3679 fp
->slots
[slot
] = OBJECT_TO_JSVAL(obj
);
3681 i
= (jsint
) GET_UINT16(regs
.pc
+ UINT16_LEN
);
3682 id
= INT_TO_JSID(i
);
3683 rval
= FETCH_OPND(-1);
3684 if (JSVAL_IS_PRIMITIVE(rval
)) {
3686 JS_snprintf(numBuf
, sizeof numBuf
, "%u", (unsigned) i
);
3687 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
3688 JSMSG_BAD_SHARP_DEF
, numBuf
);
3691 if (!obj
->defineProperty(cx
, id
, rval
, NULL
, NULL
, JSPROP_ENUMERATE
))
3693 END_CASE(JSOP_DEFSHARP
)
3695 BEGIN_CASE(JSOP_USESHARP
)
3696 slot
= GET_UINT16(regs
.pc
);
3697 JS_ASSERT(slot
+ 1 < fp
->script
->nfixed
);
3698 lval
= fp
->slots
[slot
];
3699 i
= (jsint
) GET_UINT16(regs
.pc
+ UINT16_LEN
);
3700 if (JSVAL_IS_VOID(lval
)) {
3703 obj
= JSVAL_TO_OBJECT(fp
->slots
[slot
]);
3704 id
= INT_TO_JSID(i
);
3705 if (!obj
->getProperty(cx
, id
, &rval
))
3708 if (!JSVAL_IS_OBJECT(rval
)) {
3711 JS_snprintf(numBuf
, sizeof numBuf
, "%u", (unsigned) i
);
3712 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
3713 JSMSG_BAD_SHARP_USE
, numBuf
);
3717 END_CASE(JSOP_USESHARP
)
3719 BEGIN_CASE(JSOP_SHARPINIT
)
3720 slot
= GET_UINT16(regs
.pc
);
3721 JS_ASSERT(slot
+ 1 < fp
->script
->nfixed
);
3722 vp
= &fp
->slots
[slot
];
3726 * We peek ahead safely here because empty initialisers get zero
3727 * JSOP_SHARPINIT ops, and non-empty ones get two: the first comes
3728 * immediately after JSOP_NEWINIT followed by one or more property
3729 * initialisers; and the second comes directly before JSOP_ENDINIT.
3731 if (regs
.pc
[JSOP_SHARPINIT_LENGTH
] != JSOP_ENDINIT
) {
3732 rval
= JSVAL_IS_VOID(rval
) ? JSVAL_ONE
: rval
+ 2;
3734 JS_ASSERT(JSVAL_IS_INT(rval
));
3736 if (rval
== JSVAL_ZERO
)
3740 END_CASE(JSOP_SHARPINIT
)
3742 #endif /* JS_HAS_SHARP_VARS */
3744 BEGIN_CASE(JSOP_GOSUB
)
3746 i
= (regs
.pc
- script
->main
) + JSOP_GOSUB_LENGTH
;
3747 PUSH(INT_TO_JSVAL(i
));
3748 len
= GET_JUMP_OFFSET(regs
.pc
);
3751 BEGIN_CASE(JSOP_GOSUBX
)
3753 i
= (regs
.pc
- script
->main
) + JSOP_GOSUBX_LENGTH
;
3754 len
= GET_JUMPX_OFFSET(regs
.pc
);
3755 PUSH(INT_TO_JSVAL(i
));
3758 BEGIN_CASE(JSOP_RETSUB
)
3759 /* Pop [exception or hole, retsub pc-index]. */
3762 JS_ASSERT(JSVAL_IS_BOOLEAN(lval
));
3763 if (JSVAL_TO_BOOLEAN(lval
)) {
3765 * Exception was pending during finally, throw it *before* we adjust
3766 * pc, because pc indexes into script->trynotes. This turns out not to
3767 * be necessary, but it seems clearer. And it points out a FIXME:
3768 * 350509, due to Igor Bukanov.
3770 cx
->throwing
= JS_TRUE
;
3771 cx
->exception
= rval
;
3774 JS_ASSERT(JSVAL_IS_INT(rval
));
3775 len
= JSVAL_TO_INT(rval
);
3776 regs
.pc
= script
->main
;
3779 BEGIN_CASE(JSOP_EXCEPTION
)
3780 JS_ASSERT(cx
->throwing
);
3781 PUSH(cx
->exception
);
3782 cx
->throwing
= JS_FALSE
;
3784 END_CASE(JSOP_EXCEPTION
)
3786 BEGIN_CASE(JSOP_FINALLY
)
3788 END_CASE(JSOP_FINALLY
)
3790 BEGIN_CASE(JSOP_THROWING
)
3791 JS_ASSERT(!cx
->throwing
);
3792 cx
->throwing
= JS_TRUE
;
3793 cx
->exception
= POP_OPND();
3794 END_CASE(JSOP_THROWING
)
3796 BEGIN_CASE(JSOP_THROW
)
3797 JS_ASSERT(!cx
->throwing
);
3799 cx
->throwing
= JS_TRUE
;
3800 cx
->exception
= POP_OPND();
3801 /* let the code at error try to catch the exception. */
3804 BEGIN_CASE(JSOP_SETLOCALPOP
)
3806 * The stack must have a block with at least one local slot below the
3809 JS_ASSERT((size_t) (regs
.sp
- StackBase(fp
)) >= 2);
3810 slot
= GET_UINT16(regs
.pc
);
3811 JS_ASSERT(slot
+ 1 < script
->nslots
);
3812 fp
->slots
[slot
] = POP_OPND();
3813 END_CASE(JSOP_SETLOCALPOP
)
3815 BEGIN_CASE(JSOP_IFPRIMTOP
)
3817 * If the top of stack is of primitive type, jump to our target. Otherwise
3818 * advance to the next opcode.
3820 JS_ASSERT(regs
.sp
> StackBase(fp
));
3821 rval
= FETCH_OPND(-1);
3822 if (JSVAL_IS_PRIMITIVE(rval
)) {
3823 len
= GET_JUMP_OFFSET(regs
.pc
);
3826 END_CASE(JSOP_IFPRIMTOP
)
3828 BEGIN_CASE(JSOP_PRIMTOP
)
3829 JS_ASSERT(regs
.sp
> StackBase(fp
));
3830 lval
= FETCH_OPND(-1);
3831 i
= GET_INT8(regs
.pc
);
3832 if (!JSVAL_IS_PRIMITIVE(lval
)) {
3833 lval
= FETCH_OPND(-2);
3834 js_ReportValueError2(cx
, JSMSG_CANT_CONVERT_TO
, -2, lval
, NULL
,
3835 (i
== JSTYPE_VOID
) ? "primitive type" : JS_TYPE_STR(i
));
3838 END_CASE(JSOP_PRIMTOP
)
3840 BEGIN_CASE(JSOP_OBJTOP
)
3841 lval
= FETCH_OPND(-1);
3842 if (JSVAL_IS_PRIMITIVE(lval
)) {
3843 js_ReportValueError(cx
, GET_UINT16(regs
.pc
), -1, lval
, NULL
);
3846 END_CASE(JSOP_OBJTOP
)
3848 BEGIN_CASE(JSOP_INSTANCEOF
)
3849 rval
= FETCH_OPND(-1);
3850 if (JSVAL_IS_PRIMITIVE(rval
) ||
3851 !(obj
= JSVAL_TO_OBJECT(rval
))->map
->ops
->hasInstance
) {
3852 js_ReportValueError(cx
, JSMSG_BAD_INSTANCEOF_RHS
,
3856 lval
= FETCH_OPND(-2);
3858 if (!obj
->map
->ops
->hasInstance(cx
, obj
, lval
, &cond
))
3861 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond
));
3862 END_CASE(JSOP_INSTANCEOF
)
3864 #if JS_HAS_DEBUGGER_KEYWORD
3865 BEGIN_CASE(JSOP_DEBUGGER
)
3867 JSTrapHandler handler
= cx
->debugHooks
->debuggerHandler
;
3869 switch (handler(cx
, script
, regs
.pc
, &rval
, cx
->debugHooks
->debuggerHandlerData
)) {
3872 case JSTRAP_CONTINUE
:
3879 cx
->throwing
= JS_TRUE
;
3880 cx
->exception
= rval
;
3884 CHECK_INTERRUPT_HANDLER();
3887 END_CASE(JSOP_DEBUGGER
)
3888 #endif /* JS_HAS_DEBUGGER_KEYWORD */
3890 #if JS_HAS_XML_SUPPORT
3891 BEGIN_CASE(JSOP_DEFXMLNS
)
3893 if (!js_SetDefaultXMLNamespace(cx
, rval
))
3895 END_CASE(JSOP_DEFXMLNS
)
3897 BEGIN_CASE(JSOP_ANYNAME
)
3898 if (!js_GetAnyName(cx
, &rval
))
3901 END_CASE(JSOP_ANYNAME
)
3903 BEGIN_CASE(JSOP_QNAMEPART
)
3905 PUSH_OPND(ATOM_KEY(atom
));
3906 END_CASE(JSOP_QNAMEPART
)
3908 BEGIN_CASE(JSOP_QNAMECONST
)
3910 rval
= ATOM_KEY(atom
);
3911 lval
= FETCH_OPND(-1);
3912 obj
= js_ConstructXMLQNameObject(cx
, lval
, rval
);
3915 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
3916 END_CASE(JSOP_QNAMECONST
)
3918 BEGIN_CASE(JSOP_QNAME
)
3919 rval
= FETCH_OPND(-1);
3920 lval
= FETCH_OPND(-2);
3921 obj
= js_ConstructXMLQNameObject(cx
, lval
, rval
);
3925 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
3926 END_CASE(JSOP_QNAME
)
3928 BEGIN_CASE(JSOP_TOATTRNAME
)
3929 rval
= FETCH_OPND(-1);
3930 if (!js_ToAttributeName(cx
, &rval
))
3932 STORE_OPND(-1, rval
);
3933 END_CASE(JSOP_TOATTRNAME
)
3935 BEGIN_CASE(JSOP_TOATTRVAL
)
3936 rval
= FETCH_OPND(-1);
3937 JS_ASSERT(JSVAL_IS_STRING(rval
));
3938 str
= js_EscapeAttributeValue(cx
, JSVAL_TO_STRING(rval
), JS_FALSE
);
3941 STORE_OPND(-1, STRING_TO_JSVAL(str
));
3942 END_CASE(JSOP_TOATTRVAL
)
3944 BEGIN_CASE(JSOP_ADDATTRNAME
)
3945 BEGIN_CASE(JSOP_ADDATTRVAL
)
3946 rval
= FETCH_OPND(-1);
3947 lval
= FETCH_OPND(-2);
3948 str
= JSVAL_TO_STRING(lval
);
3949 str2
= JSVAL_TO_STRING(rval
);
3950 str
= js_AddAttributePart(cx
, op
== JSOP_ADDATTRNAME
, str
, str2
);
3954 STORE_OPND(-1, STRING_TO_JSVAL(str
));
3955 END_CASE(JSOP_ADDATTRNAME
)
3957 BEGIN_CASE(JSOP_BINDXMLNAME
)
3958 lval
= FETCH_OPND(-1);
3959 if (!js_FindXMLProperty(cx
, lval
, &obj
, &id
))
3961 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
3962 PUSH_OPND(ID_TO_VALUE(id
));
3963 END_CASE(JSOP_BINDXMLNAME
)
3965 BEGIN_CASE(JSOP_SETXMLNAME
)
3966 obj
= JSVAL_TO_OBJECT(FETCH_OPND(-3));
3967 rval
= FETCH_OPND(-1);
3968 FETCH_ELEMENT_ID(obj
, -2, id
);
3969 if (!obj
->setProperty(cx
, id
, &rval
))
3971 rval
= FETCH_OPND(-1);
3973 STORE_OPND(-1, rval
);
3974 END_CASE(JSOP_SETXMLNAME
)
3976 BEGIN_CASE(JSOP_CALLXMLNAME
)
3977 BEGIN_CASE(JSOP_XMLNAME
)
3978 lval
= FETCH_OPND(-1);
3979 if (!js_FindXMLProperty(cx
, lval
, &obj
, &id
))
3981 if (!obj
->getProperty(cx
, id
, &rval
))
3983 STORE_OPND(-1, rval
);
3984 if (op
== JSOP_CALLXMLNAME
)
3985 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
3986 END_CASE(JSOP_XMLNAME
)
3988 BEGIN_CASE(JSOP_DESCENDANTS
)
3989 BEGIN_CASE(JSOP_DELDESC
)
3990 FETCH_OBJECT(cx
, -2, lval
, obj
);
3991 rval
= FETCH_OPND(-1);
3992 if (!js_GetXMLDescendants(cx
, obj
, rval
, &rval
))
3995 if (op
== JSOP_DELDESC
) {
3996 regs
.sp
[-1] = rval
; /* set local root */
3997 if (!js_DeleteXMLListElements(cx
, JSVAL_TO_OBJECT(rval
)))
3999 rval
= JSVAL_TRUE
; /* always succeed */
4003 STORE_OPND(-1, rval
);
4004 END_CASE(JSOP_DESCENDANTS
)
4006 BEGIN_CASE(JSOP_FILTER
)
4008 * We push the hole value before jumping to [enditer] so we can detect the
4009 * first iteration and direct js_StepXMLListFilter to initialize filter's
4012 PUSH_OPND(JSVAL_HOLE
);
4013 len
= GET_JUMP_OFFSET(regs
.pc
);
4017 BEGIN_CASE(JSOP_ENDFILTER
)
4018 cond
= (regs
.sp
[-1] != JSVAL_HOLE
);
4020 /* Exit the "with" block left from the previous iteration. */
4023 if (!js_StepXMLListFilter(cx
, cond
))
4025 if (regs
.sp
[-1] != JSVAL_NULL
) {
4027 * Decrease sp after EnterWith returns as we use sp[-1] there to root
4030 JS_ASSERT(VALUE_IS_XML(cx
, regs
.sp
[-1]));
4031 if (!js_EnterWith(cx
, -2))
4034 len
= GET_JUMP_OFFSET(regs
.pc
);
4039 END_CASE(JSOP_ENDFILTER
);
4041 BEGIN_CASE(JSOP_TOXML
)
4042 rval
= FETCH_OPND(-1);
4043 obj
= js_ValueToXMLObject(cx
, rval
);
4046 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
4047 END_CASE(JSOP_TOXML
)
4049 BEGIN_CASE(JSOP_TOXMLLIST
)
4050 rval
= FETCH_OPND(-1);
4051 obj
= js_ValueToXMLListObject(cx
, rval
);
4054 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
4055 END_CASE(JSOP_TOXMLLIST
)
4057 BEGIN_CASE(JSOP_XMLTAGEXPR
)
4058 rval
= FETCH_OPND(-1);
4059 str
= js_ValueToString(cx
, rval
);
4062 STORE_OPND(-1, STRING_TO_JSVAL(str
));
4063 END_CASE(JSOP_XMLTAGEXPR
)
4065 BEGIN_CASE(JSOP_XMLELTEXPR
)
4066 rval
= FETCH_OPND(-1);
4067 if (VALUE_IS_XML(cx
, rval
)) {
4068 str
= js_ValueToXMLString(cx
, rval
);
4070 str
= js_ValueToString(cx
, rval
);
4072 str
= js_EscapeElementValue(cx
, str
);
4076 STORE_OPND(-1, STRING_TO_JSVAL(str
));
4077 END_CASE(JSOP_XMLELTEXPR
)
4079 BEGIN_CASE(JSOP_XMLOBJECT
)
4081 obj
= js_CloneXMLObject(cx
, obj
);
4084 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
4085 END_CASE(JSOP_XMLOBJECT
)
4087 BEGIN_CASE(JSOP_XMLCDATA
)
4089 str
= ATOM_TO_STRING(atom
);
4090 obj
= js_NewXMLSpecialObject(cx
, JSXML_CLASS_TEXT
, NULL
, str
);
4093 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
4094 END_CASE(JSOP_XMLCDATA
)
4096 BEGIN_CASE(JSOP_XMLCOMMENT
)
4098 str
= ATOM_TO_STRING(atom
);
4099 obj
= js_NewXMLSpecialObject(cx
, JSXML_CLASS_COMMENT
, NULL
, str
);
4102 PUSH_OPND(OBJECT_TO_JSVAL(obj
));
4103 END_CASE(JSOP_XMLCOMMENT
)
4105 BEGIN_CASE(JSOP_XMLPI
)
4107 str
= ATOM_TO_STRING(atom
);
4108 rval
= FETCH_OPND(-1);
4109 str2
= JSVAL_TO_STRING(rval
);
4110 obj
= js_NewXMLSpecialObject(cx
, JSXML_CLASS_PROCESSING_INSTRUCTION
, str
, str2
);
4113 STORE_OPND(-1, OBJECT_TO_JSVAL(obj
));
4114 END_CASE(JSOP_XMLPI
)
4116 BEGIN_CASE(JSOP_GETFUNNS
)
4117 if (!js_GetFunctionNamespace(cx
, &rval
))
4120 END_CASE(JSOP_GETFUNNS
)
4121 #endif /* JS_HAS_XML_SUPPORT */
4123 BEGIN_CASE(JSOP_ENTERBLOCK
)
4125 JS_ASSERT(!OBJ_IS_CLONED_BLOCK(obj
));
4126 JS_ASSERT(StackBase(fp
) + OBJ_BLOCK_DEPTH(cx
, obj
) == regs
.sp
);
4127 vp
= regs
.sp
+ OBJ_BLOCK_COUNT(cx
, obj
);
4128 JS_ASSERT(regs
.sp
< vp
);
4129 JS_ASSERT(vp
<= fp
->slots
+ script
->nslots
);
4130 while (regs
.sp
< vp
) {
4131 STORE_OPND(0, JSVAL_VOID
);
4136 JS_ASSERT(fp
->blockChain
== OBJ_GET_PARENT(cx
, obj
));
4139 * The young end of fp->scopeChain may omit blocks if we haven't closed
4140 * over them, but if there are any closure blocks on fp->scopeChain, they'd
4141 * better be (clones of) ancestors of the block we're entering now;
4142 * anything else we should have popped off fp->scopeChain when we left its
4145 obj2
= fp
->scopeChain
;
4146 while ((clasp
= OBJ_GET_CLASS(cx
, obj2
)) == &js_WithClass
)
4147 obj2
= OBJ_GET_PARENT(cx
, obj2
);
4148 if (clasp
== &js_BlockClass
&&
4149 obj2
->getPrivate() == fp
) {
4150 JSObject
*youngestProto
= OBJ_GET_PROTO(cx
, obj2
);
4151 JS_ASSERT(!OBJ_IS_CLONED_BLOCK(youngestProto
));
4153 while ((parent
= OBJ_GET_PARENT(cx
, parent
)) != youngestProto
)
4158 fp
->blockChain
= obj
;
4159 END_CASE(JSOP_ENTERBLOCK
)
4161 BEGIN_CASE(JSOP_LEAVEBLOCKEXPR
)
4162 BEGIN_CASE(JSOP_LEAVEBLOCK
)
4165 JS_ASSERT(OBJ_GET_CLASS(cx
, fp
->blockChain
) == &js_BlockClass
);
4166 uintN blockDepth
= OBJ_BLOCK_DEPTH(cx
, fp
->blockChain
);
4168 JS_ASSERT(blockDepth
<= StackDepth(script
));
4171 * If we're about to leave the dynamic scope of a block that has been
4172 * cloned onto fp->scopeChain, clear its private data, move its locals from
4173 * the stack into the clone, and pop it off the chain.
4175 obj
= fp
->scopeChain
;
4176 if (OBJ_GET_PROTO(cx
, obj
) == fp
->blockChain
) {
4177 JS_ASSERT (OBJ_GET_CLASS(cx
, obj
) == &js_BlockClass
);
4178 if (!js_PutBlockObject(cx
, JS_TRUE
))
4182 /* Pop the block chain, too. */
4183 fp
->blockChain
= OBJ_GET_PARENT(cx
, fp
->blockChain
);
4185 /* Move the result of the expression to the new topmost stack slot. */
4186 if (op
== JSOP_LEAVEBLOCKEXPR
)
4187 rval
= FETCH_OPND(-1);
4188 regs
.sp
-= GET_UINT16(regs
.pc
);
4189 if (op
== JSOP_LEAVEBLOCKEXPR
) {
4190 JS_ASSERT(StackBase(fp
) + blockDepth
== regs
.sp
- 1);
4191 STORE_OPND(-1, rval
);
4193 JS_ASSERT(StackBase(fp
) + blockDepth
== regs
.sp
);
4196 END_CASE(JSOP_LEAVEBLOCK
)
4198 BEGIN_CASE(JSOP_CALLBUILTIN
)
4200 obj
= js_GetBuiltinFunction(cx
, GET_INDEX(regs
.pc
));
4203 rval
= FETCH_OPND(-1);
4205 STORE_OPND(-2, OBJECT_TO_JSVAL(obj
));
4207 goto bad_opcode
; /* This is an imacro-only opcode. */
4209 END_CASE(JSOP_CALLBUILTIN
)
4211 #if JS_HAS_GENERATORS
4212 BEGIN_CASE(JSOP_GENERATOR
)
4213 ASSERT_NOT_THROWING(cx
);
4214 regs
.pc
+= JSOP_GENERATOR_LENGTH
;
4215 obj
= js_NewGenerator(cx
, fp
);
4218 JS_ASSERT(!fp
->callobj
&& !fp
->argsobj
);
4219 fp
->rval
= OBJECT_TO_JSVAL(obj
);
4221 if (inlineCallCount
!= 0)
4225 BEGIN_CASE(JSOP_YIELD
)
4226 ASSERT_NOT_THROWING(cx
);
4227 if (FRAME_TO_GENERATOR(fp
)->state
== JSGEN_CLOSING
) {
4228 js_ReportValueError(cx
, JSMSG_BAD_GENERATOR_YIELD
,
4229 JSDVG_SEARCH_STACK
, fp
->argv
[-2], NULL
);
4232 fp
->rval
= FETCH_OPND(-1);
4233 fp
->flags
|= JSFRAME_YIELDING
;
4234 regs
.pc
+= JSOP_YIELD_LENGTH
;
4238 BEGIN_CASE(JSOP_ARRAYPUSH
)
4239 slot
= GET_UINT16(regs
.pc
);
4240 JS_ASSERT(script
->nfixed
<= slot
);
4241 JS_ASSERT(slot
< script
->nslots
);
4242 lval
= fp
->slots
[slot
];
4243 obj
= JSVAL_TO_OBJECT(lval
);
4244 rval
= FETCH_OPND(-1);
4245 if (!js_ArrayCompPush(cx
, obj
, rval
))
4248 END_CASE(JSOP_ARRAYPUSH
)
4249 #endif /* JS_HAS_GENERATORS */
4251 #if JS_THREADED_INTERP
4253 L_JSOP_BACKPATCH_POP
:
4255 # if !JS_HAS_GENERATORS
4261 # if !JS_HAS_SHARP_VARS
4267 # if !JS_HAS_DESTRUCTURING
4268 L_JSOP_ENUMCONSTELEM
:
4271 # if !JS_HAS_XML_SUPPORT
4273 L_JSOP_STARTXMLEXPR
:
4301 #endif /* !JS_THREADED_INTERP */