Fix method barrier not to brand, period (branding without reshaping is worse, brandin...
[mozilla-central.git] / js / src / jsops.cpp
bloba736b9de88d2a623b01f7d03c6c9d05f891aec59
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
15 * License.
17 * The Original Code is Mozilla Communicator client code, released
18 * March 31, 1998.
20 * The Initial Developer of the Original Code is
21 * Netscape Communications Corporation.
22 * Portions created by the Initial Developer are Copyright (C) 1998
23 * the Initial Developer. All Rights Reserved.
25 * Contributor(s):
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 /* This file needs to be included in possibly multiple places. */
43 #if JS_THREADED_INTERP
44 interrupt:
45 #else /* !JS_THREADED_INTERP */
46 case -1:
47 JS_ASSERT(switchMask == -1);
48 #endif /* !JS_THREADED_INTERP */
50 bool moreInterrupts = false;
51 JSTrapHandler handler = cx->debugHooks->interruptHandler;
52 if (handler) {
53 #ifdef JS_TRACER
54 if (TRACE_RECORDER(cx))
55 js_AbortRecording(cx, "interrupt handler");
56 #endif
57 switch (handler(cx, script, regs.pc, &rval,
58 cx->debugHooks->interruptHandlerData)) {
59 case JSTRAP_ERROR:
60 goto error;
61 case JSTRAP_CONTINUE:
62 break;
63 case JSTRAP_RETURN:
64 fp->rval = rval;
65 ok = JS_TRUE;
66 goto forced_return;
67 case JSTRAP_THROW:
68 cx->throwing = JS_TRUE;
69 cx->exception = rval;
70 goto error;
71 default:;
73 moreInterrupts = true;
76 #ifdef JS_TRACER
77 if (TraceRecorder* tr = TRACE_RECORDER(cx)) {
78 AbortableRecordingStatus status = tr->monitorRecording(op);
79 switch (status) {
80 case ARECORD_CONTINUE:
81 moreInterrupts = true;
82 break;
83 case ARECORD_IMACRO:
84 atoms = COMMON_ATOMS_START(&rt->atomState);
85 op = JSOp(*regs.pc);
86 DO_OP(); /* keep interrupting for op. */
87 break;
88 case ARECORD_ERROR:
89 // The code at 'error:' aborts the recording.
90 goto error;
91 case ARECORD_ABORTED:
92 case ARECORD_COMPLETED:
93 break;
94 case ARECORD_STOP:
95 /* A 'stop' error should have already aborted recording. */
96 default:
97 JS_NOT_REACHED("Bad recording status");
100 #endif /* !JS_TRACER */
102 #if JS_THREADED_INTERP
103 #ifdef MOZ_TRACEVIS
104 if (!moreInterrupts)
105 js_ExitTraceVisState(cx, R_ABORT);
106 #endif
107 jumpTable = moreInterrupts ? interruptJumpTable : normalJumpTable;
108 JS_EXTENSION_(goto *normalJumpTable[op]);
109 #else
110 switchMask = moreInterrupts ? -1 : 0;
111 switchOp = intN(op);
112 goto do_switch;
113 #endif
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)
124 #endif
125 END_EMPTY_CASES
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);
133 END_CASE(JSOP_PUSH)
135 BEGIN_CASE(JSOP_POP)
136 regs.sp--;
137 END_CASE(JSOP_POP)
139 BEGIN_CASE(JSOP_POPN)
140 regs.sp -= GET_UINT16(regs.pc);
141 #ifdef DEBUG
142 JS_ASSERT(StackBase(fp) <= regs.sp);
143 obj = fp->blockChain;
144 JS_ASSERT_IF(obj,
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)
150 continue;
151 if (obj->getPrivate() != fp)
152 break;
153 JS_ASSERT(StackBase(fp) + OBJ_BLOCK_DEPTH(cx, obj)
154 + ((clasp == &js_BlockClass)
155 ? OBJ_BLOCK_COUNT(cx, obj)
156 : 1)
157 <= regs.sp);
159 #endif
160 END_CASE(JSOP_POPN)
162 BEGIN_CASE(JSOP_SETRVAL)
163 BEGIN_CASE(JSOP_POPV)
164 ASSERT_NOT_THROWING(cx);
165 fp->rval = POP_OPND();
166 END_CASE(JSOP_POPV)
168 BEGIN_CASE(JSOP_ENTERWITH)
169 if (!js_EnterWith(cx, -1))
170 goto error;
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
176 * current level.
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));
186 regs.sp--;
187 js_LeaveWith(cx);
188 END_CASE(JSOP_LEAVEWITH)
190 BEGIN_CASE(JSOP_RETURN)
191 fp->rval = POP_OPND();
192 /* FALL THROUGH */
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);
201 CHECK_BRANCH();
203 if (fp->imacpc) {
205 * If we are at the end of an imacro, return to its caller in the
206 * current frame.
208 JS_ASSERT(op == JSOP_STOP);
210 end_imacro:
211 JS_ASSERT((uintN)(regs.sp - fp->slots) <= script->nslots);
212 regs.pc = fp->imacpc + js_CodeSpec[*fp->imacpc].length;
213 fp->imacpc = NULL;
214 atoms = script->atomMap.vector;
215 op = JSOp(*regs.pc);
216 DO_OP();
219 JS_ASSERT(regs.sp == StackBase(fp));
220 if ((fp->flags & JSFRAME_CONSTRUCTING) &&
221 JSVAL_IS_PRIMITIVE(fp->rval)) {
222 if (!fp->fun) {
223 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
224 JSMSG_BAD_NEW_RESULT,
225 js_ValueToPrintableString(cx, rval));
226 goto error;
228 fp->rval = fp->thisv;
230 ok = JS_TRUE;
231 if (inlineCallCount)
232 inline_return:
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;
243 if (hookData) {
244 JSInterpreterHook hook;
245 JSBool status;
247 hook = cx->debugHooks->callHook;
248 if (hook) {
250 * Do not pass &ok directly as exposing the address inhibits
251 * optimizations and uninitialised warnings.
253 status = ok;
254 hook(cx, fp, JS_FALSE, &status, hookData);
255 ok = status;
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
264 * 325540.
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);
274 #endif
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);
305 fp->regs = &regs;
306 JS_ARENA_RELEASE(&cx->stackPool, ifp->mark);
308 /* Restore the calling script's interpreter registers. */
309 script = fp->script;
310 atoms = FrameAtomBase(cx, fp);
312 /* Resume execution in the calling frame. */
313 inlineCallCount--;
314 if (JS_LIKELY(ok)) {
315 JS_ASSERT(js_CodeSpec[js_GetOpcode(cx, script, regs.pc)].length
316 == JSOP_CALL_LENGTH);
317 TRACE_0(LeaveFrame);
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);
322 op = (JSOp)*regs.pc;
323 DO_OP();
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;
331 } else {
332 len = JSOP_CALL_LENGTH;
334 DO_NEXT_OP(len);
336 goto error;
338 goto exit;
340 BEGIN_CASE(JSOP_DEFAULT)
341 (void) POP();
342 /* FALL THROUGH */
343 BEGIN_CASE(JSOP_GOTO)
344 len = GET_JUMP_OFFSET(regs.pc);
345 BRANCH(len);
346 END_CASE(JSOP_GOTO)
348 BEGIN_CASE(JSOP_IFEQ)
349 POP_BOOLEAN(cx, rval, cond);
350 if (cond == JS_FALSE) {
351 len = GET_JUMP_OFFSET(regs.pc);
352 BRANCH(len);
354 END_CASE(JSOP_IFEQ)
356 BEGIN_CASE(JSOP_IFNE)
357 POP_BOOLEAN(cx, rval, cond);
358 if (cond != JS_FALSE) {
359 len = GET_JUMP_OFFSET(regs.pc);
360 BRANCH(len);
362 END_CASE(JSOP_IFNE)
364 BEGIN_CASE(JSOP_OR)
365 POP_BOOLEAN(cx, rval, cond);
366 if (cond == JS_TRUE) {
367 len = GET_JUMP_OFFSET(regs.pc);
368 PUSH_OPND(rval);
369 DO_NEXT_OP(len);
371 END_CASE(JSOP_OR)
373 BEGIN_CASE(JSOP_AND)
374 POP_BOOLEAN(cx, rval, cond);
375 if (cond == JS_FALSE) {
376 len = GET_JUMP_OFFSET(regs.pc);
377 PUSH_OPND(rval);
378 DO_NEXT_OP(len);
380 END_CASE(JSOP_AND)
382 BEGIN_CASE(JSOP_DEFAULTX)
383 (void) POP();
384 /* FALL THROUGH */
385 BEGIN_CASE(JSOP_GOTOX)
386 len = GET_JUMPX_OFFSET(regs.pc);
387 BRANCH(len);
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);
394 BRANCH(len);
396 END_CASE(JSOP_IFEQX)
398 BEGIN_CASE(JSOP_IFNEX)
399 POP_BOOLEAN(cx, rval, cond);
400 if (cond != JS_FALSE) {
401 len = GET_JUMPX_OFFSET(regs.pc);
402 BRANCH(len);
404 END_CASE(JSOP_IFNEX)
406 BEGIN_CASE(JSOP_ORX)
407 POP_BOOLEAN(cx, rval, cond);
408 if (cond == JS_TRUE) {
409 len = GET_JUMPX_OFFSET(regs.pc);
410 PUSH_OPND(rval);
411 DO_NEXT_OP(len);
413 END_CASE(JSOP_ORX)
415 BEGIN_CASE(JSOP_ANDX)
416 POP_BOOLEAN(cx, rval, cond);
417 if (cond == JS_FALSE) {
418 len = GET_JUMPX_OFFSET(regs.pc);
419 PUSH_OPND(rval);
420 DO_NEXT_OP(len);
422 END_CASE(JSOP_ANDX)
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
428 * string atom id.
430 #define FETCH_ELEMENT_ID(obj, n, id) \
431 JS_BEGIN_MACRO \
432 jsval idval_ = FETCH_OPND(n); \
433 if (JSVAL_IS_INT(idval_)) { \
434 id = INT_JSVAL_TO_JSID(idval_); \
435 } else { \
436 if (!js_InternNonIntElementId(cx, obj, idval_, &id)) \
437 goto error; \
438 regs.sp[n] = ID_TO_VALUE(id); \
440 JS_END_MACRO
442 #define TRY_BRANCH_AFTER_COND(cond,spdec) \
443 JS_BEGIN_MACRO \
444 uintN diff_; \
445 JS_ASSERT(js_CodeSpec[op].length == 1); \
446 diff_ = (uintN) regs.pc[1] - (uintN) JSOP_IFEQ; \
447 if (diff_ <= 1) { \
448 regs.sp -= spdec; \
449 if (cond == (diff_ != 0)) { \
450 ++regs.pc; \
451 len = GET_JUMP_OFFSET(regs.pc); \
452 BRANCH(len); \
454 len = 1 + JSOP_IFEQ_LENGTH; \
455 DO_NEXT_OP(len); \
457 JS_END_MACRO
459 BEGIN_CASE(JSOP_IN)
460 rval = FETCH_OPND(-1);
461 if (JSVAL_IS_PRIMITIVE(rval)) {
462 js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rval, NULL);
463 goto error;
465 obj = JSVAL_TO_OBJECT(rval);
466 FETCH_ELEMENT_ID(obj, -2, id);
467 if (!obj->lookupProperty(cx, id, &obj2, &prop))
468 goto error;
469 cond = prop != NULL;
470 if (prop)
471 obj2->dropProperty(cx, prop);
472 TRY_BRANCH_AFTER_COND(cond, 2);
473 regs.sp--;
474 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));
475 END_CASE(JSOP_IN)
477 BEGIN_CASE(JSOP_ITER)
478 JS_ASSERT(regs.sp > StackBase(fp));
479 flags = regs.pc[1];
480 if (!js_ValueToIterator(cx, flags, &regs.sp[-1]))
481 goto error;
482 CHECK_INTERRUPT_HANDLER();
483 JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-1]));
484 PUSH(JSVAL_VOID);
485 END_CASE(JSOP_ITER)
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]), &regs.sp[-1]))
491 goto error;
492 CHECK_INTERRUPT_HANDLER();
493 rval = BOOLEAN_TO_JSVAL(regs.sp[-1] != JSVAL_HOLE);
494 PUSH(rval);
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]);
504 regs.sp -= 2;
505 if (!ok)
506 goto error;
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));
525 LOAD_ATOM(0);
526 id = ATOM_TO_JSID(atom);
527 if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
528 goto error;
529 if (prop)
530 obj2->dropProperty(cx, prop);
531 ok = obj->setProperty(cx, id, &regs.sp[-1]);
532 if (!ok)
533 goto error;
534 END_CASE(JSOP_FORNAME)
536 BEGIN_CASE(JSOP_FORPROP)
537 JS_ASSERT(regs.sp - 2 >= StackBase(fp));
538 LOAD_ATOM(0);
539 id = ATOM_TO_JSID(atom);
540 FETCH_OBJECT(cx, -1, lval, obj);
541 ok = obj->setProperty(cx, id, &regs.sp[-2]);
542 if (!ok)
543 goto error;
544 regs.sp--;
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);
556 PUSH(rval);
557 END_CASE(JSOP_FORELEM)
559 BEGIN_CASE(JSOP_DUP)
560 JS_ASSERT(regs.sp > StackBase(fp));
561 rval = FETCH_OPND(-1);
562 PUSH(rval);
563 END_CASE(JSOP_DUP)
565 BEGIN_CASE(JSOP_DUP2)
566 JS_ASSERT(regs.sp - 2 >= StackBase(fp));
567 lval = FETCH_OPND(-2);
568 rval = FETCH_OPND(-1);
569 PUSH(lval);
570 PUSH(rval);
571 END_CASE(JSOP_DUP2)
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);
579 END_CASE(JSOP_SWAP)
581 BEGIN_CASE(JSOP_PICK)
582 i = regs.pc[1];
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);
586 regs.sp[-1] = lval;
587 END_CASE(JSOP_PICK)
589 #define PROPERTY_OP(n, call) \
590 JS_BEGIN_MACRO \
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. */ \
595 if (!call) \
596 goto error; \
597 JS_END_MACRO
599 #define ELEMENT_OP(n, call) \
600 JS_BEGIN_MACRO \
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. */ \
608 if (!call) \
609 goto error; \
610 JS_END_MACRO
612 #define NATIVE_GET(cx,obj,pobj,sprop,getHow,vp) \
613 JS_BEGIN_MACRO \
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) \
620 : JSVAL_VOID; \
621 } else { \
622 if (!js_NativeGet(cx, obj, pobj, sprop, getHow, vp)) \
623 goto error; \
625 JS_END_MACRO
627 #define NATIVE_SET(cx,obj,sprop,entry,vp) \
628 JS_BEGIN_MACRO \
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); \
635 } else { \
636 if (!js_NativeSet(cx, obj, sprop, false, vp)) \
637 goto error; \
639 JS_END_MACRO
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) { \
654 regs.sp -= spdec; \
655 regs.pc += oplen + JSOP_POP_LENGTH; \
656 op = (JSOp) *regs.pc; \
657 DO_OP(); \
660 #define END_SET_CASE(OP) \
661 SKIP_POP_AFTER_SET(OP##_LENGTH, 1); \
662 END_CASE(OP)
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); \
669 END_CASE(OP)
671 BEGIN_CASE(JSOP_SETCONST)
672 LOAD_ATOM(0);
673 obj = fp->varobj;
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)) {
678 goto error;
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)) {
690 goto error;
692 regs.sp -= 3;
693 END_CASE(JSOP_ENUMCONSTELEM)
694 #endif
696 BEGIN_CASE(JSOP_BINDNAME)
697 do {
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
714 * forms.
716 obj = fp->scopeChain;
717 if (!OBJ_GET_PARENT(cx, obj))
718 break;
719 if (JS_LIKELY(OBJ_IS_NATIVE(obj))) {
720 PROPERTY_CACHE_TEST(cx, regs.pc, obj, obj2, entry, atom);
721 if (!atom) {
722 ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
723 JS_UNLOCK_OBJ(cx, obj2);
724 break;
726 } else {
727 entry = NULL;
728 LOAD_ATOM(0);
730 id = ATOM_TO_JSID(atom);
731 obj = js_FindIdentifierBase(cx, fp->scopeChain, id);
732 if (!obj)
733 goto error;
734 } while (0);
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);
741 DO_OP();
743 #define BITWISE_OP(OP) \
744 JS_BEGIN_MACRO \
745 FETCH_INT(cx, -2, i); \
746 FETCH_INT(cx, -1, j); \
747 i = i OP j; \
748 regs.sp--; \
749 STORE_INT(cx, -1, i); \
750 JS_END_MACRO
752 BEGIN_CASE(JSOP_BITOR)
753 BITWISE_OP(|);
754 END_CASE(JSOP_BITOR)
756 BEGIN_CASE(JSOP_BITXOR)
757 BITWISE_OP(^);
758 END_CASE(JSOP_BITXOR)
760 BEGIN_CASE(JSOP_BITAND)
761 BITWISE_OP(&);
762 END_CASE(JSOP_BITAND)
764 #define RELATIONAL_OP(OP) \
765 JS_BEGIN_MACRO \
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); \
771 } else { \
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; \
780 } else { \
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); \
787 regs.sp--; \
788 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
789 JS_END_MACRO
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)) \
805 rval = lval; \
806 if (!js_TestXMLEquality(cx, obj2, rval, &cond)) \
807 goto error; \
808 cond = cond OP JS_TRUE; \
809 } else
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)) \
819 goto error; \
820 cond = cond OP JS_TRUE; \
821 } else
822 #else
823 #define XML_EQUALITY_OP(OP) /* nothing */
824 #define EXTENDED_EQUALITY_OP(OP) /* nothing */
825 #endif
827 #define EQUALITY_OP(OP, IFNAN) \
828 JS_BEGIN_MACRO \
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); \
843 } else { \
844 EXTENDED_EQUALITY_OP(OP) \
845 /* Handle all undefined (=>NaN) and int combinations. */ \
846 cond = lval OP rval; \
848 } else { \
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)) { \
852 cond = 1 OP 0; \
853 } else { \
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; \
865 } else { \
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); \
873 regs.sp--; \
874 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
875 JS_END_MACRO
877 BEGIN_CASE(JSOP_EQ)
878 EQUALITY_OP(==, JS_FALSE);
879 END_CASE(JSOP_EQ)
881 BEGIN_CASE(JSOP_NE)
882 EQUALITY_OP(!=, JS_TRUE);
883 END_CASE(JSOP_NE)
885 #define STRICT_EQUALITY_OP(OP) \
886 JS_BEGIN_MACRO \
887 rval = FETCH_OPND(-1); \
888 lval = FETCH_OPND(-2); \
889 cond = js_StrictlyEqual(cx, lval, rval) OP JS_TRUE; \
890 regs.sp--; \
891 STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
892 JS_END_MACRO
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(==);
904 (void) POP();
905 if (cond) {
906 len = GET_JUMP_OFFSET(regs.pc);
907 BRANCH(len);
909 PUSH(lval);
910 END_CASE(JSOP_CASE)
912 BEGIN_CASE(JSOP_CASEX)
913 STRICT_EQUALITY_OP(==);
914 (void) POP();
915 if (cond) {
916 len = GET_JUMPX_OFFSET(regs.pc);
917 BRANCH(len);
919 PUSH(lval);
920 END_CASE(JSOP_CASEX)
922 BEGIN_CASE(JSOP_LT)
923 RELATIONAL_OP(<);
924 END_CASE(JSOP_LT)
926 BEGIN_CASE(JSOP_LE)
927 RELATIONAL_OP(<=);
928 END_CASE(JSOP_LE)
930 BEGIN_CASE(JSOP_GT)
931 RELATIONAL_OP(>);
932 END_CASE(JSOP_GT)
934 BEGIN_CASE(JSOP_GE)
935 RELATIONAL_OP(>=);
936 END_CASE(JSOP_GE)
938 #undef EQUALITY_OP
939 #undef RELATIONAL_OP
941 #define SIGNED_SHIFT_OP(OP) \
942 JS_BEGIN_MACRO \
943 FETCH_INT(cx, -2, i); \
944 FETCH_INT(cx, -1, j); \
945 i = i OP (j & 31); \
946 regs.sp--; \
947 STORE_INT(cx, -1, i); \
948 JS_END_MACRO
950 BEGIN_CASE(JSOP_LSH)
951 SIGNED_SHIFT_OP(<<);
952 END_CASE(JSOP_LSH)
954 BEGIN_CASE(JSOP_RSH)
955 SIGNED_SHIFT_OP(>>);
956 END_CASE(JSOP_RSH)
958 BEGIN_CASE(JSOP_URSH)
960 uint32 u;
962 FETCH_UINT(cx, -2, u);
963 FETCH_INT(cx, -1, j);
964 u >>= (j & 31);
965 regs.sp--;
966 STORE_UINT(cx, -1, u);
968 END_CASE(JSOP_URSH)
970 #undef BITWISE_OP
971 #undef SIGNED_SHIFT_OP
973 BEGIN_CASE(JSOP_ADD)
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))
981 goto error;
982 regs.sp--;
983 STORE_OPND(-1, rval);
984 } else
985 #endif
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)) {
992 if (cond) {
993 str = JSVAL_TO_STRING(lval);
994 str2 = js_ValueToString(cx, rval);
995 if (!str2)
996 goto error;
997 regs.sp[-1] = STRING_TO_JSVAL(str2);
998 } else {
999 str2 = JSVAL_TO_STRING(rval);
1000 str = js_ValueToString(cx, lval);
1001 if (!str)
1002 goto error;
1003 regs.sp[-2] = STRING_TO_JSVAL(str);
1005 str = js_ConcatStrings(cx, str, str2);
1006 if (!str)
1007 goto error;
1008 regs.sp--;
1009 STORE_OPND(-1, STRING_TO_JSVAL(str));
1010 } else {
1011 VALUE_TO_NUMBER(cx, -2, lval, d);
1012 VALUE_TO_NUMBER(cx, -1, rval, d2);
1013 d += d2;
1014 regs.sp--;
1015 STORE_NUMBER(cx, -1, d);
1018 END_CASE(JSOP_ADD)
1020 BEGIN_CASE(JSOP_CONCATN)
1022 #ifdef JS_TRACER
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
1030 * recorded imacro.
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;
1037 if (imacro) {
1038 argc = GET_ARGC(fp->imacpc);
1039 if (!recording)
1040 js_ConcatPostImacroStackCleanup(argc, regs, NULL);
1041 } else {
1042 #endif /* JS_TRACER */
1043 argc = GET_ARGC(regs.pc);
1044 #ifdef JS_TRACER
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)) {
1053 goto error;
1057 str = js_NewStringFromCharBuffer(cx, buf);
1058 if (!str)
1059 goto error;
1061 regs.sp -= argc - 1;
1062 STORE_OPND(-1, STRING_TO_JSVAL(str));
1064 #ifdef JS_TRACER
1065 if (imacro) {
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) \
1074 JS_BEGIN_MACRO \
1075 FETCH_NUMBER(cx, -2, d); \
1076 FETCH_NUMBER(cx, -1, d2); \
1077 d = d OP d2; \
1078 regs.sp--; \
1079 STORE_NUMBER(cx, -1, d); \
1080 JS_END_MACRO
1082 BEGIN_CASE(JSOP_SUB)
1083 BINARY_OP(-);
1084 END_CASE(JSOP_SUB)
1086 BEGIN_CASE(JSOP_MUL)
1087 BINARY_OP(*);
1088 END_CASE(JSOP_MUL)
1090 BEGIN_CASE(JSOP_DIV)
1091 FETCH_NUMBER(cx, -1, d2);
1092 FETCH_NUMBER(cx, -2, d);
1093 regs.sp--;
1094 if (d2 == 0) {
1095 #ifdef XP_WIN
1096 /* XXX MSVC miscompiles such that (NaN == 0) */
1097 if (JSDOUBLE_IS_NaN(d2))
1098 rval = rt->NaNValue;
1099 else
1100 #endif
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;
1105 else
1106 rval = rt->positiveInfinityValue;
1107 STORE_OPND(-1, rval);
1108 } else {
1109 d /= d2;
1110 STORE_NUMBER(cx, -1, d);
1112 END_CASE(JSOP_DIV)
1114 BEGIN_CASE(JSOP_MOD)
1115 FETCH_NUMBER(cx, -1, d2);
1116 FETCH_NUMBER(cx, -2, d);
1117 regs.sp--;
1118 if (d2 == 0) {
1119 STORE_OPND(-1, rt->NaNValue);
1120 } else {
1121 d = js_fmod(d, d2);
1122 STORE_NUMBER(cx, -1, d);
1124 END_CASE(JSOP_MOD)
1126 BEGIN_CASE(JSOP_NOT)
1127 POP_BOOLEAN(cx, rval, cond);
1128 PUSH_OPND(BOOLEAN_TO_JSVAL(!cond));
1129 END_CASE(JSOP_NOT)
1131 BEGIN_CASE(JSOP_BITNOT)
1132 FETCH_INT(cx, -1, i);
1133 i = ~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));
1148 i = -i;
1149 JS_ASSERT(INT_FITS_IN_JSVAL(i));
1150 regs.sp[-1] = INT_TO_JSVAL(i);
1151 } else {
1152 if (JSVAL_IS_DOUBLE(rval)) {
1153 d = *JSVAL_TO_DOUBLE(rval);
1154 } else {
1155 d = js_ValueToNumber(cx, &regs.sp[-1]);
1156 if (JSVAL_IS_NULL(regs.sp[-1]))
1157 goto error;
1158 JS_ASSERT(JSVAL_IS_NUMBER(regs.sp[-1]) ||
1159 regs.sp[-1] == JSVAL_TRUE);
1161 d = -d;
1162 if (!js_NewNumberInRootedValue(cx, d, &regs.sp[-1]))
1163 goto error;
1165 END_CASE(JSOP_NEG)
1167 BEGIN_CASE(JSOP_POS)
1168 rval = FETCH_OPND(-1);
1169 if (!JSVAL_IS_NUMBER(rval)) {
1170 d = js_ValueToNumber(cx, &regs.sp[-1]);
1171 rval = regs.sp[-1];
1172 if (JSVAL_IS_NULL(rval))
1173 goto error;
1174 if (rval == JSVAL_TRUE) {
1175 if (!js_NewNumberInRootedValue(cx, d, &regs.sp[-1]))
1176 goto error;
1177 } else {
1178 JS_ASSERT(JSVAL_IS_NUMBER(rval));
1181 END_CASE(JSOP_POS)
1183 BEGIN_CASE(JSOP_DELNAME)
1184 LOAD_ATOM(0);
1185 id = ATOM_TO_JSID(atom);
1186 if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
1187 goto error;
1189 /* ECMA says to return true if name is undefined or inherited. */
1190 PUSH_OPND(JSVAL_TRUE);
1191 if (prop) {
1192 obj2->dropProperty(cx, prop);
1193 if (!obj->deleteProperty(cx, id, &regs.sp[-1]))
1194 goto error;
1196 END_CASE(JSOP_DELNAME)
1198 BEGIN_CASE(JSOP_DELPROP)
1199 LOAD_ATOM(0);
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));
1207 regs.sp--;
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);
1221 END_CASE(JSOP_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.
1231 id = 0;
1232 i = -2;
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)
1239 LOAD_ATOM(0);
1240 id = ATOM_TO_JSID(atom);
1241 i = -1;
1243 fetch_incop_obj:
1244 FETCH_OBJECT(cx, i, lval, obj);
1245 if (id == 0)
1246 FETCH_ELEMENT_ID(obj, -1, id);
1247 goto do_incop;
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);
1259 if (!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))) {
1266 rtmp = rval;
1267 rval += (js_CodeSpec[op].format & JOF_INC) ? 2 : -2;
1268 if (!(js_CodeSpec[op].format & JOF_POST))
1269 rtmp = rval;
1270 LOCKED_OBJ_SET_SLOT(obj, slot, rval);
1271 JS_UNLOCK_OBJ(cx, obj);
1272 PUSH_OPND(rtmp);
1273 len = JSOP_INCNAME_LENGTH;
1274 DO_NEXT_OP(len);
1277 JS_UNLOCK_OBJ(cx, obj2);
1278 LOAD_ATOM(0);
1280 } else {
1281 LOAD_ATOM(0);
1283 id = ATOM_TO_JSID(atom);
1284 if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop))
1285 goto error;
1286 if (!prop)
1287 goto atom_not_defined;
1288 obj2->dropProperty(cx, prop);
1291 do_incop:
1293 const JSCodeSpec *cs;
1294 jsval v;
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, &regs.sp[-1]))
1302 goto error;
1304 cs = &js_CodeSpec[op];
1305 JS_ASSERT(cs->ndefs == 1);
1306 JS_ASSERT((cs->format & JOF_TMPSLOT_MASK) == JOF_TMPSLOT2);
1307 v = regs.sp[-1];
1308 if (JS_LIKELY(CAN_DO_FAST_INC_DEC(v))) {
1309 jsval incr;
1311 incr = (cs->format & JOF_INC) ? 2 : -2;
1312 if (cs->format & JOF_POST) {
1313 regs.sp[-1] = v + incr;
1314 } else {
1315 v += incr;
1316 regs.sp[-1] = v;
1318 fp->flags |= JSFRAME_ASSIGNING;
1319 ok = obj->setProperty(cx, id, &regs.sp[-1]);
1320 fp->flags &= ~JSFRAME_ASSIGNING;
1321 if (!ok)
1322 goto error;
1325 * We must set regs.sp[-1] to v for both post and pre increments
1326 * as the setter overwrites regs.sp[-1].
1328 regs.sp[-1] = v;
1329 } else {
1330 /* We need an extra root for the result. */
1331 PUSH_OPND(JSVAL_NULL);
1332 if (!js_DoIncDec(cx, cs, &regs.sp[-2], &regs.sp[-1]))
1333 goto error;
1334 fp->flags |= JSFRAME_ASSIGNING;
1335 ok = obj->setProperty(cx, id, &regs.sp[-1]);
1336 fp->flags &= ~JSFRAME_ASSIGNING;
1337 if (!ok)
1338 goto error;
1339 regs.sp--;
1342 if (cs->nuses == 0) {
1343 /* regs.sp[-1] already contains the result of name increment. */
1344 } else {
1345 rtmp = regs.sp[-1];
1346 regs.sp -= cs->nuses;
1347 regs.sp[-1] = rtmp;
1349 len = cs->length;
1350 DO_NEXT_OP(len);
1354 jsval incr, incr2;
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;
1366 do_arg_incop:
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
1385 * than arg++.
1387 do_local_incop:
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;
1394 do_int_fast_incop:
1395 rval = *vp;
1396 if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) {
1397 *vp = rval + incr;
1398 JS_ASSERT(JSOP_INCARG_LENGTH == js_CodeSpec[op].length);
1399 SKIP_POP_AFTER_SET(JSOP_INCARG_LENGTH, 0);
1400 PUSH_OPND(rval + incr2);
1401 } else {
1402 PUSH_OPND(rval);
1403 if (!js_DoIncDec(cx, &js_CodeSpec[op], &regs.sp[-1], vp))
1404 goto error;
1406 len = JSOP_INCARG_LENGTH;
1407 JS_ASSERT(len == js_CodeSpec[op].length);
1408 DO_NEXT_OP(len);
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) \
1413 op2 = SLOWOP; \
1414 incr = INCR; \
1415 incr2 = INCR2; \
1416 goto do_global_incop
1419 jsval incr, incr2;
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
1432 do_global_incop:
1433 JS_ASSERT((js_CodeSpec[op].format & JOF_TMPSLOT_MASK) ==
1434 JOF_TMPSLOT2);
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)) {
1440 op = op2;
1441 DO_OP();
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);
1447 rval += incr;
1448 } else {
1449 PUSH_OPND(rval);
1450 PUSH_OPND(JSVAL_NULL); /* Extra root */
1451 if (!js_DoIncDec(cx, &js_CodeSpec[op], &regs.sp[-2], &regs.sp[-1]))
1452 goto error;
1453 rval = regs.sp[-1];
1454 --regs.sp;
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);
1459 DO_NEXT_OP(len);
1462 #define COMPUTE_THIS(cx, fp, obj) \
1463 JS_BEGIN_MACRO \
1464 if (!(obj = js_ComputeThisForFrame(cx, fp))) \
1465 goto error; \
1466 JS_END_MACRO
1468 BEGIN_CASE(JSOP_THIS)
1469 COMPUTE_THIS(cx, fp, obj);
1470 PUSH_OPND(OBJECT_TO_JSVAL(obj));
1471 END_CASE(JSOP_THIS)
1473 BEGIN_CASE(JSOP_GETTHISPROP)
1474 i = 0;
1475 COMPUTE_THIS(cx, fp, obj);
1476 PUSH(JSVAL_NULL);
1477 goto do_getprop_with_obj;
1479 #undef COMPUTE_THIS
1481 BEGIN_CASE(JSOP_GETARGPROP)
1482 i = ARGNO_LEN;
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)
1489 i = SLOTNO_LEN;
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)
1497 i = 0;
1499 do_getprop_body:
1500 lval = FETCH_OPND(-1);
1502 do_getprop_with_lval:
1503 VALUE_TO_OBJECT(cx, -1, lval, obj);
1505 do_getprop_with_obj:
1506 do {
1507 JSObject *aobj;
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);
1518 if (!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);
1526 } else {
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,
1531 &rval);
1533 JS_UNLOCK_OBJ(cx, obj2);
1534 break;
1536 } else {
1537 entry = NULL;
1538 if (i < 0)
1539 atom = rt->atomState.lengthAtom;
1540 else
1541 LOAD_ATOM(i);
1543 id = ATOM_TO_JSID(atom);
1544 if (entry
1545 ? !js_GetPropertyHelper(cx, obj, id,
1546 fp->imacpc
1547 ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
1548 : JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER,
1549 &rval)
1550 : !obj->getProperty(cx, id, &rval)) {
1551 goto error;
1553 } while (0);
1555 STORE_OPND(-1, rval);
1556 JS_ASSERT(JSOP_GETPROP_LENGTH + i == js_CodeSpec[op].length);
1557 len = JSOP_GETPROP_LENGTH + i;
1558 END_VARLEN_CASE
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))) {
1567 jsuint length;
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,
1578 &regs.sp[-1])) {
1579 goto error;
1581 } else {
1582 i = -2;
1583 goto do_getprop_with_lval;
1585 END_CASE(JSOP_LENGTH)
1587 BEGIN_CASE(JSOP_CALLPROP)
1589 JSObject *aobj;
1590 JSPropCacheEntry *entry;
1592 lval = FETCH_OPND(-1);
1593 if (!JSVAL_IS_PRIMITIVE(lval)) {
1594 obj = JSVAL_TO_OBJECT(lval);
1595 } else {
1596 if (JSVAL_IS_STRING(lval)) {
1597 i = JSProto_String;
1598 } else if (JSVAL_IS_NUMBER(lval)) {
1599 i = JSProto_Number;
1600 } else if (JSVAL_IS_BOOLEAN(lval)) {
1601 i = JSProto_Boolean;
1602 } else {
1603 JS_ASSERT(JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval));
1604 js_ReportIsNullOrUndefined(cx, -1, lval, NULL);
1605 goto error;
1608 if (!js_GetClassPrototype(cx, NULL, INT_TO_JSID(i), &obj))
1609 goto error;
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);
1615 if (!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);
1623 } else {
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);
1630 PUSH_OPND(lval);
1631 goto end_callprop;
1633 } else {
1634 entry = NULL;
1635 LOAD_ATOM(0);
1639 * Cache miss: use the immediate atom that was loaded for us under
1640 * PROPERTY_CACHE_TEST.
1642 id = ATOM_TO_JSID(atom);
1643 PUSH(JSVAL_NULL);
1644 if (!JSVAL_IS_PRIMITIVE(lval)) {
1645 if (!js_GetMethod(cx, obj, id,
1646 entry
1647 ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
1648 : JSGET_NO_METHOD_BARRIER,
1649 &rval)) {
1650 goto error;
1652 STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
1653 STORE_OPND(-2, rval);
1654 } else {
1655 JS_ASSERT(obj->map->ops->getProperty == js_GetProperty);
1656 if (!js_GetPropertyHelper(cx, obj, id,
1657 JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER,
1658 &rval)) {
1659 goto error;
1661 STORE_OPND(-1, lval);
1662 STORE_OPND(-2, rval);
1665 end_callprop:
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, &regs.sp[-1]))
1674 goto error;
1677 #if JS_HAS_NO_SUCH_METHOD
1678 if (JS_UNLIKELY(JSVAL_IS_VOID(rval))) {
1679 LOAD_ATOM(0);
1680 regs.sp[-2] = ATOM_KEY(atom);
1681 if (!js_OnUnknownMethod(cx, regs.sp - 2))
1682 goto error;
1684 #endif
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);
1697 do {
1698 JSPropCacheEntry *entry;
1700 entry = NULL;
1701 atom = NULL;
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};
1712 * return o;
1715 * or similar real-world cases, which evolve a newborn native
1716 * object predicatably through some bounded number of property
1717 * additions. And second:
1719 * o.p = x;
1721 * in a frequently executed method or loop body, where p will
1722 * (possibly after the first iteration) always exist in native
1723 * object o.
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.
1747 bool checkForAdd;
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);
1765 break;
1767 checkForAdd =
1768 !(sprop->attrs & JSPROP_SHARED) &&
1769 sprop->parent == scope->lastProp &&
1770 !scope->hadMiddleDelete();
1771 } else {
1772 scope = js_GetMutableScope(cx, obj);
1773 if (!scope) {
1774 JS_UNLOCK_OBJ(cx, obj);
1775 goto error;
1777 checkForAdd = !sprop->parent;
1780 if (checkForAdd &&
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) {
1806 ++scope->freeslot;
1807 } else {
1808 if (!js_AllocSlot(cx, obj, &slot)) {
1809 JS_UNLOCK_SCOPE(cx, scope);
1810 goto error;
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,
1828 slot, sprop->attrs,
1829 sprop->flags, sprop->shortid);
1830 if (!sprop2) {
1831 js_FreeSlot(cx, obj, slot);
1832 JS_UNLOCK_SCOPE(cx, scope);
1833 goto error;
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);
1842 sprop = sprop2;
1843 } else {
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
1851 * branded scope.
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);
1863 break;
1865 JS_UNLOCK_SCOPE(cx, scope);
1866 PCMETER(cache->setpcmisses++);
1870 atom = js_FullTestPropertyCache(cx, regs.pc, &obj, &obj2,
1871 &entry);
1872 if (atom) {
1873 PCMETER(cache->misses++);
1874 PCMETER(cache->setmisses++);
1875 } else {
1876 ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
1877 sprop = NULL;
1878 if (obj == obj2) {
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);
1886 if (sprop)
1887 break;
1891 if (!atom)
1892 LOAD_ATOM(0);
1893 id = ATOM_TO_JSID(atom);
1894 if (entry) {
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))
1899 goto error;
1900 } else {
1901 if (!obj->setProperty(cx, id, &rval))
1902 goto error;
1903 ABORT_RECORDING(cx, "Non-native set");
1905 } while (0);
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));
1917 if (!str)
1918 goto error;
1919 rval = STRING_TO_JSVAL(str);
1920 goto end_getelem;
1924 VALUE_TO_OBJECT(cx, -2, lval, obj);
1925 if (JSVAL_IS_INT(rval)) {
1926 if (OBJ_IS_DENSE_ARRAY(cx, obj)) {
1927 jsuint length;
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)
1935 goto end_getelem;
1937 /* Reload rval from the stack in the rare hole case. */
1938 rval = FETCH_OPND(-1);
1941 id = INT_JSVAL_TO_JSID(rval);
1942 } else {
1943 if (!js_InternNonIntElementId(cx, obj, rval, &id))
1944 goto error;
1947 if (!obj->getProperty(cx, id, &rval))
1948 goto error;
1949 end_getelem:
1950 regs.sp--;
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))
1961 goto error;
1962 } else
1963 #endif
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);
1974 do {
1975 if (OBJ_IS_DENSE_ARRAY(cx, obj) && JSID_IS_INT(id)) {
1976 jsuint length;
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))
1983 break;
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;
1989 goto end_setelem;
1992 } while (0);
1993 if (!obj->setProperty(cx, id, &rval))
1994 goto error;
1995 end_setelem:
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))
2004 goto error;
2005 regs.sp -= 3;
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.
2018 lval = *vp;
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),
2026 &vp[1])) {
2027 goto error;
2029 rval = vp[1];
2030 obj2 = js_NewObject(cx, &js_ObjectClass,
2031 JSVAL_IS_OBJECT(rval) ? JSVAL_TO_OBJECT(rval) : NULL,
2032 OBJ_GET_PARENT(cx, obj));
2033 if (!obj2)
2034 goto error;
2036 if (fun->u.i.script->isEmpty()) {
2037 *vp = OBJECT_TO_JSVAL(obj2);
2038 regs.sp = vp + 1;
2039 goto end_new;
2042 vp[1] = OBJECT_TO_JSVAL(obj2);
2043 flags = JSFRAME_CONSTRUCTING;
2044 goto inline_call;
2048 if (!js_InvokeConstructor(cx, argc, JS_FALSE, vp))
2049 goto error;
2050 regs.sp = vp + 1;
2051 CHECK_INTERRUPT_HANDLER();
2052 TRACE_0(NativeCallComplete);
2054 end_new:
2055 END_CASE(JSOP_NEW)
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);
2063 lval = *vp;
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. */
2069 flags = 0;
2070 if (FUN_INTERPRETED(fun))
2071 inline_call:
2073 uintN nframeslots, nvars, missing;
2074 JSArena *a;
2075 jsuword nbytes;
2076 void *newmark;
2077 jsval *newsp;
2078 JSInlineFrame *newifp;
2079 JSInterpreterHook hook;
2081 script = fun->u.i.script;
2082 if (script->isEmpty()) {
2083 script = fp->script;
2084 *vp = JSVAL_VOID;
2085 regs.sp = vp + 1;
2086 goto end_call;
2089 /* Restrict recursion of lightweight functions. */
2090 if (inlineCallCount >= JS_MAX_INLINE_CALL_COUNT) {
2091 js_ReportOverRecursed(cx);
2092 script = fp->script;
2093 goto error;
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) {
2105 missing = 0;
2106 } else {
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;
2113 do {
2114 *--argsp = JSVAL_VOID;
2115 } while (argsp != regs.sp);
2116 missing = 0;
2117 } else {
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;
2126 a->avail += nbytes;
2127 JS_ASSERT(missing == 0);
2128 } else {
2129 JS_ARENA_ALLOCATE_CAST(newsp, jsval *, &cx->stackPool,
2130 nbytes);
2131 if (!newsp) {
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.
2140 if (missing) {
2141 memcpy(newsp, vp, (2 + argc) * sizeof(jsval));
2142 vp = newsp;
2143 newsp = vp + 2 + argc;
2144 do {
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;
2184 while (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;
2204 regs.sp = newsp;
2205 regs.pc = script->code;
2206 newifp->frame.regs = &regs;
2207 cx->fp = fp = &newifp->frame;
2209 /* Call the debugger hook if present. */
2210 hook = cx->debugHooks->callHook;
2211 if (hook) {
2212 newifp->hookData = hook(cx, &newifp->frame, JS_TRUE, 0,
2213 cx->debugHooks->callHookData);
2214 CHECK_INTERRUPT_HANDLER();
2215 } else {
2216 newifp->hookData = NULL;
2219 inlineCallCount++;
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);
2230 #endif
2232 #ifdef JS_TRACER
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);
2241 #endif
2243 /* Load first op and dispatch it (safe since JSOP_STOP). */
2244 op = (JSOp) *regs.pc;
2245 DO_OP();
2247 bad_inline_call:
2248 JS_ASSERT(fp->regs == &regs);
2249 script = fp->script;
2250 atoms = script->atomMap.vector;
2251 js_FreeRawStack(cx, newmark);
2252 goto error;
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);
2266 #endif
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);
2279 #endif
2280 regs.sp = vp + 1;
2281 if (!ok) {
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;
2296 } else {
2297 goto error;
2300 TRACE_0(NativeCallComplete);
2301 goto end_call;
2305 ok = js_Invoke(cx, argc, vp, 0);
2306 regs.sp = vp + 1;
2307 CHECK_INTERRUPT_HANDLER();
2308 if (!ok)
2309 goto error;
2310 JS_RUNTIME_METER(rt, nonInlineCalls);
2311 TRACE_0(NativeCallComplete);
2313 end_call:
2314 END_CASE(JSOP_CALL)
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);
2321 goto error;
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);
2332 if (!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);
2337 goto do_push_rval;
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);
2345 goto do_push_rval;
2348 JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
2349 sprop = PCVAL_TO_SPROP(entry->vword);
2350 goto do_native_get;
2352 } else {
2353 LOAD_ATOM(0);
2356 id = ATOM_TO_JSID(atom);
2357 if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop))
2358 goto error;
2359 if (!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;
2366 DO_NEXT_OP(len);
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))
2375 goto error;
2376 } else {
2377 sprop = (JSScopeProperty *)prop;
2378 do_native_get:
2379 NATIVE_GET(cx, obj, obj2, sprop, JSGET_METHOD_BARRIER, &rval);
2380 obj2->dropProperty(cx, (JSProperty *) sprop);
2383 do_push_rval:
2384 PUSH_OPND(rval);
2385 if (op == JSOP_CALLNAME)
2386 PUSH_OPND(OBJECT_TO_JSVAL(obj));
2388 END_CASE(JSOP_NAME)
2390 BEGIN_CASE(JSOP_UINT16)
2391 i = (jsint) GET_UINT16(regs.pc);
2392 rval = INT_TO_JSVAL(i);
2393 PUSH_OPND(rval);
2394 END_CASE(JSOP_UINT16)
2396 BEGIN_CASE(JSOP_UINT24)
2397 i = (jsint) GET_UINT24(regs.pc);
2398 rval = INT_TO_JSVAL(i);
2399 PUSH_OPND(rval);
2400 END_CASE(JSOP_UINT24)
2402 BEGIN_CASE(JSOP_INT8)
2403 i = GET_INT8(regs.pc);
2404 rval = INT_TO_JSVAL(i);
2405 PUSH_OPND(rval);
2406 END_CASE(JSOP_INT8)
2408 BEGIN_CASE(JSOP_INT32)
2409 i = GET_INT32(regs.pc);
2410 rval = INT_TO_JSVAL(i);
2411 PUSH_OPND(rval);
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);
2436 /* FALL THROUGH */
2438 BEGIN_CASE(JSOP_STRING)
2439 LOAD_ATOM(0);
2440 PUSH_OPND(ATOM_KEY(atom));
2441 END_CASE(JSOP_DOUBLE)
2443 BEGIN_CASE(JSOP_OBJECT)
2444 LOAD_OBJECT(0);
2445 PUSH_OPND(OBJECT_TO_JSVAL(obj));
2446 END_CASE(JSOP_OBJECT)
2448 BEGIN_CASE(JSOP_REGEXP)
2450 JSObject *funobj;
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
2470 * lazily here.
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);
2479 slot = index;
2480 if (fp->fun) {
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))
2492 goto error;
2493 if (JSVAL_IS_VOID(rval))
2494 rval = JSVAL_NULL;
2495 } else {
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];
2506 #ifdef __GNUC__
2507 funobj = NULL; /* suppress bogus gcc warnings */
2508 #endif
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)
2515 obj2 = parent;
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.
2525 * In other words,
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
2539 * fully in ECMA.
2541 obj = script->getRegExp(index);
2542 if (OBJ_GET_PARENT(cx, obj) != obj2) {
2543 obj = js_CloneRegExpObject(cx, obj, obj2);
2544 if (!obj)
2545 goto error;
2547 rval = OBJECT_TO_JSVAL(obj);
2549 /* Store the regexp object value in its cloneIndex slot. */
2550 if (fp->fun) {
2551 if (!JS_SetReservedSlot(cx, funobj, slot, rval))
2552 goto error;
2553 } else {
2554 fp->slots[slot] = rval;
2558 PUSH_OPND(rval);
2560 END_CASE(JSOP_REGEXP)
2562 BEGIN_CASE(JSOP_ZERO)
2563 PUSH_OPND(JSVAL_ZERO);
2564 END_CASE(JSOP_ZERO)
2566 BEGIN_CASE(JSOP_ONE)
2567 PUSH_OPND(JSVAL_ONE);
2568 END_CASE(JSOP_ONE)
2570 BEGIN_CASE(JSOP_NULL)
2571 PUSH_OPND(JSVAL_NULL);
2572 END_CASE(JSOP_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);
2580 END_CASE(JSOP_TRUE)
2582 BEGIN_CASE(JSOP_TABLESWITCH)
2583 pc2 = regs.pc;
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.)
2591 rval = POP_OPND();
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. */
2596 i = 0;
2597 } else {
2598 DO_NEXT_OP(len);
2601 pc2 += JUMP_OFFSET_LEN;
2602 low = GET_JUMP_OFFSET(pc2);
2603 pc2 += JUMP_OFFSET_LEN;
2604 high = GET_JUMP_OFFSET(pc2);
2606 i -= low;
2607 if ((jsuint)i < (jsuint)(high - low + 1)) {
2608 pc2 += JUMP_OFFSET_LEN + JUMP_OFFSET_LEN * i;
2609 off = (jsint) GET_JUMP_OFFSET(pc2);
2610 if (off)
2611 len = off;
2613 END_VARLEN_CASE
2615 BEGIN_CASE(JSOP_TABLESWITCHX)
2616 pc2 = regs.pc;
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.)
2624 rval = POP_OPND();
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. */
2629 i = 0;
2630 } else {
2631 DO_NEXT_OP(len);
2634 pc2 += JUMPX_OFFSET_LEN;
2635 low = GET_JUMP_OFFSET(pc2);
2636 pc2 += JUMP_OFFSET_LEN;
2637 high = GET_JUMP_OFFSET(pc2);
2639 i -= low;
2640 if ((jsuint)i < (jsuint)(high - low + 1)) {
2641 pc2 += JUMP_OFFSET_LEN + JUMPX_OFFSET_LEN * i;
2642 off = (jsint) GET_JUMPX_OFFSET(pc2);
2643 if (off)
2644 len = off;
2646 END_VARLEN_CASE
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;
2655 do_lookup_switch:
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);
2662 pc2 = regs.pc;
2663 lval = POP_OPND();
2665 if (!JSVAL_IS_NUMBER(lval) &&
2666 !JSVAL_IS_STRING(lval) &&
2667 !JSVAL_IS_BOOLEAN(lval)) {
2668 goto end_lookup_switch;
2671 pc2 += off;
2672 npairs = (jsint) GET_UINT16(pc2);
2673 pc2 += UINT16_LEN;
2674 JS_ASSERT(npairs); /* empty switch uses JSOP_TABLESWITCH */
2676 #define SEARCH_PAIRS(MATCH_CODE) \
2677 for (;;) { \
2678 JS_ASSERT(GET_INDEX(pc2) < script->atomMap.length); \
2679 atom = atoms[GET_INDEX(pc2)]; \
2680 rval = ATOM_KEY(atom); \
2681 MATCH_CODE \
2682 pc2 += INDEX_LEN; \
2683 if (match) \
2684 break; \
2685 pc2 += off; \
2686 if (--npairs == 0) { \
2687 pc2 = regs.pc; \
2688 break; \
2692 if (JSVAL_IS_STRING(lval)) {
2693 str = JSVAL_TO_STRING(lval);
2694 SEARCH_PAIRS(
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);
2701 SEARCH_PAIRS(
2702 match = (JSVAL_IS_DOUBLE(rval) &&
2703 *JSVAL_TO_DOUBLE(rval) == d);
2705 } else {
2706 SEARCH_PAIRS(
2707 match = (lval == rval);
2710 #undef SEARCH_PAIRS
2712 end_lookup_switch:
2713 len = (op == JSOP_LOOKUPSWITCH)
2714 ? GET_JUMP_OFFSET(pc2)
2715 : GET_JUMPX_OFFSET(pc2);
2716 END_VARLEN_CASE
2718 BEGIN_CASE(JSOP_TRAP)
2720 JSTrapStatus status;
2722 status = JS_HandleTrap(cx, script, regs.pc, &rval);
2723 switch (status) {
2724 case JSTRAP_ERROR:
2725 goto error;
2726 case JSTRAP_RETURN:
2727 fp->rval = rval;
2728 ok = JS_TRUE;
2729 goto forced_return;
2730 case JSTRAP_THROW:
2731 cx->throwing = JS_TRUE;
2732 cx->exception = rval;
2733 goto error;
2734 default:
2735 break;
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);
2742 DO_OP();
2745 BEGIN_CASE(JSOP_ARGUMENTS)
2746 if (!js_GetArgsValue(cx, fp, &rval))
2747 goto error;
2748 PUSH_OPND(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))
2754 goto error;
2755 PUSH_OPND(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))
2761 goto error;
2762 PUSH_OPND(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]);
2812 PUSH_OPND(rval);
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)
2821 fun = fp->fun;
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);
2829 if (!names)
2830 goto error;
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);
2838 if (!ok)
2839 goto error;
2842 if (!prop)
2843 goto atom_not_defined;
2845 /* Minimize footprint with generic code instead of NATIVE_GET. */
2846 obj2->dropProperty(cx, prop);
2847 vp = regs.sp;
2848 PUSH_OPND(JSVAL_NULL);
2849 if (!obj->getProperty(cx, id, vp))
2850 goto error;
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]);
2860 JS_ASSERT(obj);
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;
2881 DO_OP();
2883 obj = fp->varobj;
2884 slot = JSVAL_TO_INT(lval);
2885 rval = OBJ_GET_SLOT(cx, obj, slot);
2886 PUSH_OPND(rval);
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);
2896 obj = fp->varobj;
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.
2904 #ifdef JS_TRACER
2905 if (TRACE_RECORDER(cx))
2906 js_AbortRecording(cx, "SETGVAR with NULL slot");
2907 #endif
2908 LOAD_ATOM(0);
2909 id = ATOM_TO_JSID(atom);
2910 if (!obj->setProperty(cx, id, &rval))
2911 goto error;
2912 } else {
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);
2918 goto error;
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;
2935 obj = fp->varobj;
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);
2945 prop = NULL;
2946 if (!js_CheckRedeclaration(cx, obj, id, attrs, &obj2, &prop))
2947 goto error;
2949 /* Bind a variable only if it's not yet defined. */
2950 if (!prop) {
2951 if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID, JS_PropertyStub, JS_PropertyStub,
2952 attrs, 0, 0, &prop)) {
2953 goto error;
2955 JS_ASSERT(prop);
2956 obj2 = obj;
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.
2965 if (!fp->fun &&
2966 index < GlobalVarCount(fp) &&
2967 obj2 == obj &&
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
2979 * index.
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;
2991 bool doSet;
2992 JSObject *pobj;
2993 JSProperty *prop;
2994 uint32 old;
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).
3002 LOAD_FUNCTION(0);
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;
3012 } else {
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;
3021 } else {
3022 obj2 = js_GetScopeChain(cx, fp);
3023 if (!obj2)
3024 goto error;
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);
3039 if (!obj)
3040 goto error;
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
3055 * impermanent.
3057 attrs = (fp->flags & JSFRAME_EVAL)
3058 ? JSPROP_ENUMERATE
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);
3068 if (flags) {
3069 /* Function cannot be both getter a setter. */
3070 JS_ASSERT(flags == JSPROP_GETTER || flags == JSPROP_SETTER);
3071 attrs |= flags | JSPROP_SHARED;
3072 rval = JSVAL_VOID;
3073 if (flags == JSPROP_GETTER)
3074 getter = js_CastAsPropertyOp(obj);
3075 else
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;
3085 JS_ASSERT(parent);
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);
3093 prop = NULL;
3094 ok = js_CheckRedeclaration(cx, parent, id, attrs, &pobj, &prop);
3095 if (!ok)
3096 goto restore_scope;
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,
3107 * see bug 467495.
3109 doSet = (attrs == JSPROP_ENUMERATE);
3110 JS_ASSERT_IF(doSet, fp->flags & JSFRAME_EVAL);
3111 if (prop) {
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));
3123 doSet = JS_TRUE;
3125 pobj->dropProperty(cx, prop);
3127 ok = doSet
3128 ? parent->setProperty(cx, id, &rval)
3129 : parent->defineProperty(cx, id, rval, getter, setter, attrs);
3131 restore_scope:
3132 /* Restore fp->scopeChain now that obj is defined in fp->varobj. */
3133 fp->scopeChain = obj2;
3134 if (!ok)
3135 goto error;
3137 END_CASE(JSOP_DEFFUN)
3139 BEGIN_CASE(JSOP_DEFFUN_FC)
3140 BEGIN_CASE(JSOP_DEFFUN_DBGFC)
3141 LOAD_FUNCTION(0);
3143 obj = (op == JSOP_DEFFUN_FC)
3144 ? js_NewFlatClosure(cx, fun)
3145 : js_NewDebuggableFlatClosure(cx, fun);
3146 if (!obj)
3147 goto error;
3148 rval = OBJECT_TO_JSVAL(obj);
3150 attrs = (fp->flags & JSFRAME_EVAL)
3151 ? JSPROP_ENUMERATE
3152 : JSPROP_ENUMERATE | JSPROP_PERMANENT;
3154 flags = JSFUN_GSFLAG2ATTR(fun->flags);
3155 if (flags) {
3156 attrs |= flags | JSPROP_SHARED;
3157 rval = JSVAL_VOID;
3160 parent = fp->varobj;
3161 JS_ASSERT(parent);
3163 id = ATOM_TO_JSID(fun->atom);
3164 ok = js_CheckRedeclaration(cx, parent, id, attrs, NULL, NULL);
3165 if (ok) {
3166 if (attrs == JSPROP_ENUMERATE) {
3167 JS_ASSERT(fp->flags & JSFRAME_EVAL);
3168 ok = parent->setProperty(cx, id, &rval);
3169 } else {
3170 JS_ASSERT(attrs & JSPROP_PERMANENT);
3172 ok = parent->defineProperty(cx, id, rval,
3173 (flags & JSPROP_GETTER)
3174 ? js_CastAsPropertyOp(obj)
3175 : JS_PropertyStub,
3176 (flags & JSPROP_SETTER)
3177 ? js_CastAsPropertyOp(obj)
3178 : JS_PropertyStub,
3179 attrs);
3183 if (!ok)
3184 goto error;
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
3193 * activation.
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);
3202 if (!obj)
3203 goto error;
3204 } else {
3205 parent = js_GetScopeChain(cx, fp);
3206 if (!parent)
3207 goto error;
3209 if (OBJ_GET_PARENT(cx, obj) != parent) {
3210 #ifdef JS_TRACER
3211 if (TRACE_RECORDER(cx))
3212 js_AbortRecording(cx, "DEFLOCALFUN for closure");
3213 #endif
3214 obj = js_CloneFunctionObject(cx, fun, parent);
3215 if (!obj)
3216 goto error;
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);
3230 if (!obj)
3231 goto error;
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);
3243 if (!obj)
3244 goto error;
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. */
3252 LOAD_FUNCTION(0);
3253 obj = FUN_OBJECT(fun);
3255 /* do-while(0) so we can break instead of using a goto. */
3256 do {
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) {
3268 #ifdef DEBUG
3269 op2 = JSOp(regs.pc[JSOP_LAMBDA_LENGTH + JSOP_SETMETHOD_LENGTH]);
3270 JS_ASSERT(op2 == JSOP_POP || op2 == JSOP_POPV);
3271 #endif
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) {
3277 break;
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);
3285 break;
3288 } else {
3289 parent = js_GetScopeChain(cx, fp);
3290 if (!parent)
3291 goto error;
3294 obj = js_CloneFunctionObject(cx, fun, parent);
3295 if (!obj)
3296 goto error;
3297 } while (0);
3299 PUSH_OPND(OBJECT_TO_JSVAL(obj));
3300 END_CASE(JSOP_LAMBDA)
3302 BEGIN_CASE(JSOP_LAMBDA_FC)
3303 LOAD_FUNCTION(0);
3305 obj = js_NewFlatClosure(cx, fun);
3306 if (!obj)
3307 goto error;
3309 PUSH_OPND(OBJECT_TO_JSVAL(obj));
3310 END_CASE(JSOP_LAMBDA_FC)
3312 BEGIN_CASE(JSOP_LAMBDA_DBGFC)
3313 LOAD_FUNCTION(0);
3315 obj = js_NewDebuggableFlatClosure(cx, fun);
3316 if (!obj)
3317 goto error;
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)
3329 do_getter_setter:
3330 op2 = (JSOp) *++regs.pc;
3331 switch (op2) {
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;
3342 case JSOP_SETNAME:
3343 case JSOP_SETPROP:
3344 LOAD_ATOM(0);
3345 id = ATOM_TO_JSID(atom);
3346 rval = FETCH_OPND(-1);
3347 i = -1;
3348 goto gs_pop_lval;
3350 case JSOP_SETELEM:
3351 rval = FETCH_OPND(-1);
3352 id = 0;
3353 i = -2;
3354 gs_pop_lval:
3355 FETCH_OBJECT(cx, i - 1, lval, obj);
3356 break;
3358 case JSOP_INITPROP:
3359 JS_ASSERT(regs.sp - StackBase(fp) >= 2);
3360 rval = FETCH_OPND(-1);
3361 i = -1;
3362 LOAD_ATOM(0);
3363 id = ATOM_TO_JSID(atom);
3364 goto gs_get_lval;
3366 default:
3367 JS_ASSERT(op2 == JSOP_INITELEM);
3369 JS_ASSERT(regs.sp - StackBase(fp) >= 3);
3370 rval = FETCH_OPND(-1);
3371 id = 0;
3372 i = -2;
3373 gs_get_lval:
3374 lval = FETCH_OPND(i-1);
3375 JS_ASSERT(JSVAL_IS_OBJECT(lval));
3376 obj = JSVAL_TO_OBJECT(lval);
3377 break;
3380 /* Ensure that id has a type suitable for use with obj. */
3381 if (id == 0)
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,
3387 (op == JSOP_GETTER)
3388 ? js_getter_str
3389 : js_setter_str);
3390 goto error;
3394 * Getters and setters are just like watchpoints from an access control
3395 * point of view.
3397 if (!obj->checkAccess(cx, id, JSACC_WATCH, &rtmp, &attrs))
3398 goto error;
3400 if (op == JSOP_GETTER) {
3401 getter = js_CastAsPropertyOp(JSVAL_TO_OBJECT(rval));
3402 setter = JS_PropertyStub;
3403 attrs = JSPROP_GETTER;
3404 } else {
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))
3413 goto error;
3415 if (!obj->defineProperty(cx, id, JSVAL_VOID, getter, setter, attrs))
3416 goto error;
3418 regs.sp += i;
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;
3424 DO_NEXT_OP(len);
3425 #endif /* JS_HAS_GETTER_SETTER */
3427 BEGIN_CASE(JSOP_HOLE)
3428 PUSH_OPND(JSVAL_HOLE);
3429 END_CASE(JSOP_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);
3435 if (!obj)
3436 goto error;
3437 regs.sp -= len - 1;
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);
3446 if (!obj)
3447 goto error;
3448 } else {
3449 obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL);
3450 if (!obj)
3451 goto error;
3453 if (regs.pc[JSOP_NEWINIT_LENGTH] != JSOP_ENDINIT) {
3454 JS_LOCK_OBJ(cx, obj);
3455 JSScope *scope = js_GetMutableScope(cx, obj);
3456 if (!scope) {
3457 JS_UNLOCK_OBJ(cx, obj);
3458 goto error;
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));
3489 do {
3490 JSScope *scope;
3491 uint32 kshape;
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
3499 // below.
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
3525 * of business.
3527 if (!SPROP_HAS_STUB_SETTER(sprop))
3528 goto do_initprop_miss;
3530 if (!scope->owned()) {
3531 scope = js_GetMutableScope(cx, obj);
3532 if (!scope) {
3533 JS_UNLOCK_OBJ(cx, obj);
3534 goto error;
3539 * Detect a repeated property name and force a miss to share the
3540 * strict warning code and cope with complexity managed by
3541 * JSScope::add.
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
3549 * prior properties.
3551 JS_ASSERT(!scope->hadMiddleDelete());
3552 JS_ASSERT_IF(scope->table, !scope->has(sprop));
3554 slot = sprop->slot;
3555 JS_ASSERT(slot == scope->freeslot);
3556 if (slot < STOBJ_NSLOTS(obj)) {
3557 ++scope->freeslot;
3558 } else {
3559 if (!js_AllocSlot(cx, obj, &slot)) {
3560 JS_UNLOCK_SCOPE(cx, scope);
3561 goto error;
3563 JS_ASSERT(slot == sprop->slot);
3566 JS_ASSERT(!scope->lastProp ||
3567 scope->shape == scope->lastProp->shape);
3568 if (scope->table) {
3569 JSScopeProperty *sprop2 =
3570 scope->add(cx, sprop->id,
3571 sprop->getter, sprop->setter,
3572 slot, sprop->attrs,
3573 sprop->flags, sprop->shortid);
3574 if (!sprop2) {
3575 js_FreeSlot(cx, obj, slot);
3576 JS_UNLOCK_SCOPE(cx, scope);
3577 goto error;
3579 JS_ASSERT(sprop2 == sprop);
3580 } else {
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);
3593 break;
3596 do_initprop_miss:
3597 PCMETER(cache->inipcmisses++);
3598 JS_UNLOCK_SCOPE(cx, scope);
3600 /* Get the immediate property name into id. */
3601 LOAD_ATOM(0);
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,
3606 NULL, NULL)) {
3607 goto error;
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,
3617 defineHow))) {
3618 goto error;
3620 } while (0);
3622 /* Common tail for property cache hit and miss cases. */
3623 regs.sp--;
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))
3644 goto error;
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))) {
3657 goto error;
3659 } else {
3660 if (!obj->defineProperty(cx, id, rval, NULL, NULL, JSPROP_ENUMERATE))
3661 goto error;
3663 regs.sp -= 2;
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);
3674 } else {
3675 JS_ASSERT(JSVAL_IS_VOID(lval));
3676 obj = js_NewArrayObject(cx, 0, NULL);
3677 if (!obj)
3678 goto error;
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)) {
3685 char numBuf[12];
3686 JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i);
3687 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3688 JSMSG_BAD_SHARP_DEF, numBuf);
3689 goto error;
3691 if (!obj->defineProperty(cx, id, rval, NULL, NULL, JSPROP_ENUMERATE))
3692 goto error;
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)) {
3701 rval = JSVAL_VOID;
3702 } else {
3703 obj = JSVAL_TO_OBJECT(fp->slots[slot]);
3704 id = INT_TO_JSID(i);
3705 if (!obj->getProperty(cx, id, &rval))
3706 goto error;
3708 if (!JSVAL_IS_OBJECT(rval)) {
3709 char numBuf[12];
3711 JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i);
3712 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3713 JSMSG_BAD_SHARP_USE, numBuf);
3714 goto error;
3716 PUSH_OPND(rval);
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];
3723 rval = vp[1];
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;
3733 } else {
3734 JS_ASSERT(JSVAL_IS_INT(rval));
3735 rval -= 2;
3736 if (rval == JSVAL_ZERO)
3737 vp[0] = JSVAL_VOID;
3739 vp[1] = rval;
3740 END_CASE(JSOP_SHARPINIT)
3742 #endif /* JS_HAS_SHARP_VARS */
3744 BEGIN_CASE(JSOP_GOSUB)
3745 PUSH(JSVAL_FALSE);
3746 i = (regs.pc - script->main) + JSOP_GOSUB_LENGTH;
3747 PUSH(INT_TO_JSVAL(i));
3748 len = GET_JUMP_OFFSET(regs.pc);
3749 END_VARLEN_CASE
3751 BEGIN_CASE(JSOP_GOSUBX)
3752 PUSH(JSVAL_FALSE);
3753 i = (regs.pc - script->main) + JSOP_GOSUBX_LENGTH;
3754 len = GET_JUMPX_OFFSET(regs.pc);
3755 PUSH(INT_TO_JSVAL(i));
3756 END_VARLEN_CASE
3758 BEGIN_CASE(JSOP_RETSUB)
3759 /* Pop [exception or hole, retsub pc-index]. */
3760 rval = POP();
3761 lval = POP();
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;
3772 goto error;
3774 JS_ASSERT(JSVAL_IS_INT(rval));
3775 len = JSVAL_TO_INT(rval);
3776 regs.pc = script->main;
3777 END_VARLEN_CASE
3779 BEGIN_CASE(JSOP_EXCEPTION)
3780 JS_ASSERT(cx->throwing);
3781 PUSH(cx->exception);
3782 cx->throwing = JS_FALSE;
3783 CHECK_BRANCH();
3784 END_CASE(JSOP_EXCEPTION)
3786 BEGIN_CASE(JSOP_FINALLY)
3787 CHECK_BRANCH();
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);
3798 CHECK_BRANCH();
3799 cx->throwing = JS_TRUE;
3800 cx->exception = POP_OPND();
3801 /* let the code at error try to catch the exception. */
3802 goto error;
3804 BEGIN_CASE(JSOP_SETLOCALPOP)
3806 * The stack must have a block with at least one local slot below the
3807 * exception object.
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);
3824 BRANCH(len);
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));
3836 goto error;
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);
3844 goto error;
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,
3853 -1, rval, NULL);
3854 goto error;
3856 lval = FETCH_OPND(-2);
3857 cond = JS_FALSE;
3858 if (!obj->map->ops->hasInstance(cx, obj, lval, &cond))
3859 goto error;
3860 regs.sp--;
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;
3868 if (handler) {
3869 switch (handler(cx, script, regs.pc, &rval, cx->debugHooks->debuggerHandlerData)) {
3870 case JSTRAP_ERROR:
3871 goto error;
3872 case JSTRAP_CONTINUE:
3873 break;
3874 case JSTRAP_RETURN:
3875 fp->rval = rval;
3876 ok = JS_TRUE;
3877 goto forced_return;
3878 case JSTRAP_THROW:
3879 cx->throwing = JS_TRUE;
3880 cx->exception = rval;
3881 goto error;
3882 default:;
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)
3892 rval = POP();
3893 if (!js_SetDefaultXMLNamespace(cx, rval))
3894 goto error;
3895 END_CASE(JSOP_DEFXMLNS)
3897 BEGIN_CASE(JSOP_ANYNAME)
3898 if (!js_GetAnyName(cx, &rval))
3899 goto error;
3900 PUSH_OPND(rval);
3901 END_CASE(JSOP_ANYNAME)
3903 BEGIN_CASE(JSOP_QNAMEPART)
3904 LOAD_ATOM(0);
3905 PUSH_OPND(ATOM_KEY(atom));
3906 END_CASE(JSOP_QNAMEPART)
3908 BEGIN_CASE(JSOP_QNAMECONST)
3909 LOAD_ATOM(0);
3910 rval = ATOM_KEY(atom);
3911 lval = FETCH_OPND(-1);
3912 obj = js_ConstructXMLQNameObject(cx, lval, rval);
3913 if (!obj)
3914 goto error;
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);
3922 if (!obj)
3923 goto error;
3924 regs.sp--;
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))
3931 goto error;
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);
3939 if (!str)
3940 goto error;
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);
3951 if (!str)
3952 goto error;
3953 regs.sp--;
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))
3960 goto error;
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))
3970 goto error;
3971 rval = FETCH_OPND(-1);
3972 regs.sp -= 2;
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))
3980 goto error;
3981 if (!obj->getProperty(cx, id, &rval))
3982 goto error;
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))
3993 goto error;
3995 if (op == JSOP_DELDESC) {
3996 regs.sp[-1] = rval; /* set local root */
3997 if (!js_DeleteXMLListElements(cx, JSVAL_TO_OBJECT(rval)))
3998 goto error;
3999 rval = JSVAL_TRUE; /* always succeed */
4002 regs.sp--;
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
4010 * state.
4012 PUSH_OPND(JSVAL_HOLE);
4013 len = GET_JUMP_OFFSET(regs.pc);
4014 JS_ASSERT(len > 0);
4015 END_VARLEN_CASE
4017 BEGIN_CASE(JSOP_ENDFILTER)
4018 cond = (regs.sp[-1] != JSVAL_HOLE);
4019 if (cond) {
4020 /* Exit the "with" block left from the previous iteration. */
4021 js_LeaveWith(cx);
4023 if (!js_StepXMLListFilter(cx, cond))
4024 goto error;
4025 if (regs.sp[-1] != JSVAL_NULL) {
4027 * Decrease sp after EnterWith returns as we use sp[-1] there to root
4028 * temporaries.
4030 JS_ASSERT(VALUE_IS_XML(cx, regs.sp[-1]));
4031 if (!js_EnterWith(cx, -2))
4032 goto error;
4033 regs.sp--;
4034 len = GET_JUMP_OFFSET(regs.pc);
4035 JS_ASSERT(len < 0);
4036 BRANCH(len);
4038 regs.sp--;
4039 END_CASE(JSOP_ENDFILTER);
4041 BEGIN_CASE(JSOP_TOXML)
4042 rval = FETCH_OPND(-1);
4043 obj = js_ValueToXMLObject(cx, rval);
4044 if (!obj)
4045 goto error;
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);
4052 if (!obj)
4053 goto error;
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);
4060 if (!str)
4061 goto error;
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);
4069 } else {
4070 str = js_ValueToString(cx, rval);
4071 if (str)
4072 str = js_EscapeElementValue(cx, str);
4074 if (!str)
4075 goto error;
4076 STORE_OPND(-1, STRING_TO_JSVAL(str));
4077 END_CASE(JSOP_XMLELTEXPR)
4079 BEGIN_CASE(JSOP_XMLOBJECT)
4080 LOAD_OBJECT(0);
4081 obj = js_CloneXMLObject(cx, obj);
4082 if (!obj)
4083 goto error;
4084 PUSH_OPND(OBJECT_TO_JSVAL(obj));
4085 END_CASE(JSOP_XMLOBJECT)
4087 BEGIN_CASE(JSOP_XMLCDATA)
4088 LOAD_ATOM(0);
4089 str = ATOM_TO_STRING(atom);
4090 obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_TEXT, NULL, str);
4091 if (!obj)
4092 goto error;
4093 PUSH_OPND(OBJECT_TO_JSVAL(obj));
4094 END_CASE(JSOP_XMLCDATA)
4096 BEGIN_CASE(JSOP_XMLCOMMENT)
4097 LOAD_ATOM(0);
4098 str = ATOM_TO_STRING(atom);
4099 obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_COMMENT, NULL, str);
4100 if (!obj)
4101 goto error;
4102 PUSH_OPND(OBJECT_TO_JSVAL(obj));
4103 END_CASE(JSOP_XMLCOMMENT)
4105 BEGIN_CASE(JSOP_XMLPI)
4106 LOAD_ATOM(0);
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);
4111 if (!obj)
4112 goto error;
4113 STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
4114 END_CASE(JSOP_XMLPI)
4116 BEGIN_CASE(JSOP_GETFUNNS)
4117 if (!js_GetFunctionNamespace(cx, &rval))
4118 goto error;
4119 PUSH_OPND(rval);
4120 END_CASE(JSOP_GETFUNNS)
4121 #endif /* JS_HAS_XML_SUPPORT */
4123 BEGIN_CASE(JSOP_ENTERBLOCK)
4124 LOAD_OBJECT(0);
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);
4132 regs.sp++;
4135 #ifdef DEBUG
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
4143 * static scope.
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));
4152 parent = obj;
4153 while ((parent = OBJ_GET_PARENT(cx, parent)) != youngestProto)
4154 JS_ASSERT(parent);
4156 #endif
4158 fp->blockChain = obj;
4159 END_CASE(JSOP_ENTERBLOCK)
4161 BEGIN_CASE(JSOP_LEAVEBLOCKEXPR)
4162 BEGIN_CASE(JSOP_LEAVEBLOCK)
4164 #ifdef DEBUG
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));
4169 #endif
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))
4179 goto error;
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);
4192 } else {
4193 JS_ASSERT(StackBase(fp) + blockDepth == regs.sp);
4196 END_CASE(JSOP_LEAVEBLOCK)
4198 BEGIN_CASE(JSOP_CALLBUILTIN)
4199 #ifdef JS_TRACER
4200 obj = js_GetBuiltinFunction(cx, GET_INDEX(regs.pc));
4201 if (!obj)
4202 goto error;
4203 rval = FETCH_OPND(-1);
4204 PUSH_OPND(rval);
4205 STORE_OPND(-2, OBJECT_TO_JSVAL(obj));
4206 #else
4207 goto bad_opcode; /* This is an imacro-only opcode. */
4208 #endif
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);
4216 if (!obj)
4217 goto error;
4218 JS_ASSERT(!fp->callobj && !fp->argsobj);
4219 fp->rval = OBJECT_TO_JSVAL(obj);
4220 ok = JS_TRUE;
4221 if (inlineCallCount != 0)
4222 goto inline_return;
4223 goto exit;
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);
4230 goto error;
4232 fp->rval = FETCH_OPND(-1);
4233 fp->flags |= JSFRAME_YIELDING;
4234 regs.pc += JSOP_YIELD_LENGTH;
4235 ok = JS_TRUE;
4236 goto exit;
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))
4246 goto error;
4247 regs.sp--;
4248 END_CASE(JSOP_ARRAYPUSH)
4249 #endif /* JS_HAS_GENERATORS */
4251 #if JS_THREADED_INTERP
4252 L_JSOP_BACKPATCH:
4253 L_JSOP_BACKPATCH_POP:
4255 # if !JS_HAS_GENERATORS
4256 L_JSOP_GENERATOR:
4257 L_JSOP_YIELD:
4258 L_JSOP_ARRAYPUSH:
4259 # endif
4261 # if !JS_HAS_SHARP_VARS
4262 L_JSOP_DEFSHARP:
4263 L_JSOP_USESHARP:
4264 L_JSOP_SHARPINIT:
4265 # endif
4267 # if !JS_HAS_DESTRUCTURING
4268 L_JSOP_ENUMCONSTELEM:
4269 # endif
4271 # if !JS_HAS_XML_SUPPORT
4272 L_JSOP_CALLXMLNAME:
4273 L_JSOP_STARTXMLEXPR:
4274 L_JSOP_STARTXML:
4275 L_JSOP_DELDESC:
4276 L_JSOP_GETFUNNS:
4277 L_JSOP_XMLPI:
4278 L_JSOP_XMLCOMMENT:
4279 L_JSOP_XMLCDATA:
4280 L_JSOP_XMLOBJECT:
4281 L_JSOP_XMLELTEXPR:
4282 L_JSOP_XMLTAGEXPR:
4283 L_JSOP_TOXMLLIST:
4284 L_JSOP_TOXML:
4285 L_JSOP_ENDFILTER:
4286 L_JSOP_FILTER:
4287 L_JSOP_DESCENDANTS:
4288 L_JSOP_XMLNAME:
4289 L_JSOP_SETXMLNAME:
4290 L_JSOP_BINDXMLNAME:
4291 L_JSOP_ADDATTRVAL:
4292 L_JSOP_ADDATTRNAME:
4293 L_JSOP_TOATTRVAL:
4294 L_JSOP_TOATTRNAME:
4295 L_JSOP_QNAME:
4296 L_JSOP_QNAMECONST:
4297 L_JSOP_QNAMEPART:
4298 L_JSOP_ANYNAME:
4299 L_JSOP_DEFXMLNS:
4300 # endif
4301 #endif /* !JS_THREADED_INTERP */