/[jscoverage]/trunk/js/jsops.cpp
ViewVC logotype

Annotation of /trunk/js/jsops.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 507 - (hide annotations)
Sun Jan 10 07:23:34 2010 UTC (10 years, 7 months ago) by siliconforks
File size: 168151 byte(s)
Update SpiderMonkey from Firefox 3.6rc1.

1 siliconforks 507 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2     * vim: set ts=8 sw=4 et tw=79:
3     *
4     * ***** BEGIN LICENSE BLOCK *****
5     * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6     *
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/
11     *
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.
16     *
17     * The Original Code is Mozilla Communicator client code, released
18     * March 31, 1998.
19     *
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.
24     *
25     * Contributor(s):
26     *
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.
38     *
39     * ***** END LICENSE BLOCK ***** */
40    
41     /* This file needs to be included in possibly multiple places. */
42    
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 */
49     {
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:;
72     }
73     moreInterrupts = true;
74     }
75    
76     #ifdef JS_TRACER
77     TraceRecorder* tr = TRACE_RECORDER(cx);
78     if (tr) {
79     JSRecordingStatus status = TraceRecorder::monitorRecording(cx, tr, op);
80     switch (status) {
81     case JSRS_CONTINUE:
82     moreInterrupts = true;
83     break;
84     case JSRS_IMACRO:
85     atoms = COMMON_ATOMS_START(&rt->atomState);
86     op = JSOp(*regs.pc);
87     DO_OP(); /* keep interrupting for op. */
88     break;
89     case JSRS_ERROR:
90     // The code at 'error:' aborts the recording.
91     goto error;
92     case JSRS_STOP:
93     break;
94     default:
95     JS_NOT_REACHED("Bad recording status");
96     }
97     }
98     #endif /* !JS_TRACER */
99    
100     #if JS_THREADED_INTERP
101     #ifdef MOZ_TRACEVIS
102     if (!moreInterrupts)
103     js_ExitTraceVisState(cx, R_ABORT);
104     #endif
105     jumpTable = moreInterrupts ? interruptJumpTable : normalJumpTable;
106     JS_EXTENSION_(goto *normalJumpTable[op]);
107     #else
108     switchMask = moreInterrupts ? -1 : 0;
109     switchOp = intN(op);
110     goto do_switch;
111     #endif
112     }
113    
114     /* No-ops for ease of decompilation. */
115     ADD_EMPTY_CASE(JSOP_NOP)
116     ADD_EMPTY_CASE(JSOP_CONDSWITCH)
117     ADD_EMPTY_CASE(JSOP_TRY)
118     ADD_EMPTY_CASE(JSOP_TRACE)
119     #if JS_HAS_XML_SUPPORT
120     ADD_EMPTY_CASE(JSOP_STARTXML)
121     ADD_EMPTY_CASE(JSOP_STARTXMLEXPR)
122     #endif
123     END_EMPTY_CASES
124    
125     /* ADD_EMPTY_CASE is not used here as JSOP_LINENO_LENGTH == 3. */
126     BEGIN_CASE(JSOP_LINENO)
127     END_CASE(JSOP_LINENO)
128    
129     BEGIN_CASE(JSOP_PUSH)
130     PUSH_OPND(JSVAL_VOID);
131     END_CASE(JSOP_PUSH)
132    
133     BEGIN_CASE(JSOP_POP)
134     regs.sp--;
135     END_CASE(JSOP_POP)
136    
137     BEGIN_CASE(JSOP_POPN)
138     regs.sp -= GET_UINT16(regs.pc);
139     #ifdef DEBUG
140     JS_ASSERT(StackBase(fp) <= regs.sp);
141     obj = fp->blockChain;
142     JS_ASSERT_IF(obj,
143     OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj)
144     <= (size_t) (regs.sp - StackBase(fp)));
145     for (obj = fp->scopeChain; obj; obj = OBJ_GET_PARENT(cx, obj)) {
146     clasp = OBJ_GET_CLASS(cx, obj);
147     if (clasp != &js_BlockClass && clasp != &js_WithClass)
148     continue;
149     if (obj->getPrivate() != fp)
150     break;
151     JS_ASSERT(StackBase(fp) + OBJ_BLOCK_DEPTH(cx, obj)
152     + ((clasp == &js_BlockClass)
153     ? OBJ_BLOCK_COUNT(cx, obj)
154     : 1)
155     <= regs.sp);
156     }
157     #endif
158     END_CASE(JSOP_POPN)
159    
160     BEGIN_CASE(JSOP_SETRVAL)
161     BEGIN_CASE(JSOP_POPV)
162     ASSERT_NOT_THROWING(cx);
163     fp->rval = POP_OPND();
164     END_CASE(JSOP_POPV)
165    
166     BEGIN_CASE(JSOP_ENTERWITH)
167     if (!js_EnterWith(cx, -1))
168     goto error;
169    
170     /*
171     * We must ensure that different "with" blocks have different
172     * stack depth associated with them. This allows the try handler
173     * search to properly recover the scope chain. Thus we must keep
174     * the stack at least at the current level.
175     *
176     * We set sp[-1] to the current "with" object to help asserting
177     * the enter/leave balance in [leavewith].
178     */
179     regs.sp[-1] = OBJECT_TO_JSVAL(fp->scopeChain);
180     END_CASE(JSOP_ENTERWITH)
181    
182     BEGIN_CASE(JSOP_LEAVEWITH)
183     JS_ASSERT(regs.sp[-1] == OBJECT_TO_JSVAL(fp->scopeChain));
184     regs.sp--;
185     js_LeaveWith(cx);
186     END_CASE(JSOP_LEAVEWITH)
187    
188     BEGIN_CASE(JSOP_RETURN)
189     fp->rval = POP_OPND();
190     /* FALL THROUGH */
191    
192     BEGIN_CASE(JSOP_RETRVAL) /* fp->rval already set */
193     BEGIN_CASE(JSOP_STOP)
194     /*
195     * When the inlined frame exits with an exception or an error, ok
196     * will be false after the inline_return label.
197     */
198     ASSERT_NOT_THROWING(cx);
199     CHECK_BRANCH();
200    
201     if (fp->imacpc) {
202     /*
203     * If we are at the end of an imacro, return to its caller in
204     * the current frame.
205     */
206     JS_ASSERT(op == JSOP_STOP);
207    
208     end_imacro:
209     JS_ASSERT((uintN)(regs.sp - fp->slots) <= script->nslots);
210     regs.pc = fp->imacpc + js_CodeSpec[*fp->imacpc].length;
211     fp->imacpc = NULL;
212     atoms = script->atomMap.vector;
213     op = JSOp(*regs.pc);
214     DO_OP();
215     }
216    
217     JS_ASSERT(regs.sp == StackBase(fp));
218     if ((fp->flags & JSFRAME_CONSTRUCTING) &&
219     JSVAL_IS_PRIMITIVE(fp->rval)) {
220     if (!fp->fun) {
221     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
222     JSMSG_BAD_NEW_RESULT,
223     js_ValueToPrintableString(cx, rval));
224     goto error;
225     }
226     fp->rval = OBJECT_TO_JSVAL(fp->thisp);
227     }
228     ok = JS_TRUE;
229     if (inlineCallCount)
230     inline_return:
231     {
232     JSInlineFrame *ifp = (JSInlineFrame *) fp;
233     void *hookData = ifp->hookData;
234    
235     JS_ASSERT(!fp->blockChain);
236     JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0));
237    
238     if (script->staticLevel < JS_DISPLAY_SIZE)
239     cx->display[script->staticLevel] = fp->displaySave;
240    
241     if (hookData) {
242     JSInterpreterHook hook;
243     JSBool status;
244    
245     hook = cx->debugHooks->callHook;
246     if (hook) {
247     /*
248     * Do not pass &ok directly as exposing the address
249     * inhibits optimizations and uninitialised warnings.
250     */
251     status = ok;
252     hook(cx, fp, JS_FALSE, &status, hookData);
253     ok = status;
254     CHECK_INTERRUPT_HANDLER();
255     }
256     }
257    
258     /*
259     * If fp has a call object, sync values and clear the back-
260     * pointer. This can happen for a lightweight function if it
261     * calls eval unexpectedly (in a way that is hidden from the
262     * compiler). See bug 325540.
263     */
264     fp->putActivationObjects(cx);
265    
266     #ifdef INCLUDE_MOZILLA_DTRACE
267     /* DTrace function return, inlines */
268     if (JAVASCRIPT_FUNCTION_RVAL_ENABLED())
269     jsdtrace_function_rval(cx, fp, fp->fun, &fp->rval);
270     if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
271     jsdtrace_function_return(cx, fp, fp->fun);
272     #endif
273    
274     /* Restore context version only if callee hasn't set version. */
275     if (JS_LIKELY(cx->version == currentVersion)) {
276     currentVersion = ifp->callerVersion;
277     if (currentVersion != cx->version)
278     js_SetVersion(cx, currentVersion);
279     }
280    
281     /*
282     * If inline-constructing, replace primitive rval with the new
283     * object passed in via |this|, and instrument this constructor
284     * invocation
285     */
286     if (fp->flags & JSFRAME_CONSTRUCTING) {
287     if (JSVAL_IS_PRIMITIVE(fp->rval))
288     fp->rval = OBJECT_TO_JSVAL(fp->thisp);
289     JS_RUNTIME_METER(cx->runtime, constructs);
290     }
291    
292     /* Restore caller's registers. */
293     regs = ifp->callerRegs;
294    
295     /* Store the return value in the caller's operand frame. */
296     regs.sp -= 1 + (size_t) ifp->frame.argc;
297     regs.sp[-1] = fp->rval;
298    
299     /* Restore cx->fp and release the inline frame's space. */
300     cx->fp = fp = fp->down;
301     JS_ASSERT(fp->regs == &ifp->callerRegs);
302     fp->regs = &regs;
303     JS_ARENA_RELEASE(&cx->stackPool, ifp->mark);
304    
305     /* Restore the calling script's interpreter registers. */
306     script = fp->script;
307     atoms = FrameAtomBase(cx, fp);
308    
309     /* Resume execution in the calling frame. */
310     inlineCallCount--;
311     if (JS_LIKELY(ok)) {
312     TRACE_0(LeaveFrame);
313     JS_ASSERT(js_CodeSpec[js_GetOpcode(cx, script, regs.pc)].length
314     == JSOP_CALL_LENGTH);
315     len = JSOP_CALL_LENGTH;
316     DO_NEXT_OP(len);
317     }
318     goto error;
319     }
320     goto exit;
321    
322     BEGIN_CASE(JSOP_DEFAULT)
323     (void) POP();
324     /* FALL THROUGH */
325     BEGIN_CASE(JSOP_GOTO)
326     len = GET_JUMP_OFFSET(regs.pc);
327     BRANCH(len);
328     END_CASE(JSOP_GOTO)
329    
330     BEGIN_CASE(JSOP_IFEQ)
331     POP_BOOLEAN(cx, rval, cond);
332     if (cond == JS_FALSE) {
333     len = GET_JUMP_OFFSET(regs.pc);
334     BRANCH(len);
335     }
336     END_CASE(JSOP_IFEQ)
337    
338     BEGIN_CASE(JSOP_IFNE)
339     POP_BOOLEAN(cx, rval, cond);
340     if (cond != JS_FALSE) {
341     len = GET_JUMP_OFFSET(regs.pc);
342     BRANCH(len);
343     }
344     END_CASE(JSOP_IFNE)
345    
346     BEGIN_CASE(JSOP_OR)
347     POP_BOOLEAN(cx, rval, cond);
348     if (cond == JS_TRUE) {
349     len = GET_JUMP_OFFSET(regs.pc);
350     PUSH_OPND(rval);
351     DO_NEXT_OP(len);
352     }
353     END_CASE(JSOP_OR)
354    
355     BEGIN_CASE(JSOP_AND)
356     POP_BOOLEAN(cx, rval, cond);
357     if (cond == JS_FALSE) {
358     len = GET_JUMP_OFFSET(regs.pc);
359     PUSH_OPND(rval);
360     DO_NEXT_OP(len);
361     }
362     END_CASE(JSOP_AND)
363    
364     BEGIN_CASE(JSOP_DEFAULTX)
365     (void) POP();
366     /* FALL THROUGH */
367     BEGIN_CASE(JSOP_GOTOX)
368     len = GET_JUMPX_OFFSET(regs.pc);
369     BRANCH(len);
370     END_CASE(JSOP_GOTOX);
371    
372     BEGIN_CASE(JSOP_IFEQX)
373     POP_BOOLEAN(cx, rval, cond);
374     if (cond == JS_FALSE) {
375     len = GET_JUMPX_OFFSET(regs.pc);
376     BRANCH(len);
377     }
378     END_CASE(JSOP_IFEQX)
379    
380     BEGIN_CASE(JSOP_IFNEX)
381     POP_BOOLEAN(cx, rval, cond);
382     if (cond != JS_FALSE) {
383     len = GET_JUMPX_OFFSET(regs.pc);
384     BRANCH(len);
385     }
386     END_CASE(JSOP_IFNEX)
387    
388     BEGIN_CASE(JSOP_ORX)
389     POP_BOOLEAN(cx, rval, cond);
390     if (cond == JS_TRUE) {
391     len = GET_JUMPX_OFFSET(regs.pc);
392     PUSH_OPND(rval);
393     DO_NEXT_OP(len);
394     }
395     END_CASE(JSOP_ORX)
396    
397     BEGIN_CASE(JSOP_ANDX)
398     POP_BOOLEAN(cx, rval, cond);
399     if (cond == JS_FALSE) {
400     len = GET_JUMPX_OFFSET(regs.pc);
401     PUSH_OPND(rval);
402     DO_NEXT_OP(len);
403     }
404     END_CASE(JSOP_ANDX)
405    
406     /*
407     * If the index value at sp[n] is not an int that fits in a jsval, it could
408     * be an object (an XML QName, AttributeName, or AnyName), but only if we are
409     * compiling with JS_HAS_XML_SUPPORT. Otherwise convert the index value to a
410     * string atom id.
411     */
412     #define FETCH_ELEMENT_ID(obj, n, id) \
413     JS_BEGIN_MACRO \
414     jsval idval_ = FETCH_OPND(n); \
415     if (JSVAL_IS_INT(idval_)) { \
416     id = INT_JSVAL_TO_JSID(idval_); \
417     } else { \
418     if (!js_InternNonIntElementId(cx, obj, idval_, &id)) \
419     goto error; \
420     regs.sp[n] = ID_TO_VALUE(id); \
421     } \
422     JS_END_MACRO
423    
424     #define TRY_BRANCH_AFTER_COND(cond,spdec) \
425     JS_BEGIN_MACRO \
426     uintN diff_; \
427     JS_ASSERT(js_CodeSpec[op].length == 1); \
428     diff_ = (uintN) regs.pc[1] - (uintN) JSOP_IFEQ; \
429     if (diff_ <= 1) { \
430     regs.sp -= spdec; \
431     if (cond == (diff_ != 0)) { \
432     ++regs.pc; \
433     len = GET_JUMP_OFFSET(regs.pc); \
434     BRANCH(len); \
435     } \
436     len = 1 + JSOP_IFEQ_LENGTH; \
437     DO_NEXT_OP(len); \
438     } \
439     JS_END_MACRO
440    
441     BEGIN_CASE(JSOP_IN)
442     rval = FETCH_OPND(-1);
443     if (JSVAL_IS_PRIMITIVE(rval)) {
444     js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rval, NULL);
445     goto error;
446     }
447     obj = JSVAL_TO_OBJECT(rval);
448     FETCH_ELEMENT_ID(obj, -2, id);
449     if (!obj->lookupProperty(cx, id, &obj2, &prop))
450     goto error;
451     cond = prop != NULL;
452     if (prop)
453     obj2->dropProperty(cx, prop);
454     TRY_BRANCH_AFTER_COND(cond, 2);
455     regs.sp--;
456     STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));
457     END_CASE(JSOP_IN)
458    
459     BEGIN_CASE(JSOP_ITER)
460     JS_ASSERT(regs.sp > StackBase(fp));
461     flags = regs.pc[1];
462     if (!js_ValueToIterator(cx, flags, &regs.sp[-1]))
463     goto error;
464     CHECK_INTERRUPT_HANDLER();
465     JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-1]));
466     PUSH(JSVAL_VOID);
467     END_CASE(JSOP_ITER)
468    
469     BEGIN_CASE(JSOP_NEXTITER)
470     JS_ASSERT(regs.sp - 2 >= StackBase(fp));
471     JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-2]));
472     if (!js_CallIteratorNext(cx, JSVAL_TO_OBJECT(regs.sp[-2]), &regs.sp[-1]))
473     goto error;
474     CHECK_INTERRUPT_HANDLER();
475     rval = BOOLEAN_TO_JSVAL(regs.sp[-1] != JSVAL_HOLE);
476     PUSH(rval);
477     END_CASE(JSOP_NEXTITER)
478    
479     BEGIN_CASE(JSOP_ENDITER)
480     /*
481     * Decrease the stack pointer even when !ok -- see comments in the
482     * exception capturing code for details.
483     */
484     JS_ASSERT(regs.sp - 2 >= StackBase(fp));
485     ok = js_CloseIterator(cx, regs.sp[-2]);
486     regs.sp -= 2;
487     if (!ok)
488     goto error;
489     END_CASE(JSOP_ENDITER)
490    
491     BEGIN_CASE(JSOP_FORARG)
492     JS_ASSERT(regs.sp - 2 >= StackBase(fp));
493     slot = GET_ARGNO(regs.pc);
494     JS_ASSERT(slot < fp->fun->nargs);
495     fp->argv[slot] = regs.sp[-1];
496     END_CASE(JSOP_FORARG)
497    
498     BEGIN_CASE(JSOP_FORLOCAL)
499     JS_ASSERT(regs.sp - 2 >= StackBase(fp));
500     slot = GET_SLOTNO(regs.pc);
501     JS_ASSERT(slot < fp->script->nslots);
502     fp->slots[slot] = regs.sp[-1];
503     END_CASE(JSOP_FORLOCAL)
504    
505     BEGIN_CASE(JSOP_FORNAME)
506     JS_ASSERT(regs.sp - 2 >= StackBase(fp));
507     LOAD_ATOM(0);
508     id = ATOM_TO_JSID(atom);
509     if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
510     goto error;
511     if (prop)
512     obj2->dropProperty(cx, prop);
513     ok = obj->setProperty(cx, id, &regs.sp[-1]);
514     if (!ok)
515     goto error;
516     END_CASE(JSOP_FORNAME)
517    
518     BEGIN_CASE(JSOP_FORPROP)
519     JS_ASSERT(regs.sp - 2 >= StackBase(fp));
520     LOAD_ATOM(0);
521     id = ATOM_TO_JSID(atom);
522     FETCH_OBJECT(cx, -1, lval, obj);
523     ok = obj->setProperty(cx, id, &regs.sp[-2]);
524     if (!ok)
525     goto error;
526     regs.sp--;
527     END_CASE(JSOP_FORPROP)
528    
529     BEGIN_CASE(JSOP_FORELEM)
530     /*
531     * JSOP_FORELEM simply dups the property identifier at top of stack
532     * and lets the subsequent JSOP_ENUMELEM opcode sequence handle the
533     * left-hand side expression evaluation and assignment. This opcode
534     * exists solely to help the decompiler.
535     */
536     JS_ASSERT(regs.sp - 2 >= StackBase(fp));
537     rval = FETCH_OPND(-1);
538     PUSH(rval);
539     END_CASE(JSOP_FORELEM)
540    
541     BEGIN_CASE(JSOP_DUP)
542     JS_ASSERT(regs.sp > StackBase(fp));
543     rval = FETCH_OPND(-1);
544     PUSH(rval);
545     END_CASE(JSOP_DUP)
546    
547     BEGIN_CASE(JSOP_DUP2)
548     JS_ASSERT(regs.sp - 2 >= StackBase(fp));
549     lval = FETCH_OPND(-2);
550     rval = FETCH_OPND(-1);
551     PUSH(lval);
552     PUSH(rval);
553     END_CASE(JSOP_DUP2)
554    
555     BEGIN_CASE(JSOP_SWAP)
556     JS_ASSERT(regs.sp - 2 >= StackBase(fp));
557     lval = FETCH_OPND(-2);
558     rval = FETCH_OPND(-1);
559     STORE_OPND(-1, lval);
560     STORE_OPND(-2, rval);
561     END_CASE(JSOP_SWAP)
562    
563     BEGIN_CASE(JSOP_PICK)
564     i = regs.pc[1];
565     JS_ASSERT(regs.sp - (i+1) >= StackBase(fp));
566     lval = regs.sp[-(i+1)];
567     memmove(regs.sp - (i+1), regs.sp - i, sizeof(jsval)*i);
568     regs.sp[-1] = lval;
569     END_CASE(JSOP_PICK)
570    
571     #define PROPERTY_OP(n, call) \
572     JS_BEGIN_MACRO \
573     /* Fetch the left part and resolve it to a non-null object. */ \
574     FETCH_OBJECT(cx, n, lval, obj); \
575     \
576     /* Get or set the property. */ \
577     if (!call) \
578     goto error; \
579     JS_END_MACRO
580    
581     #define ELEMENT_OP(n, call) \
582     JS_BEGIN_MACRO \
583     /* Fetch the left part and resolve it to a non-null object. */ \
584     FETCH_OBJECT(cx, n - 1, lval, obj); \
585     \
586     /* Fetch index and convert it to id suitable for use with obj. */ \
587     FETCH_ELEMENT_ID(obj, n, id); \
588     \
589     /* Get or set the element. */ \
590     if (!call) \
591     goto error; \
592     JS_END_MACRO
593    
594     #define NATIVE_GET(cx,obj,pobj,sprop,vp) \
595     JS_BEGIN_MACRO \
596     if (SPROP_HAS_STUB_GETTER(sprop)) { \
597     /* Fast path for Object instance properties. */ \
598     JS_ASSERT((sprop)->slot != SPROP_INVALID_SLOT || \
599     !SPROP_HAS_STUB_SETTER(sprop)); \
600     *vp = ((sprop)->slot != SPROP_INVALID_SLOT) \
601     ? LOCKED_OBJ_GET_SLOT(pobj, (sprop)->slot) \
602     : JSVAL_VOID; \
603     } else { \
604     if (!js_NativeGet(cx, obj, pobj, sprop, vp)) \
605     goto error; \
606     } \
607     JS_END_MACRO
608    
609     #define NATIVE_SET(cx,obj,sprop,entry,vp) \
610     JS_BEGIN_MACRO \
611     TRACE_2(SetPropHit, entry, sprop); \
612     if (SPROP_HAS_STUB_SETTER(sprop) && \
613     (sprop)->slot != SPROP_INVALID_SLOT) { \
614     /* Fast path for, e.g., Object instance properties. */ \
615     LOCKED_OBJ_WRITE_SLOT(cx, obj, (sprop)->slot, *vp); \
616     } else { \
617     if (!js_NativeSet(cx, obj, sprop, vp)) \
618     goto error; \
619     } \
620     JS_END_MACRO
621    
622     /*
623     * Skip the JSOP_POP typically found after a JSOP_SET* opcode, where oplen is
624     * the constant length of the SET opcode sequence, and spdec is the constant
625     * by which to decrease the stack pointer to pop all of the SET op's operands.
626     *
627     * NB: unlike macros that could conceivably be replaced by functions (ignoring
628     * goto error), where a call should not have to be braced in order to expand
629     * correctly (e.g., in if (cond) FOO(); else BAR()), these three macros lack
630     * JS_{BEGIN,END}_MACRO brackets. They are also indented so as to align with
631     * nearby opcode code.
632     */
633     #define SKIP_POP_AFTER_SET(oplen,spdec) \
634     if (regs.pc[oplen] == JSOP_POP) { \
635     regs.sp -= spdec; \
636     regs.pc += oplen + JSOP_POP_LENGTH; \
637     op = (JSOp) *regs.pc; \
638     DO_OP(); \
639     }
640    
641     #define END_SET_CASE(OP) \
642     SKIP_POP_AFTER_SET(OP##_LENGTH, 1); \
643     END_CASE(OP)
644    
645     #define END_SET_CASE_STORE_RVAL(OP,spdec) \
646     SKIP_POP_AFTER_SET(OP##_LENGTH, spdec); \
647     rval = FETCH_OPND(-1); \
648     regs.sp -= (spdec) - 1; \
649     STORE_OPND(-1, rval); \
650     END_CASE(OP)
651    
652     BEGIN_CASE(JSOP_SETCONST)
653     LOAD_ATOM(0);
654     obj = fp->varobj;
655     rval = FETCH_OPND(-1);
656     if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), rval,
657     JS_PropertyStub, JS_PropertyStub,
658     JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
659     goto error;
660     }
661     END_SET_CASE(JSOP_SETCONST);
662    
663     #if JS_HAS_DESTRUCTURING
664     BEGIN_CASE(JSOP_ENUMCONSTELEM)
665     rval = FETCH_OPND(-3);
666     FETCH_OBJECT(cx, -2, lval, obj);
667     FETCH_ELEMENT_ID(obj, -1, id);
668     if (!obj->defineProperty(cx, id, rval,
669     JS_PropertyStub, JS_PropertyStub,
670     JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
671     goto error;
672     }
673     regs.sp -= 3;
674     END_CASE(JSOP_ENUMCONSTELEM)
675     #endif
676    
677     BEGIN_CASE(JSOP_BINDNAME)
678     do {
679     JSPropCacheEntry *entry;
680    
681     /*
682     * We can skip the property lookup for the global object. If
683     * the property does not exist anywhere on the scope chain,
684     * JSOP_SETNAME adds the property to the global.
685     *
686     * As a consequence of this optimization for the global object
687     * we run its JSRESOLVE_ASSIGNING-tolerant resolve hooks only
688     * in JSOP_SETNAME, after the interpreter evaluates the right-
689     * hand-side of the assignment, and not here.
690     *
691     * This should be transparent to the hooks because the script,
692     * instead of name = rhs, could have used global.name = rhs
693     * given a global object reference, which also calls the hooks
694     * only after evaluating the rhs. We desire such resolve hook
695     * equivalence between the two forms.
696     */
697     obj = fp->scopeChain;
698     if (!OBJ_GET_PARENT(cx, obj))
699     break;
700     if (JS_LIKELY(OBJ_IS_NATIVE(obj))) {
701     PROPERTY_CACHE_TEST(cx, regs.pc, obj, obj2, entry, atom);
702     if (!atom) {
703     ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
704     JS_UNLOCK_OBJ(cx, obj2);
705     break;
706     }
707     } else {
708     entry = NULL;
709     LOAD_ATOM(0);
710     }
711     id = ATOM_TO_JSID(atom);
712     obj = js_FindIdentifierBase(cx, fp->scopeChain, id);
713     if (!obj)
714     goto error;
715     } while (0);
716     PUSH_OPND(OBJECT_TO_JSVAL(obj));
717     END_CASE(JSOP_BINDNAME)
718    
719     BEGIN_CASE(JSOP_IMACOP)
720     JS_ASSERT(JS_UPTRDIFF(fp->imacpc, script->code) < script->length);
721     op = JSOp(*fp->imacpc);
722     DO_OP();
723    
724     #define BITWISE_OP(OP) \
725     JS_BEGIN_MACRO \
726     FETCH_INT(cx, -2, i); \
727     FETCH_INT(cx, -1, j); \
728     i = i OP j; \
729     regs.sp--; \
730     STORE_INT(cx, -1, i); \
731     JS_END_MACRO
732    
733     BEGIN_CASE(JSOP_BITOR)
734     BITWISE_OP(|);
735     END_CASE(JSOP_BITOR)
736    
737     BEGIN_CASE(JSOP_BITXOR)
738     BITWISE_OP(^);
739     END_CASE(JSOP_BITXOR)
740    
741     BEGIN_CASE(JSOP_BITAND)
742     BITWISE_OP(&);
743     END_CASE(JSOP_BITAND)
744    
745     #define RELATIONAL_OP(OP) \
746     JS_BEGIN_MACRO \
747     rval = FETCH_OPND(-1); \
748     lval = FETCH_OPND(-2); \
749     /* Optimize for two int-tagged operands (typical loop control). */ \
750     if ((lval & rval) & JSVAL_INT) { \
751     cond = JSVAL_TO_INT(lval) OP JSVAL_TO_INT(rval); \
752     } else { \
753     if (!JSVAL_IS_PRIMITIVE(lval)) \
754     DEFAULT_VALUE(cx, -2, JSTYPE_NUMBER, lval); \
755     if (!JSVAL_IS_PRIMITIVE(rval)) \
756     DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \
757     if (JSVAL_IS_STRING(lval) && JSVAL_IS_STRING(rval)) { \
758     str = JSVAL_TO_STRING(lval); \
759     str2 = JSVAL_TO_STRING(rval); \
760     cond = js_CompareStrings(str, str2) OP 0; \
761     } else { \
762     VALUE_TO_NUMBER(cx, -2, lval, d); \
763     VALUE_TO_NUMBER(cx, -1, rval, d2); \
764     cond = JSDOUBLE_COMPARE(d, OP, d2, JS_FALSE); \
765     } \
766     } \
767     TRY_BRANCH_AFTER_COND(cond, 2); \
768     regs.sp--; \
769     STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
770     JS_END_MACRO
771    
772     /*
773     * NB: These macros can't use JS_BEGIN_MACRO/JS_END_MACRO around their bodies
774     * because they begin if/else chains, so callers must not put semicolons after
775     * the call expressions!
776     */
777     #if JS_HAS_XML_SUPPORT
778     #define XML_EQUALITY_OP(OP) \
779     if ((ltmp == JSVAL_OBJECT && \
780     (obj2 = JSVAL_TO_OBJECT(lval)) && \
781     OBJECT_IS_XML(cx, obj2)) || \
782     (rtmp == JSVAL_OBJECT && \
783     (obj2 = JSVAL_TO_OBJECT(rval)) && \
784     OBJECT_IS_XML(cx, obj2))) { \
785     if (JSVAL_IS_OBJECT(rval) && obj2 == JSVAL_TO_OBJECT(rval)) \
786     rval = lval; \
787     if (!js_TestXMLEquality(cx, obj2, rval, &cond)) \
788     goto error; \
789     cond = cond OP JS_TRUE; \
790     } else
791    
792     #define EXTENDED_EQUALITY_OP(OP) \
793     if (ltmp == JSVAL_OBJECT && \
794     (obj2 = JSVAL_TO_OBJECT(lval)) && \
795     ((clasp = OBJ_GET_CLASS(cx, obj2))->flags & JSCLASS_IS_EXTENDED)) { \
796     JSExtendedClass *xclasp; \
797     \
798     xclasp = (JSExtendedClass *) clasp; \
799     if (!xclasp->equality(cx, obj2, rval, &cond)) \
800     goto error; \
801     cond = cond OP JS_TRUE; \
802     } else
803     #else
804     #define XML_EQUALITY_OP(OP) /* nothing */
805     #define EXTENDED_EQUALITY_OP(OP) /* nothing */
806     #endif
807    
808     #define EQUALITY_OP(OP, IFNAN) \
809     JS_BEGIN_MACRO \
810     rval = FETCH_OPND(-1); \
811     lval = FETCH_OPND(-2); \
812     ltmp = JSVAL_TAG(lval); \
813     rtmp = JSVAL_TAG(rval); \
814     XML_EQUALITY_OP(OP) \
815     if (ltmp == rtmp) { \
816     if (ltmp == JSVAL_STRING) { \
817     str = JSVAL_TO_STRING(lval); \
818     str2 = JSVAL_TO_STRING(rval); \
819     cond = js_EqualStrings(str, str2) OP JS_TRUE; \
820     } else if (ltmp == JSVAL_DOUBLE) { \
821     d = *JSVAL_TO_DOUBLE(lval); \
822     d2 = *JSVAL_TO_DOUBLE(rval); \
823     cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN); \
824     } else { \
825     EXTENDED_EQUALITY_OP(OP) \
826     /* Handle all undefined (=>NaN) and int combinations. */ \
827     cond = lval OP rval; \
828     } \
829     } else { \
830     if (JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval)) { \
831     cond = (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) OP 1; \
832     } else if (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) { \
833     cond = 1 OP 0; \
834     } else { \
835     if (ltmp == JSVAL_OBJECT) { \
836     DEFAULT_VALUE(cx, -2, JSTYPE_VOID, lval); \
837     ltmp = JSVAL_TAG(lval); \
838     } else if (rtmp == JSVAL_OBJECT) { \
839     DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval); \
840     rtmp = JSVAL_TAG(rval); \
841     } \
842     if (ltmp == JSVAL_STRING && rtmp == JSVAL_STRING) { \
843     str = JSVAL_TO_STRING(lval); \
844     str2 = JSVAL_TO_STRING(rval); \
845     cond = js_EqualStrings(str, str2) OP JS_TRUE; \
846     } else { \
847     VALUE_TO_NUMBER(cx, -2, lval, d); \
848     VALUE_TO_NUMBER(cx, -1, rval, d2); \
849     cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN); \
850     } \
851     } \
852     } \
853     TRY_BRANCH_AFTER_COND(cond, 2); \
854     regs.sp--; \
855     STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
856     JS_END_MACRO
857    
858     BEGIN_CASE(JSOP_EQ)
859     EQUALITY_OP(==, JS_FALSE);
860     END_CASE(JSOP_EQ)
861    
862     BEGIN_CASE(JSOP_NE)
863     EQUALITY_OP(!=, JS_TRUE);
864     END_CASE(JSOP_NE)
865    
866     #define STRICT_EQUALITY_OP(OP) \
867     JS_BEGIN_MACRO \
868     rval = FETCH_OPND(-1); \
869     lval = FETCH_OPND(-2); \
870     cond = js_StrictlyEqual(cx, lval, rval) OP JS_TRUE; \
871     regs.sp--; \
872     STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
873     JS_END_MACRO
874    
875     BEGIN_CASE(JSOP_STRICTEQ)
876     STRICT_EQUALITY_OP(==);
877     END_CASE(JSOP_STRICTEQ)
878    
879     BEGIN_CASE(JSOP_STRICTNE)
880     STRICT_EQUALITY_OP(!=);
881     END_CASE(JSOP_STRICTNE)
882    
883     BEGIN_CASE(JSOP_CASE)
884     STRICT_EQUALITY_OP(==);
885     (void) POP();
886     if (cond) {
887     len = GET_JUMP_OFFSET(regs.pc);
888     BRANCH(len);
889     }
890     PUSH(lval);
891     END_CASE(JSOP_CASE)
892    
893     BEGIN_CASE(JSOP_CASEX)
894     STRICT_EQUALITY_OP(==);
895     (void) POP();
896     if (cond) {
897     len = GET_JUMPX_OFFSET(regs.pc);
898     BRANCH(len);
899     }
900     PUSH(lval);
901     END_CASE(JSOP_CASEX)
902    
903     BEGIN_CASE(JSOP_LT)
904     RELATIONAL_OP(<);
905     END_CASE(JSOP_LT)
906    
907     BEGIN_CASE(JSOP_LE)
908     RELATIONAL_OP(<=);
909     END_CASE(JSOP_LE)
910    
911     BEGIN_CASE(JSOP_GT)
912     RELATIONAL_OP(>);
913     END_CASE(JSOP_GT)
914    
915     BEGIN_CASE(JSOP_GE)
916     RELATIONAL_OP(>=);
917     END_CASE(JSOP_GE)
918    
919     #undef EQUALITY_OP
920     #undef RELATIONAL_OP
921    
922     #define SIGNED_SHIFT_OP(OP) \
923     JS_BEGIN_MACRO \
924     FETCH_INT(cx, -2, i); \
925     FETCH_INT(cx, -1, j); \
926     i = i OP (j & 31); \
927     regs.sp--; \
928     STORE_INT(cx, -1, i); \
929     JS_END_MACRO
930    
931     BEGIN_CASE(JSOP_LSH)
932     SIGNED_SHIFT_OP(<<);
933     END_CASE(JSOP_LSH)
934    
935     BEGIN_CASE(JSOP_RSH)
936     SIGNED_SHIFT_OP(>>);
937     END_CASE(JSOP_RSH)
938    
939     BEGIN_CASE(JSOP_URSH)
940     {
941     uint32 u;
942    
943     FETCH_UINT(cx, -2, u);
944     FETCH_INT(cx, -1, j);
945     u >>= (j & 31);
946     regs.sp--;
947     STORE_UINT(cx, -1, u);
948     }
949     END_CASE(JSOP_URSH)
950    
951     #undef BITWISE_OP
952     #undef SIGNED_SHIFT_OP
953    
954     BEGIN_CASE(JSOP_ADD)
955     rval = FETCH_OPND(-1);
956     lval = FETCH_OPND(-2);
957     #if JS_HAS_XML_SUPPORT
958     if (!JSVAL_IS_PRIMITIVE(lval) &&
959     (obj2 = JSVAL_TO_OBJECT(lval), OBJECT_IS_XML(cx, obj2)) &&
960     VALUE_IS_XML(cx, rval)) {
961     if (!js_ConcatenateXML(cx, obj2, rval, &rval))
962     goto error;
963     regs.sp--;
964     STORE_OPND(-1, rval);
965     } else
966     #endif
967     {
968     if (!JSVAL_IS_PRIMITIVE(lval))
969     DEFAULT_VALUE(cx, -2, JSTYPE_VOID, lval);
970     if (!JSVAL_IS_PRIMITIVE(rval))
971     DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval);
972     if ((cond = JSVAL_IS_STRING(lval)) || JSVAL_IS_STRING(rval)) {
973     if (cond) {
974     str = JSVAL_TO_STRING(lval);
975     str2 = js_ValueToString(cx, rval);
976     if (!str2)
977     goto error;
978     regs.sp[-1] = STRING_TO_JSVAL(str2);
979     } else {
980     str2 = JSVAL_TO_STRING(rval);
981     str = js_ValueToString(cx, lval);
982     if (!str)
983     goto error;
984     regs.sp[-2] = STRING_TO_JSVAL(str);
985     }
986     str = js_ConcatStrings(cx, str, str2);
987     if (!str)
988     goto error;
989     regs.sp--;
990     STORE_OPND(-1, STRING_TO_JSVAL(str));
991     } else {
992     VALUE_TO_NUMBER(cx, -2, lval, d);
993     VALUE_TO_NUMBER(cx, -1, rval, d2);
994     d += d2;
995     regs.sp--;
996     STORE_NUMBER(cx, -1, d);
997     }
998     }
999     END_CASE(JSOP_ADD)
1000    
1001     BEGIN_CASE(JSOP_CONCATN)
1002     {
1003     #ifdef JS_TRACER
1004     JS_ASSERT_IF(fp->imacpc,
1005     *fp->imacpc == JSOP_CONCATN && *regs.pc == JSOP_IMACOP);
1006    
1007     /*
1008     * This instruction can be executed in three contexts. (1) is normal
1009     * execution. (2) is while recording, during an imacro 'imacop'.
1010     * (3) is during a failed recording or when trace execution aborts
1011     * during a recorded imacro.
1012     * 1. !imacro : N args on stack, pc is regs.pc
1013     * 2. imacro && recording : N args on stack, pc is fp->imacpc
1014     * 3. imacro && !recording : N+2 args on stack, pc is fp->imacpc
1015     */
1016     bool imacro = fp->imacpc != NULL;
1017     bool recording = TRACE_RECORDER(cx) != NULL;
1018     if (imacro) {
1019     argc = GET_ARGC(fp->imacpc);
1020     if (!recording)
1021     js_ConcatPostImacroStackCleanup(argc, regs, NULL);
1022     } else {
1023     #endif /* JS_TRACER */
1024     argc = GET_ARGC(regs.pc);
1025     #ifdef JS_TRACER
1026     }
1027     #endif /* JS_TRACER */
1028    
1029     JSCharBuffer buf(cx);
1030     for (vp = regs.sp - argc; vp < regs.sp; vp++) {
1031     if ((!JSVAL_IS_PRIMITIVE(*vp) &&
1032     !JSVAL_TO_OBJECT(*vp)->defaultValue(cx, JSTYPE_VOID, vp)) ||
1033     !js_ValueToCharBuffer(cx, *vp, buf)) {
1034     goto error;
1035     }
1036     }
1037    
1038     str = js_NewStringFromCharBuffer(cx, buf);
1039     if (!str)
1040     goto error;
1041    
1042     regs.sp -= argc - 1;
1043     STORE_OPND(-1, STRING_TO_JSVAL(str));
1044    
1045     #ifdef JS_TRACER
1046     if (imacro) {
1047     /* END_CASE does pc += CONCATN_LENGTH. (IMACOP YOU IDIOT!) */
1048     regs.pc -= JSOP_CONCATN_LENGTH - JSOP_IMACOP_LENGTH;
1049     }
1050     #endif /* JS_TRACER */
1051     }
1052     END_CASE(JSOP_CONCATN)
1053    
1054     #define BINARY_OP(OP) \
1055     JS_BEGIN_MACRO \
1056     FETCH_NUMBER(cx, -2, d); \
1057     FETCH_NUMBER(cx, -1, d2); \
1058     d = d OP d2; \
1059     regs.sp--; \
1060     STORE_NUMBER(cx, -1, d); \
1061     JS_END_MACRO
1062    
1063     BEGIN_CASE(JSOP_SUB)
1064     BINARY_OP(-);
1065     END_CASE(JSOP_SUB)
1066    
1067     BEGIN_CASE(JSOP_MUL)
1068     BINARY_OP(*);
1069     END_CASE(JSOP_MUL)
1070    
1071     BEGIN_CASE(JSOP_DIV)
1072     FETCH_NUMBER(cx, -1, d2);
1073     FETCH_NUMBER(cx, -2, d);
1074     regs.sp--;
1075     if (d2 == 0) {
1076     #ifdef XP_WIN
1077     /* XXX MSVC miscompiles such that (NaN == 0) */
1078     if (JSDOUBLE_IS_NaN(d2))
1079     rval = DOUBLE_TO_JSVAL(rt->jsNaN);
1080     else
1081     #endif
1082     if (d == 0 || JSDOUBLE_IS_NaN(d))
1083     rval = DOUBLE_TO_JSVAL(rt->jsNaN);
1084     else if (JSDOUBLE_IS_NEG(d) != JSDOUBLE_IS_NEG(d2))
1085     rval = DOUBLE_TO_JSVAL(rt->jsNegativeInfinity);
1086     else
1087     rval = DOUBLE_TO_JSVAL(rt->jsPositiveInfinity);
1088     STORE_OPND(-1, rval);
1089     } else {
1090     d /= d2;
1091     STORE_NUMBER(cx, -1, d);
1092     }
1093     END_CASE(JSOP_DIV)
1094    
1095     BEGIN_CASE(JSOP_MOD)
1096     FETCH_NUMBER(cx, -1, d2);
1097     FETCH_NUMBER(cx, -2, d);
1098     regs.sp--;
1099     if (d2 == 0) {
1100     STORE_OPND(-1, DOUBLE_TO_JSVAL(rt->jsNaN));
1101     } else {
1102     d = js_fmod(d, d2);
1103     STORE_NUMBER(cx, -1, d);
1104     }
1105     END_CASE(JSOP_MOD)
1106    
1107     BEGIN_CASE(JSOP_NOT)
1108     POP_BOOLEAN(cx, rval, cond);
1109     PUSH_OPND(BOOLEAN_TO_JSVAL(!cond));
1110     END_CASE(JSOP_NOT)
1111    
1112     BEGIN_CASE(JSOP_BITNOT)
1113     FETCH_INT(cx, -1, i);
1114     i = ~i;
1115     STORE_INT(cx, -1, i);
1116     END_CASE(JSOP_BITNOT)
1117    
1118     BEGIN_CASE(JSOP_NEG)
1119     /*
1120     * When the operand is int jsval, INT_FITS_IN_JSVAL(i) implies
1121     * INT_FITS_IN_JSVAL(-i) unless i is 0 or JSVAL_INT_MIN when the
1122     * results, -0.0 or JSVAL_INT_MAX + 1, are jsdouble values.
1123     */
1124     rval = FETCH_OPND(-1);
1125     if (JSVAL_IS_INT(rval) &&
1126     rval != INT_TO_JSVAL(JSVAL_INT_MIN) &&
1127     (i = JSVAL_TO_INT(rval)) != 0) {
1128     JS_STATIC_ASSERT(!INT_FITS_IN_JSVAL(-JSVAL_INT_MIN));
1129     i = -i;
1130     JS_ASSERT(INT_FITS_IN_JSVAL(i));
1131     regs.sp[-1] = INT_TO_JSVAL(i);
1132     } else {
1133     if (JSVAL_IS_DOUBLE(rval)) {
1134     d = *JSVAL_TO_DOUBLE(rval);
1135     } else {
1136     d = js_ValueToNumber(cx, &regs.sp[-1]);
1137     if (JSVAL_IS_NULL(regs.sp[-1]))
1138     goto error;
1139     JS_ASSERT(JSVAL_IS_NUMBER(regs.sp[-1]) ||
1140     regs.sp[-1] == JSVAL_TRUE);
1141     }
1142     d = -d;
1143     if (!js_NewNumberInRootedValue(cx, d, &regs.sp[-1]))
1144     goto error;
1145     }
1146     END_CASE(JSOP_NEG)
1147    
1148     BEGIN_CASE(JSOP_POS)
1149     rval = FETCH_OPND(-1);
1150     if (!JSVAL_IS_NUMBER(rval)) {
1151     d = js_ValueToNumber(cx, &regs.sp[-1]);
1152     rval = regs.sp[-1];
1153     if (JSVAL_IS_NULL(rval))
1154     goto error;
1155     if (rval == JSVAL_TRUE) {
1156     if (!js_NewNumberInRootedValue(cx, d, &regs.sp[-1]))
1157     goto error;
1158     } else {
1159     JS_ASSERT(JSVAL_IS_NUMBER(rval));
1160     }
1161     }
1162     END_CASE(JSOP_POS)
1163    
1164     BEGIN_CASE(JSOP_DELNAME)
1165     LOAD_ATOM(0);
1166     id = ATOM_TO_JSID(atom);
1167     if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
1168     goto error;
1169    
1170     /* ECMA says to return true if name is undefined or inherited. */
1171     PUSH_OPND(JSVAL_TRUE);
1172     if (prop) {
1173     obj2->dropProperty(cx, prop);
1174     if (!obj->deleteProperty(cx, id, &regs.sp[-1]))
1175     goto error;
1176     }
1177     END_CASE(JSOP_DELNAME)
1178    
1179     BEGIN_CASE(JSOP_DELPROP)
1180     LOAD_ATOM(0);
1181     id = ATOM_TO_JSID(atom);
1182     PROPERTY_OP(-1, obj->deleteProperty(cx, id, &rval));
1183     STORE_OPND(-1, rval);
1184     END_CASE(JSOP_DELPROP)
1185    
1186     BEGIN_CASE(JSOP_DELELEM)
1187     ELEMENT_OP(-1, obj->deleteProperty(cx, id, &rval));
1188     regs.sp--;
1189     STORE_OPND(-1, rval);
1190     END_CASE(JSOP_DELELEM)
1191    
1192     BEGIN_CASE(JSOP_TYPEOFEXPR)
1193     BEGIN_CASE(JSOP_TYPEOF)
1194     rval = FETCH_OPND(-1);
1195     type = JS_TypeOfValue(cx, rval);
1196     atom = rt->atomState.typeAtoms[type];
1197     STORE_OPND(-1, ATOM_KEY(atom));
1198     END_CASE(JSOP_TYPEOF)
1199    
1200     BEGIN_CASE(JSOP_VOID)
1201     STORE_OPND(-1, JSVAL_VOID);
1202     END_CASE(JSOP_VOID)
1203    
1204     BEGIN_CASE(JSOP_INCELEM)
1205     BEGIN_CASE(JSOP_DECELEM)
1206     BEGIN_CASE(JSOP_ELEMINC)
1207     BEGIN_CASE(JSOP_ELEMDEC)
1208     /*
1209     * Delay fetching of id until we have the object to ensure
1210     * the proper evaluation order. See bug 372331.
1211     */
1212     id = 0;
1213     i = -2;
1214     goto fetch_incop_obj;
1215    
1216     BEGIN_CASE(JSOP_INCPROP)
1217     BEGIN_CASE(JSOP_DECPROP)
1218     BEGIN_CASE(JSOP_PROPINC)
1219     BEGIN_CASE(JSOP_PROPDEC)
1220     LOAD_ATOM(0);
1221     id = ATOM_TO_JSID(atom);
1222     i = -1;
1223    
1224     fetch_incop_obj:
1225     FETCH_OBJECT(cx, i, lval, obj);
1226     if (id == 0)
1227     FETCH_ELEMENT_ID(obj, -1, id);
1228     goto do_incop;
1229    
1230     BEGIN_CASE(JSOP_INCNAME)
1231     BEGIN_CASE(JSOP_DECNAME)
1232     BEGIN_CASE(JSOP_NAMEINC)
1233     BEGIN_CASE(JSOP_NAMEDEC)
1234     {
1235     JSPropCacheEntry *entry;
1236    
1237     obj = fp->scopeChain;
1238     if (JS_LIKELY(OBJ_IS_NATIVE(obj))) {
1239     PROPERTY_CACHE_TEST(cx, regs.pc, obj, obj2, entry, atom);
1240     if (!atom) {
1241     ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
1242     if (obj == obj2 && PCVAL_IS_SLOT(entry->vword)) {
1243     slot = PCVAL_TO_SLOT(entry->vword);
1244     JS_ASSERT(slot < OBJ_SCOPE(obj)->freeslot);
1245     rval = LOCKED_OBJ_GET_SLOT(obj, slot);
1246     if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) {
1247     rtmp = rval;
1248     rval += (js_CodeSpec[op].format & JOF_INC) ? 2 : -2;
1249     if (!(js_CodeSpec[op].format & JOF_POST))
1250     rtmp = rval;
1251     LOCKED_OBJ_SET_SLOT(obj, slot, rval);
1252     JS_UNLOCK_OBJ(cx, obj);
1253     PUSH_OPND(rtmp);
1254     len = JSOP_INCNAME_LENGTH;
1255     DO_NEXT_OP(len);
1256     }
1257     }
1258     JS_UNLOCK_OBJ(cx, obj2);
1259     LOAD_ATOM(0);
1260     }
1261     } else {
1262     LOAD_ATOM(0);
1263     }
1264     id = ATOM_TO_JSID(atom);
1265     if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop))
1266     goto error;
1267     if (!prop)
1268     goto atom_not_defined;
1269     obj2->dropProperty(cx, prop);
1270     }
1271    
1272     do_incop:
1273     {
1274     const JSCodeSpec *cs;
1275     jsval v;
1276    
1277     /*
1278     * We need a root to store the value to leave on the stack until
1279     * we have done with obj->setProperty.
1280     */
1281     PUSH_OPND(JSVAL_NULL);
1282     if (!obj->getProperty(cx, id, &regs.sp[-1]))
1283     goto error;
1284    
1285     cs = &js_CodeSpec[op];
1286     JS_ASSERT(cs->ndefs == 1);
1287     JS_ASSERT((cs->format & JOF_TMPSLOT_MASK) == JOF_TMPSLOT2);
1288     v = regs.sp[-1];
1289     if (JS_LIKELY(CAN_DO_FAST_INC_DEC(v))) {
1290     jsval incr;
1291    
1292     incr = (cs->format & JOF_INC) ? 2 : -2;
1293     if (cs->format & JOF_POST) {
1294     regs.sp[-1] = v + incr;
1295     } else {
1296     v += incr;
1297     regs.sp[-1] = v;
1298     }
1299     fp->flags |= JSFRAME_ASSIGNING;
1300     ok = obj->setProperty(cx, id, &regs.sp[-1]);
1301     fp->flags &= ~JSFRAME_ASSIGNING;
1302     if (!ok)
1303     goto error;
1304    
1305     /*
1306     * We must set regs.sp[-1] to v for both post and pre increments
1307     * as the setter overwrites regs.sp[-1].
1308     */
1309     regs.sp[-1] = v;
1310     } else {
1311     /* We need an extra root for the result. */
1312     PUSH_OPND(JSVAL_NULL);
1313     if (!js_DoIncDec(cx, cs, &regs.sp[-2], &regs.sp[-1]))
1314     goto error;
1315     fp->flags |= JSFRAME_ASSIGNING;
1316     ok = obj->setProperty(cx, id, &regs.sp[-1]);
1317     fp->flags &= ~JSFRAME_ASSIGNING;
1318     if (!ok)
1319     goto error;
1320     regs.sp--;
1321     }
1322    
1323     if (cs->nuses == 0) {
1324     /* regs.sp[-1] already contains the result of name increment. */
1325     } else {
1326     rtmp = regs.sp[-1];
1327     regs.sp -= cs->nuses;
1328     regs.sp[-1] = rtmp;
1329     }
1330     len = cs->length;
1331     DO_NEXT_OP(len);
1332     }
1333    
1334     {
1335     jsval incr, incr2;
1336    
1337     /* Position cases so the most frequent i++ does not need a jump. */
1338     BEGIN_CASE(JSOP_DECARG)
1339     incr = -2; incr2 = -2; goto do_arg_incop;
1340     BEGIN_CASE(JSOP_ARGDEC)
1341     incr = -2; incr2 = 0; goto do_arg_incop;
1342     BEGIN_CASE(JSOP_INCARG)
1343     incr = 2; incr2 = 2; goto do_arg_incop;
1344     BEGIN_CASE(JSOP_ARGINC)
1345     incr = 2; incr2 = 0;
1346    
1347     do_arg_incop:
1348     slot = GET_ARGNO(regs.pc);
1349     JS_ASSERT(slot < fp->fun->nargs);
1350     METER_SLOT_OP(op, slot);
1351     vp = fp->argv + slot;
1352     goto do_int_fast_incop;
1353    
1354     BEGIN_CASE(JSOP_DECLOCAL)
1355     incr = -2; incr2 = -2; goto do_local_incop;
1356     BEGIN_CASE(JSOP_LOCALDEC)
1357     incr = -2; incr2 = 0; goto do_local_incop;
1358     BEGIN_CASE(JSOP_INCLOCAL)
1359     incr = 2; incr2 = 2; goto do_local_incop;
1360     BEGIN_CASE(JSOP_LOCALINC)
1361     incr = 2; incr2 = 0;
1362    
1363     /*
1364     * do_local_incop comes right before do_int_fast_incop as we want to
1365     * avoid an extra jump for variable cases as local++ is more frequent
1366     * than arg++.
1367     */
1368     do_local_incop:
1369     slot = GET_SLOTNO(regs.pc);
1370     JS_ASSERT(slot < fp->script->nslots);
1371     vp = fp->slots + slot;
1372     METER_SLOT_OP(op, slot);
1373     vp = fp->slots + slot;
1374    
1375     do_int_fast_incop:
1376     rval = *vp;
1377     if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) {
1378     *vp = rval + incr;
1379     JS_ASSERT(JSOP_INCARG_LENGTH == js_CodeSpec[op].length);
1380     SKIP_POP_AFTER_SET(JSOP_INCARG_LENGTH, 0);
1381     PUSH_OPND(rval + incr2);
1382     } else {
1383     PUSH_OPND(rval);
1384     if (!js_DoIncDec(cx, &js_CodeSpec[op], &regs.sp[-1], vp))
1385     goto error;
1386     }
1387     len = JSOP_INCARG_LENGTH;
1388     JS_ASSERT(len == js_CodeSpec[op].length);
1389     DO_NEXT_OP(len);
1390     }
1391    
1392     /* NB: This macro doesn't use JS_BEGIN_MACRO/JS_END_MACRO around its body. */
1393     #define FAST_GLOBAL_INCREMENT_OP(SLOWOP,INCR,INCR2) \
1394     op2 = SLOWOP; \
1395     incr = INCR; \
1396     incr2 = INCR2; \
1397     goto do_global_incop
1398    
1399     {
1400     jsval incr, incr2;
1401    
1402     BEGIN_CASE(JSOP_DECGVAR)
1403     FAST_GLOBAL_INCREMENT_OP(JSOP_DECNAME, -2, -2);
1404     BEGIN_CASE(JSOP_GVARDEC)
1405     FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEDEC, -2, 0);
1406     BEGIN_CASE(JSOP_INCGVAR)
1407     FAST_GLOBAL_INCREMENT_OP(JSOP_INCNAME, 2, 2);
1408     BEGIN_CASE(JSOP_GVARINC)
1409     FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEINC, 2, 0);
1410    
1411     #undef FAST_GLOBAL_INCREMENT_OP
1412    
1413     do_global_incop:
1414     JS_ASSERT((js_CodeSpec[op].format & JOF_TMPSLOT_MASK) ==
1415     JOF_TMPSLOT2);
1416     slot = GET_SLOTNO(regs.pc);
1417     JS_ASSERT(slot < GlobalVarCount(fp));
1418     METER_SLOT_OP(op, slot);
1419     lval = fp->slots[slot];
1420     if (JSVAL_IS_NULL(lval)) {
1421     op = op2;
1422     DO_OP();
1423     }
1424     slot = JSVAL_TO_INT(lval);
1425     rval = OBJ_GET_SLOT(cx, fp->varobj, slot);
1426     if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) {
1427     PUSH_OPND(rval + incr2);
1428     rval += incr;
1429     } else {
1430     PUSH_OPND(rval);
1431     PUSH_OPND(JSVAL_NULL); /* Extra root */
1432     if (!js_DoIncDec(cx, &js_CodeSpec[op], &regs.sp[-2], &regs.sp[-1]))
1433     goto error;
1434     rval = regs.sp[-1];
1435     --regs.sp;
1436     }
1437     OBJ_SET_SLOT(cx, fp->varobj, slot, rval);
1438     len = JSOP_INCGVAR_LENGTH; /* all gvar incops are same length */
1439     JS_ASSERT(len == js_CodeSpec[op].length);
1440     DO_NEXT_OP(len);
1441     }
1442    
1443     #define COMPUTE_THIS(cx, fp, obj) \
1444     JS_BEGIN_MACRO \
1445     if (!(obj = js_ComputeThisForFrame(cx, fp))) \
1446     goto error; \
1447     JS_END_MACRO
1448    
1449     BEGIN_CASE(JSOP_THIS)
1450     COMPUTE_THIS(cx, fp, obj);
1451     PUSH_OPND(OBJECT_TO_JSVAL(obj));
1452     END_CASE(JSOP_THIS)
1453    
1454     BEGIN_CASE(JSOP_GETTHISPROP)
1455     i = 0;
1456     COMPUTE_THIS(cx, fp, obj);
1457     PUSH(JSVAL_NULL);
1458     goto do_getprop_with_obj;
1459    
1460     #undef COMPUTE_THIS
1461    
1462     BEGIN_CASE(JSOP_GETARGPROP)
1463     i = ARGNO_LEN;
1464     slot = GET_ARGNO(regs.pc);
1465     JS_ASSERT(slot < fp->fun->nargs);
1466     PUSH_OPND(fp->argv[slot]);
1467     goto do_getprop_body;
1468    
1469     BEGIN_CASE(JSOP_GETLOCALPROP)
1470     i = SLOTNO_LEN;
1471     slot = GET_SLOTNO(regs.pc);
1472     JS_ASSERT(slot < script->nslots);
1473     PUSH_OPND(fp->slots[slot]);
1474     goto do_getprop_body;
1475    
1476     BEGIN_CASE(JSOP_GETPROP)
1477     BEGIN_CASE(JSOP_GETXPROP)
1478     i = 0;
1479    
1480     do_getprop_body:
1481     lval = FETCH_OPND(-1);
1482    
1483     do_getprop_with_lval:
1484     VALUE_TO_OBJECT(cx, -1, lval, obj);
1485    
1486     do_getprop_with_obj:
1487     do {
1488     JSObject *aobj;
1489     JSPropCacheEntry *entry;
1490    
1491     aobj = js_GetProtoIfDenseArray(cx, obj);
1492     if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)) {
1493     PROPERTY_CACHE_TEST(cx, regs.pc, aobj, obj2, entry, atom);
1494     if (!atom) {
1495     ASSERT_VALID_PROPERTY_CACHE_HIT(i, aobj, obj2, entry);
1496     if (PCVAL_IS_OBJECT(entry->vword)) {
1497     rval = PCVAL_OBJECT_TO_JSVAL(entry->vword);
1498     } else if (PCVAL_IS_SLOT(entry->vword)) {
1499     slot = PCVAL_TO_SLOT(entry->vword);
1500     JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot);
1501     rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
1502     } else {
1503     JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
1504     sprop = PCVAL_TO_SPROP(entry->vword);
1505     NATIVE_GET(cx, obj, obj2, sprop, &rval);
1506     }
1507     JS_UNLOCK_OBJ(cx, obj2);
1508     break;
1509     }
1510     } else {
1511     entry = NULL;
1512     if (i < 0)
1513     atom = rt->atomState.lengthAtom;
1514     else
1515     LOAD_ATOM(i);
1516     }
1517     id = ATOM_TO_JSID(atom);
1518     if (entry
1519     ? !js_GetPropertyHelper(cx, obj, id, true, &rval)
1520     : !obj->getProperty(cx, id, &rval)) {
1521     goto error;
1522     }
1523     } while (0);
1524    
1525     STORE_OPND(-1, rval);
1526     JS_ASSERT(JSOP_GETPROP_LENGTH + i == js_CodeSpec[op].length);
1527     len = JSOP_GETPROP_LENGTH + i;
1528     END_VARLEN_CASE
1529    
1530     BEGIN_CASE(JSOP_LENGTH)
1531     lval = FETCH_OPND(-1);
1532     if (JSVAL_IS_STRING(lval)) {
1533     str = JSVAL_TO_STRING(lval);
1534     regs.sp[-1] = INT_TO_JSVAL(str->length());
1535     } else if (!JSVAL_IS_PRIMITIVE(lval) &&
1536     (obj = JSVAL_TO_OBJECT(lval), OBJ_IS_ARRAY(cx, obj))) {
1537     jsuint length;
1538    
1539     /*
1540     * We know that the array is created with only its 'length'
1541     * private data in a fixed slot at JSSLOT_ARRAY_LENGTH. See
1542     * also JSOP_ARRAYPUSH, far below.
1543     */
1544     length = obj->fslots[JSSLOT_ARRAY_LENGTH];
1545     if (length <= JSVAL_INT_MAX) {
1546     regs.sp[-1] = INT_TO_JSVAL(length);
1547     } else if (!js_NewDoubleInRootedValue(cx, (jsdouble) length,
1548     &regs.sp[-1])) {
1549     goto error;
1550     }
1551     } else {
1552     i = -2;
1553     goto do_getprop_with_lval;
1554     }
1555     END_CASE(JSOP_LENGTH)
1556    
1557     BEGIN_CASE(JSOP_CALLPROP)
1558     {
1559     JSObject *aobj;
1560     JSPropCacheEntry *entry;
1561    
1562     lval = FETCH_OPND(-1);
1563     if (!JSVAL_IS_PRIMITIVE(lval)) {
1564     obj = JSVAL_TO_OBJECT(lval);
1565     } else {
1566     if (JSVAL_IS_STRING(lval)) {
1567     i = JSProto_String;
1568     } else if (JSVAL_IS_NUMBER(lval)) {
1569     i = JSProto_Number;
1570     } else if (JSVAL_IS_BOOLEAN(lval)) {
1571     i = JSProto_Boolean;
1572     } else {
1573     JS_ASSERT(JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval));
1574     js_ReportIsNullOrUndefined(cx, -1, lval, NULL);
1575     goto error;
1576     }
1577    
1578     if (!js_GetClassPrototype(cx, NULL, INT_TO_JSID(i), &obj))
1579     goto error;
1580     }
1581    
1582     aobj = js_GetProtoIfDenseArray(cx, obj);
1583     if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)) {
1584     PROPERTY_CACHE_TEST(cx, regs.pc, aobj, obj2, entry, atom);
1585     if (!atom) {
1586     ASSERT_VALID_PROPERTY_CACHE_HIT(0, aobj, obj2, entry);
1587     if (PCVAL_IS_OBJECT(entry->vword)) {
1588     rval = PCVAL_OBJECT_TO_JSVAL(entry->vword);
1589     } else if (PCVAL_IS_SLOT(entry->vword)) {
1590     slot = PCVAL_TO_SLOT(entry->vword);
1591     JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot);
1592     rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
1593     } else {
1594     JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
1595     sprop = PCVAL_TO_SPROP(entry->vword);
1596     NATIVE_GET(cx, obj, obj2, sprop, &rval);
1597     }
1598     JS_UNLOCK_OBJ(cx, obj2);
1599     STORE_OPND(-1, rval);
1600     PUSH_OPND(lval);
1601     goto end_callprop;
1602     }
1603     } else {
1604     entry = NULL;
1605     LOAD_ATOM(0);
1606     }
1607    
1608     /*
1609     * Cache miss: use the immediate atom that was loaded for us under
1610     * PROPERTY_CACHE_TEST.
1611     */
1612     id = ATOM_TO_JSID(atom);
1613     PUSH(JSVAL_NULL);
1614     if (!JSVAL_IS_PRIMITIVE(lval)) {
1615     if (!js_GetMethod(cx, obj, id, !!entry, &rval))
1616     goto error;
1617     STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
1618     STORE_OPND(-2, rval);
1619     } else {
1620     JS_ASSERT(obj->map->ops->getProperty == js_GetProperty);
1621     if (!js_GetPropertyHelper(cx, obj, id, true, &rval))
1622     goto error;
1623     STORE_OPND(-1, lval);
1624     STORE_OPND(-2, rval);
1625     }
1626    
1627     end_callprop:
1628     /* Wrap primitive lval in object clothing if necessary. */
1629     if (JSVAL_IS_PRIMITIVE(lval)) {
1630     /* FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=412571 */
1631     if (!VALUE_IS_FUNCTION(cx, rval) ||
1632     (obj = JSVAL_TO_OBJECT(rval),
1633     fun = GET_FUNCTION_PRIVATE(cx, obj),
1634     !PRIMITIVE_THIS_TEST(fun, lval))) {
1635     if (!js_PrimitiveToObject(cx, &regs.sp[-1]))
1636     goto error;
1637     }
1638     }
1639     #if JS_HAS_NO_SUCH_METHOD
1640     if (JS_UNLIKELY(JSVAL_IS_VOID(rval))) {
1641     LOAD_ATOM(0);
1642     regs.sp[-2] = ATOM_KEY(atom);
1643     if (!js_OnUnknownMethod(cx, regs.sp - 2))
1644     goto error;
1645     }
1646     #endif
1647     }
1648     END_CASE(JSOP_CALLPROP)
1649    
1650     BEGIN_CASE(JSOP_SETNAME)
1651     BEGIN_CASE(JSOP_SETPROP)
1652     rval = FETCH_OPND(-1);
1653     lval = FETCH_OPND(-2);
1654     JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval) || op == JSOP_SETPROP);
1655     VALUE_TO_OBJECT(cx, -2, lval, obj);
1656    
1657     do {
1658     JSPropCacheEntry *entry;
1659    
1660     entry = NULL;
1661     atom = NULL;
1662     if (JS_LIKELY(obj->map->ops->setProperty == js_SetProperty)) {
1663     JSPropertyCache *cache = &JS_PROPERTY_CACHE(cx);
1664     uint32 kshape = OBJ_SHAPE(obj);
1665    
1666     /*
1667     * Open-code PROPERTY_CACHE_TEST, specializing for two
1668     * important set-property cases. First:
1669     *
1670     * function f(a, b, c) {
1671     * var o = {p:a, q:b, r:c};
1672     * return o;
1673     * }
1674     *
1675     * or similar real-world cases, which evolve a newborn
1676     * native object predicatably through some bounded number
1677     * of property additions. And second:
1678     *
1679     * o.p = x;
1680     *
1681     * in a frequently executed method or loop body, where p
1682     * will (possibly after the first iteration) always exist
1683     * in native object o.
1684     */
1685     entry = &cache->table[PROPERTY_CACHE_HASH_PC(regs.pc, kshape)];
1686     PCMETER(cache->pctestentry = entry);
1687     PCMETER(cache->tests++);
1688     PCMETER(cache->settests++);
1689     if (entry->kpc == regs.pc && entry->kshape == kshape) {
1690     JS_ASSERT(PCVCAP_TAG(entry->vcap) <= 1);
1691     if (JS_LOCK_OBJ_IF_SHAPE(cx, obj, kshape)) {
1692     JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
1693     sprop = PCVAL_TO_SPROP(entry->vword);
1694     JS_ASSERT(!(sprop->attrs & JSPROP_READONLY));
1695     JS_ASSERT_IF(!(sprop->attrs & JSPROP_SHARED),
1696     PCVCAP_TAG(entry->vcap) == 0);
1697    
1698     JSScope *scope = OBJ_SCOPE(obj);
1699     JS_ASSERT(!scope->sealed());
1700    
1701     /*
1702     * Fastest path: check whether the cached sprop is
1703     * already in scope and call NATIVE_SET and break
1704     * to get out of the do-while(0). But we can call
1705     * NATIVE_SET only if obj owns scope or sprop is
1706     * shared.
1707     */
1708     bool checkForAdd;
1709     if (sprop->attrs & JSPROP_SHARED) {
1710     if (PCVCAP_TAG(entry->vcap) == 0 ||
1711     ((obj2 = OBJ_GET_PROTO(cx, obj)) &&
1712     OBJ_IS_NATIVE(obj2) &&
1713     OBJ_SHAPE(obj2) == PCVCAP_SHAPE(entry->vcap))) {
1714     goto fast_set_propcache_hit;
1715     }
1716    
1717     /* The cache entry doesn't apply. vshape mismatch. */
1718     checkForAdd = false;
1719     } else if (scope->owned()) {
1720     if (sprop == scope->lastProp || scope->has(sprop)) {
1721     fast_set_propcache_hit:
1722     PCMETER(cache->pchits++);
1723     PCMETER(cache->setpchits++);
1724     NATIVE_SET(cx, obj, sprop, entry, &rval);
1725     JS_UNLOCK_SCOPE(cx, scope);
1726     break;
1727     }
1728     checkForAdd =
1729     !(sprop->attrs & JSPROP_SHARED) &&
1730     sprop->parent == scope->lastProp &&
1731     !scope->hadMiddleDelete();
1732     } else {
1733     scope = js_GetMutableScope(cx, obj);
1734     if (!scope) {
1735     JS_UNLOCK_OBJ(cx, obj);
1736     goto error;
1737     }
1738     checkForAdd = !sprop->parent;
1739     }
1740    
1741     if (checkForAdd &&
1742     SPROP_HAS_STUB_SETTER(sprop) &&
1743     (slot = sprop->slot) == scope->freeslot) {
1744     /*
1745     * Fast path: adding a plain old property that
1746     * was once at the frontier of the property
1747     * tree, whose slot is next to claim among the
1748     * allocated slots in obj, where scope->table
1749     * has not been created yet.
1750     *
1751     * We may want to remove hazard conditions
1752     * above and inline compensation code here,
1753     * depending on real-world workloads.
1754     */
1755     JS_ASSERT(!(obj->getClass()->flags &
1756     JSCLASS_SHARE_ALL_PROPERTIES));
1757    
1758     PCMETER(cache->pchits++);
1759     PCMETER(cache->addpchits++);
1760    
1761     /*
1762     * Beware classes such as Function that use
1763     * the reserveSlots hook to allocate a number
1764     * of reserved slots that may vary with obj.
1765     */
1766     if (slot < STOBJ_NSLOTS(obj) &&
1767     !OBJ_GET_CLASS(cx, obj)->reserveSlots) {
1768     ++scope->freeslot;
1769     } else {
1770     if (!js_AllocSlot(cx, obj, &slot)) {
1771     JS_UNLOCK_SCOPE(cx, scope);
1772     goto error;
1773     }
1774     }
1775    
1776     /*
1777     * If this obj's number of reserved slots
1778     * differed, or if something created a hash
1779     * table for scope, we must pay the price of
1780     * JSScope::add.
1781     *
1782     * If slot does not match the cached sprop's
1783     * slot, update the cache entry in the hope
1784     * that obj and other instances with the same
1785     * number of reserved slots are now "hot".
1786     */
1787     if (slot != sprop->slot || scope->table) {
1788     JSScopeProperty *sprop2 =
1789     scope->add(cx, sprop->id,
1790     sprop->getter, sprop->setter,
1791     slot, sprop->attrs,
1792     sprop->flags, sprop->shortid);
1793     if (!sprop2) {
1794     js_FreeSlot(cx, obj, slot);
1795     JS_UNLOCK_SCOPE(cx, scope);
1796     goto error;
1797     }
1798     if (sprop2 != sprop) {
1799     PCMETER(cache->slotchanges++);
1800     JS_ASSERT(slot != sprop->slot &&
1801     slot == sprop2->slot &&
1802     sprop2->id == sprop->id);
1803     entry->vword = SPROP_TO_PCVAL(sprop2);
1804     }
1805     sprop = sprop2;
1806     } else {
1807     scope->extend(cx, sprop);
1808     }
1809    
1810     LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, rval);
1811     TRACE_2(SetPropHit, entry, sprop);
1812     LOCKED_OBJ_SET_SLOT(obj, slot, rval);
1813     JS_UNLOCK_SCOPE(cx, scope);
1814    
1815     /*
1816     * Purge the property cache of the id we may
1817     * have just shadowed in obj's scope and proto
1818     * chains. We do this after unlocking obj's
1819     * scope to avoid lock nesting.
1820     */
1821     js_PurgeScopeChain(cx, obj, sprop->id);
1822     break;
1823     }
1824     JS_UNLOCK_SCOPE(cx, scope);
1825     PCMETER(cache->setpcmisses++);
1826     }
1827     }
1828    
1829     atom = js_FullTestPropertyCache(cx, regs.pc, &obj, &obj2,
1830     &entry);
1831     if (atom) {
1832     PCMETER(cache->misses++);
1833     PCMETER(cache->setmisses++);
1834     } else {
1835     ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
1836     sprop = NULL;
1837     if (obj == obj2) {
1838     JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
1839     sprop = PCVAL_TO_SPROP(entry->vword);
1840     JS_ASSERT(!(sprop->attrs & JSPROP_READONLY));
1841     JS_ASSERT(!OBJ_SCOPE(obj2)->sealed());
1842     NATIVE_SET(cx, obj, sprop, entry, &rval);
1843     }
1844     JS_UNLOCK_OBJ(cx, obj2);
1845     if (sprop)
1846     break;
1847     }
1848     }
1849    
1850     if (!atom)
1851     LOAD_ATOM(0);
1852     id = ATOM_TO_JSID(atom);
1853     if (entry) {
1854     if (!js_SetPropertyHelper(cx, obj, id, true, &rval))
1855     goto error;
1856     } else {
1857     if (!obj->setProperty(cx, id, &rval))
1858     goto error;
1859     ABORT_RECORDING(cx, "Non-native set");
1860     }
1861     } while (0);
1862     END_SET_CASE_STORE_RVAL(JSOP_SETPROP, 2);
1863    
1864     BEGIN_CASE(JSOP_GETELEM)
1865     /* Open-coded ELEMENT_OP optimized for strings and dense arrays. */
1866     lval = FETCH_OPND(-2);
1867     rval = FETCH_OPND(-1);
1868     if (JSVAL_IS_STRING(lval) && JSVAL_IS_INT(rval)) {
1869     str = JSVAL_TO_STRING(lval);
1870     i = JSVAL_TO_INT(rval);
1871     if ((size_t)i < str->length()) {
1872     str = JSString::getUnitString(cx, str, size_t(i));
1873     if (!str)
1874     goto error;
1875     rval = STRING_TO_JSVAL(str);
1876     goto end_getelem;
1877     }
1878     }
1879    
1880     VALUE_TO_OBJECT(cx, -2, lval, obj);
1881     if (JSVAL_IS_INT(rval)) {
1882     if (OBJ_IS_DENSE_ARRAY(cx, obj)) {
1883     jsuint length;
1884    
1885     length = js_DenseArrayCapacity(obj);
1886     i = JSVAL_TO_INT(rval);
1887     if ((jsuint)i < length &&
1888     i < obj->fslots[JSSLOT_ARRAY_LENGTH]) {
1889     rval = obj->dslots[i];
1890     if (rval != JSVAL_HOLE)
1891     goto end_getelem;
1892    
1893     /* Reload rval from the stack in the rare hole case. */
1894     rval = FETCH_OPND(-1);
1895     }
1896     }
1897     id = INT_JSVAL_TO_JSID(rval);
1898     } else {
1899     if (!js_InternNonIntElementId(cx, obj, rval, &id))
1900     goto error;
1901     }
1902    
1903     if (!obj->getProperty(cx, id, &rval))
1904     goto error;
1905     end_getelem:
1906     regs.sp--;
1907     STORE_OPND(-1, rval);
1908     END_CASE(JSOP_GETELEM)
1909    
1910     BEGIN_CASE(JSOP_CALLELEM)
1911     ELEMENT_OP(-1, js_GetMethod(cx, obj, id, false, &rval));
1912     #if JS_HAS_NO_SUCH_METHOD
1913     if (JS_UNLIKELY(JSVAL_IS_VOID(rval))) {
1914     regs.sp[-2] = regs.sp[-1];
1915     regs.sp[-1] = OBJECT_TO_JSVAL(obj);
1916     if (!js_OnUnknownMethod(cx, regs.sp - 2))
1917     goto error;
1918     } else
1919     #endif
1920     {
1921     STORE_OPND(-2, rval);
1922     STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
1923     }
1924     END_CASE(JSOP_CALLELEM)
1925    
1926     BEGIN_CASE(JSOP_SETELEM)
1927     rval = FETCH_OPND(-1);
1928     FETCH_OBJECT(cx, -3, lval, obj);
1929     FETCH_ELEMENT_ID(obj, -2, id);
1930     do {
1931     if (OBJ_IS_DENSE_ARRAY(cx, obj) && JSID_IS_INT(id)) {
1932     jsuint length;
1933    
1934     length = js_DenseArrayCapacity(obj);
1935     i = JSID_TO_INT(id);
1936     if ((jsuint)i < length) {
1937     if (obj->dslots[i] == JSVAL_HOLE) {
1938     if (js_PrototypeHasIndexedProperties(cx, obj))
1939     break;
1940     if (i >= obj->fslots[JSSLOT_ARRAY_LENGTH])
1941     obj->fslots[JSSLOT_ARRAY_LENGTH] = i + 1;
1942     obj->fslots[JSSLOT_ARRAY_COUNT]++;
1943     }
1944     obj->dslots[i] = rval;
1945     goto end_setelem;
1946     }
1947     }
1948     } while (0);
1949     if (!obj->setProperty(cx, id, &rval))
1950     goto error;
1951     end_setelem:
1952     END_SET_CASE_STORE_RVAL(JSOP_SETELEM, 3)
1953    
1954     BEGIN_CASE(JSOP_ENUMELEM)
1955     /* Funky: the value to set is under the [obj, id] pair. */
1956     rval = FETCH_OPND(-3);
1957     FETCH_OBJECT(cx, -2, lval, obj);
1958     FETCH_ELEMENT_ID(obj, -1, id);
1959     if (!obj->setProperty(cx, id, &rval))
1960     goto error;
1961     regs.sp -= 3;
1962     END_CASE(JSOP_ENUMELEM)
1963    
1964     BEGIN_CASE(JSOP_NEW)
1965     /* Get immediate argc and find the constructor function. */
1966     argc = GET_ARGC(regs.pc);
1967     vp = regs.sp - (2 + argc);
1968     JS_ASSERT(vp >= StackBase(fp));
1969    
1970     /*
1971     * Assign lval, obj, and fun exactly as the code at inline_call:
1972     * expects to find them, to avoid nesting a js_Interpret call via
1973     * js_InvokeConstructor.
1974     */
1975     lval = *vp;
1976     if (VALUE_IS_FUNCTION(cx, lval)) {
1977     obj = JSVAL_TO_OBJECT(lval);
1978     fun = GET_FUNCTION_PRIVATE(cx, obj);
1979     if (FUN_INTERPRETED(fun)) {
1980     /* Root as we go using vp[1]. */
1981     if (!obj->getProperty(cx,
1982     ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom),
1983     &vp[1])) {
1984     goto error;
1985     }
1986     rval = vp[1];
1987     obj2 = js_NewObject(cx, &js_ObjectClass,
1988     JSVAL_IS_OBJECT(rval)
1989     ? JSVAL_TO_OBJECT(rval)
1990     : NULL,
1991     OBJ_GET_PARENT(cx, obj));
1992     if (!obj2)
1993     goto error;
1994     vp[1] = OBJECT_TO_JSVAL(obj2);
1995     flags = JSFRAME_CONSTRUCTING;
1996     goto inline_call;
1997     }
1998     }
1999    
2000     if (!js_InvokeConstructor(cx, argc, JS_FALSE, vp))
2001     goto error;
2002     regs.sp = vp + 1;
2003     CHECK_INTERRUPT_HANDLER();
2004     TRACE_0(NativeCallComplete);
2005     END_CASE(JSOP_NEW)
2006    
2007     BEGIN_CASE(JSOP_CALL)
2008     BEGIN_CASE(JSOP_EVAL)
2009     BEGIN_CASE(JSOP_APPLY)
2010     argc = GET_ARGC(regs.pc);
2011     vp = regs.sp - (argc + 2);
2012    
2013     lval = *vp;
2014     if (VALUE_IS_FUNCTION(cx, lval)) {
2015     obj = JSVAL_TO_OBJECT(lval);
2016     fun = GET_FUNCTION_PRIVATE(cx, obj);
2017    
2018     /* Clear frame flags since this is not a constructor call. */
2019     flags = 0;
2020     if (FUN_INTERPRETED(fun))
2021     inline_call:
2022     {
2023     uintN nframeslots, nvars, missing;
2024     JSArena *a;
2025     jsuword nbytes;
2026     void *newmark;
2027     jsval *newsp;
2028     JSInlineFrame *newifp;
2029     JSInterpreterHook hook;
2030    
2031     /* Restrict recursion of lightweight functions. */
2032     if (inlineCallCount == MAX_INLINE_CALL_COUNT) {
2033     js_ReportOverRecursed(cx);
2034     goto error;
2035     }
2036    
2037     /* Compute the total number of stack slots needed by fun. */
2038     nframeslots = JS_HOWMANY(sizeof(JSInlineFrame),
2039     sizeof(jsval));
2040     script = fun->u.i.script;
2041     atoms = script->atomMap.vector;
2042     nbytes = (nframeslots + script->nslots) * sizeof(jsval);
2043    
2044     /* Allocate missing expected args adjacent to actuals. */
2045     a = cx->stackPool.current;
2046     newmark = (void *) a->avail;
2047     if (fun->nargs <= argc) {
2048     missing = 0;
2049     } else {
2050     newsp = vp + 2 + fun->nargs;
2051     JS_ASSERT(newsp > regs.sp);
2052     if ((jsuword) newsp <= a->limit) {
2053     if ((jsuword) newsp > a->avail)
2054     a->avail = (jsuword) newsp;
2055     jsval *argsp = newsp;
2056     do {
2057     *--argsp = JSVAL_VOID;
2058     } while (argsp != regs.sp);
2059     missing = 0;
2060     } else {
2061     missing = fun->nargs - argc;
2062     nbytes += (2 + fun->nargs) * sizeof(jsval);
2063     }
2064     }
2065    
2066     /* Allocate the inline frame with its slots and operands. */
2067     if (a->avail + nbytes <= a->limit) {
2068     newsp = (jsval *) a->avail;
2069     a->avail += nbytes;
2070     JS_ASSERT(missing == 0);
2071     } else {
2072     JS_ARENA_ALLOCATE_CAST(newsp, jsval *, &cx->stackPool,
2073     nbytes);
2074     if (!newsp) {
2075     js_ReportOutOfScriptQuota(cx);
2076     goto bad_inline_call;
2077     }
2078    
2079     /*
2080     * Move args if the missing ones overflow arena a, then
2081     * push undefined for the missing args.
2082     */
2083     if (missing) {
2084     memcpy(newsp, vp, (2 + argc) * sizeof(jsval));
2085     vp = newsp;
2086     newsp = vp + 2 + argc;
2087     do {
2088     *newsp++ = JSVAL_VOID;
2089     } while (--missing != 0);
2090     }
2091     }
2092    
2093     /* Claim space for the stack frame and initialize it. */
2094     newifp = (JSInlineFrame *) newsp;
2095     newsp += nframeslots;
2096     newifp->frame.callobj = NULL;
2097     newifp->frame.argsobj = NULL;
2098     newifp->frame.varobj = NULL;
2099     newifp->frame.script = script;
2100     newifp->frame.fun = fun;
2101     newifp->frame.argc = argc;
2102     newifp->frame.argv = vp + 2;
2103     newifp->frame.rval = JSVAL_VOID;
2104     newifp->frame.down = fp;
2105     newifp->frame.annotation = NULL;
2106     newifp->frame.scopeChain = parent = OBJ_GET_PARENT(cx, obj);
2107     newifp->frame.sharpDepth = 0;
2108     newifp->frame.sharpArray = NULL;
2109     newifp->frame.flags = flags;
2110     newifp->frame.dormantNext = NULL;
2111     newifp->frame.blockChain = NULL;
2112     if (script->staticLevel < JS_DISPLAY_SIZE) {
2113     JSStackFrame **disp = &cx->display[script->staticLevel];
2114     newifp->frame.displaySave = *disp;
2115     *disp = &newifp->frame;
2116     }
2117     newifp->mark = newmark;
2118    
2119     /* Compute the 'this' parameter now that argv is set. */
2120     JS_ASSERT(!JSFUN_BOUND_METHOD_TEST(fun->flags));
2121     JS_ASSERT(JSVAL_IS_OBJECT(vp[1]));
2122     newifp->frame.thisp = (JSObject *)vp[1];
2123    
2124     newifp->frame.regs = NULL;
2125     newifp->frame.imacpc = NULL;
2126     newifp->frame.slots = newsp;
2127    
2128     /* Push void to initialize local variables. */
2129     nvars = fun->u.i.nvars;
2130     while (nvars--)
2131     *newsp++ = JSVAL_VOID;
2132    
2133     /* Scope with a call object parented by callee's parent. */
2134     if (JSFUN_HEAVYWEIGHT_TEST(fun->flags) &&
2135     !js_GetCallObject(cx, &newifp->frame)) {
2136     goto bad_inline_call;
2137     }
2138    
2139     /* Switch version if currentVersion wasn't overridden. */
2140     newifp->callerVersion = (JSVersion) cx->version;
2141     if (JS_LIKELY(cx->version == currentVersion)) {
2142     currentVersion = (JSVersion) script->version;
2143     if (currentVersion != cx->version)
2144     js_SetVersion(cx, currentVersion);
2145     }
2146    
2147     /* Push the frame and set interpreter registers. */
2148     newifp->callerRegs = regs;
2149     fp->regs = &newifp->callerRegs;
2150     regs.sp = newsp;
2151     regs.pc = script->code;
2152     newifp->frame.regs = &regs;
2153     cx->fp = fp = &newifp->frame;
2154    
2155     /* Call the debugger hook if present. */
2156     hook = cx->debugHooks->callHook;
2157     if (hook) {
2158     newifp->hookData = hook(cx, &newifp->frame, JS_TRUE, 0,
2159     cx->debugHooks->callHookData);
2160     CHECK_INTERRUPT_HANDLER();
2161     } else {
2162     newifp->hookData = NULL;
2163     }
2164    
2165     TRACE_0(EnterFrame);
2166    
2167     inlineCallCount++;
2168     JS_RUNTIME_METER(rt, inlineCalls);
2169    
2170     #ifdef INCLUDE_MOZILLA_DTRACE
2171     /* DTrace function entry, inlines */
2172     if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
2173     jsdtrace_function_entry(cx, fp, fun);
2174     if (JAVASCRIPT_FUNCTION_INFO_ENABLED())
2175     jsdtrace_function_info(cx, fp, fp->down, fun);
2176     if (JAVASCRIPT_FUNCTION_ARGS_ENABLED())
2177     jsdtrace_function_args(cx, fp, fun, fp->argc, fp->argv);
2178     #endif
2179    
2180     /* Load first op and dispatch it (safe since JSOP_STOP). */
2181     op = (JSOp) *regs.pc;
2182     DO_OP();
2183    
2184     bad_inline_call:
2185     JS_ASSERT(fp->regs == &regs);
2186     script = fp->script;
2187     atoms = script->atomMap.vector;
2188     js_FreeRawStack(cx, newmark);
2189     goto error;
2190     }
2191    
2192     if (fun->flags & JSFUN_FAST_NATIVE) {
2193     #ifdef INCLUDE_MOZILLA_DTRACE
2194     /* DTrace function entry, non-inlines */
2195     if (VALUE_IS_FUNCTION(cx, lval)) {
2196     if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
2197     jsdtrace_function_entry(cx, NULL, fun);
2198     if (JAVASCRIPT_FUNCTION_INFO_ENABLED())
2199     jsdtrace_function_info(cx, NULL, fp, fun);
2200     if (JAVASCRIPT_FUNCTION_ARGS_ENABLED())
2201     jsdtrace_function_args(cx, fp, fun, argc, vp+2);
2202     }
2203     #endif
2204    
2205     JS_ASSERT(fun->u.n.extra == 0);
2206     JS_ASSERT(JSVAL_IS_OBJECT(vp[1]) ||
2207     PRIMITIVE_THIS_TEST(fun, vp[1]));
2208     ok = ((JSFastNative) fun->u.n.native)(cx, argc, vp);
2209     #ifdef INCLUDE_MOZILLA_DTRACE
2210     if (VALUE_IS_FUNCTION(cx, lval)) {
2211     if (JAVASCRIPT_FUNCTION_RVAL_ENABLED())
2212     jsdtrace_function_rval(cx, NULL, fun, vp);
2213     if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
2214     jsdtrace_function_return(cx, NULL, fun);
2215     }
2216     #endif
2217     regs.sp = vp + 1;
2218     if (!ok) {
2219     /*
2220     * If we are executing the JSOP_NEXTITER imacro and a Stopiteration
2221     * exception is raised, transform it into a JSVAL_HOLE return value.
2222     * The tracer generates equivalent code by calling CatchStopIteration_tn.
2223     */
2224     if (fp->imacpc && *fp->imacpc == JSOP_NEXTITER &&
2225     cx->throwing && js_ValueIsStopIteration(cx->exception)) {
2226     // pc may point to JSOP_DUP here due to bug 474854.
2227     JS_ASSERT(*regs.pc == JSOP_CALL || *regs.pc == JSOP_DUP);
2228     cx->throwing = JS_FALSE;
2229     cx->exception = JSVAL_VOID;
2230     regs.sp[-1] = JSVAL_HOLE;
2231     } else {
2232     goto error;
2233     }
2234     }
2235     TRACE_0(NativeCallComplete);
2236     goto end_call;
2237     }
2238     }
2239    
2240     ok = js_Invoke(cx, argc, vp, 0);
2241     regs.sp = vp + 1;
2242     CHECK_INTERRUPT_HANDLER();
2243     if (!ok)
2244     goto error;
2245     JS_RUNTIME_METER(rt, nonInlineCalls);
2246     TRACE_0(NativeCallComplete);
2247    
2248     end_call:
2249     #if JS_HAS_LVALUE_RETURN
2250     if (cx->rval2set) {
2251     /*
2252     * Use the stack depth we didn't claim in our budget, but that
2253     * we know is there on account of [fun, this] already having
2254     * been pushed, at a minimum (if no args). Those two slots
2255     * have been popped and [rval] has been pushed, which leaves
2256     * one more slot for rval2 before we might overflow.
2257     *
2258     * NB: rval2 must be the property identifier, and rval the
2259     * object from which to get the property. The pair form an
2260     * ECMA "reference type", which can be used on the right- or
2261     * left-hand side of assignment ops. Note well: only native
2262     * methods can return reference types. See JSOP_SETCALL just
2263     * below for the left-hand-side case.
2264     */
2265     PUSH_OPND(cx->rval2);
2266     ELEMENT_OP(-1, obj->getProperty(cx, id, &rval));
2267    
2268     regs.sp--;
2269     STORE_OPND(-1, rval);
2270     cx->rval2set = JS_FALSE;
2271     }
2272     #endif /* JS_HAS_LVALUE_RETURN */
2273     END_CASE(JSOP_CALL)
2274    
2275     #if JS_HAS_LVALUE_RETURN
2276     BEGIN_CASE(JSOP_SETCALL)
2277     argc = GET_ARGC(regs.pc);
2278     vp = regs.sp - argc - 2;
2279     ok = js_Invoke(cx, argc, vp, 0);
2280     regs.sp = vp + 1;
2281     CHECK_INTERRUPT_HANDLER();
2282     if (!ok)
2283     goto error;
2284     if (!cx->rval2set) {
2285     op2 = js_GetOpcode(cx, script, regs.pc + JSOP_SETCALL_LENGTH);
2286     if (op2 != JSOP_DELELEM) {
2287     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2288     JSMSG_BAD_LEFTSIDE_OF_ASS);
2289     goto error;
2290     }
2291    
2292     /*
2293     * Store true as the result of the emulated delete of a
2294     * non-existent property. NB: We don't METER_OP_PAIR here;
2295     * it doesn't seem worth the code for this obscure case.
2296     */
2297     *vp = JSVAL_TRUE;
2298     regs.pc += JSOP_SETCALL_LENGTH + JSOP_DELELEM_LENGTH;
2299     op = (JSOp) *regs.pc;
2300     DO_OP();
2301     }
2302     PUSH_OPND(cx->rval2);
2303     cx->rval2set = JS_FALSE;
2304     END_CASE(JSOP_SETCALL)
2305     #endif
2306    
2307     BEGIN_CASE(JSOP_NAME)
2308     BEGIN_CASE(JSOP_CALLNAME)
2309     {
2310     JSPropCacheEntry *entry;
2311    
2312     obj = fp->scopeChain;
2313     if (JS_LIKELY(OBJ_IS_NATIVE(obj))) {
2314     PROPERTY_CACHE_TEST(cx, regs.pc, obj, obj2, entry, atom);
2315     if (!atom) {
2316     ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
2317     if (PCVAL_IS_OBJECT(entry->vword)) {
2318     rval = PCVAL_OBJECT_TO_JSVAL(entry->vword);
2319     JS_UNLOCK_OBJ(cx, obj2);
2320     goto do_push_rval;
2321     }
2322    
2323     if (PCVAL_IS_SLOT(entry->vword)) {
2324     slot = PCVAL_TO_SLOT(entry->vword);
2325     JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot);
2326     rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
2327     JS_UNLOCK_OBJ(cx, obj2);
2328     goto do_push_rval;
2329     }
2330    
2331     JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
2332     sprop = PCVAL_TO_SPROP(entry->vword);
2333     goto do_native_get;
2334     }
2335     } else {
2336     LOAD_ATOM(0);
2337     }
2338    
2339     id = ATOM_TO_JSID(atom);
2340     if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop))
2341     goto error;
2342     if (!prop) {
2343     /* Kludge to allow (typeof foo == "undefined") tests. */
2344     endpc = script->code + script->length;
2345     op2 = js_GetOpcode(cx, script, regs.pc + JSOP_NAME_LENGTH);
2346     if (op2 == JSOP_TYPEOF) {
2347     PUSH_OPND(JSVAL_VOID);
2348     len = JSOP_NAME_LENGTH;
2349     DO_NEXT_OP(len);
2350     }
2351     goto atom_not_defined;
2352     }
2353    
2354     /* Take the slow path if prop was not found in a native object. */
2355     if (!OBJ_IS_NATIVE(obj) || !OBJ_IS_NATIVE(obj2)) {
2356     obj2->dropProperty(cx, prop);
2357     if (!obj->getProperty(cx, id, &rval))
2358     goto error;
2359     } else {
2360     sprop = (JSScopeProperty *)prop;
2361     do_native_get:
2362     NATIVE_GET(cx, obj, obj2, sprop, &rval);
2363     obj2->dropProperty(cx, (JSProperty *) sprop);
2364     }
2365    
2366     do_push_rval:
2367     PUSH_OPND(rval);
2368     if (op == JSOP_CALLNAME)
2369     PUSH_OPND(OBJECT_TO_JSVAL(obj));
2370     }
2371     END_CASE(JSOP_NAME)
2372    
2373     BEGIN_CASE(JSOP_UINT16)
2374     i = (jsint) GET_UINT16(regs.pc);
2375     rval = INT_TO_JSVAL(i);
2376     PUSH_OPND(rval);
2377     END_CASE(JSOP_UINT16)
2378    
2379     BEGIN_CASE(JSOP_UINT24)
2380     i = (jsint) GET_UINT24(regs.pc);
2381     rval = INT_TO_JSVAL(i);
2382     PUSH_OPND(rval);
2383     END_CASE(JSOP_UINT24)
2384    
2385     BEGIN_CASE(JSOP_INT8)
2386     i = GET_INT8(regs.pc);
2387     rval = INT_TO_JSVAL(i);
2388     PUSH_OPND(rval);
2389     END_CASE(JSOP_INT8)
2390    
2391     BEGIN_CASE(JSOP_INT32)
2392     i = GET_INT32(regs.pc);
2393     rval = INT_TO_JSVAL(i);
2394     PUSH_OPND(rval);
2395     END_CASE(JSOP_INT32)
2396    
2397     BEGIN_CASE(JSOP_INDEXBASE)
2398     /*
2399     * Here atoms can exceed script->atomMap.length as we use atoms
2400     * as a segment register for object literals as well.
2401     */
2402     atoms += GET_INDEXBASE(regs.pc);
2403     END_CASE(JSOP_INDEXBASE)
2404    
2405     BEGIN_CASE(JSOP_INDEXBASE1)
2406     BEGIN_CASE(JSOP_INDEXBASE2)
2407     BEGIN_CASE(JSOP_INDEXBASE3)
2408     atoms += (op - JSOP_INDEXBASE1 + 1) << 16;
2409     END_CASE(JSOP_INDEXBASE3)
2410    
2411     BEGIN_CASE(JSOP_RESETBASE0)
2412     BEGIN_CASE(JSOP_RESETBASE)
2413     atoms = script->atomMap.vector;
2414     END_CASE(JSOP_RESETBASE)
2415    
2416     BEGIN_CASE(JSOP_DOUBLE)
2417     JS_ASSERT(!fp->imacpc);
2418     JS_ASSERT(size_t(atoms - script->atomMap.vector) < script->atomMap.length);
2419     /* FALL THROUGH */
2420    
2421     BEGIN_CASE(JSOP_STRING)
2422     LOAD_ATOM(0);
2423     PUSH_OPND(ATOM_KEY(atom));
2424     END_CASE(JSOP_DOUBLE)
2425    
2426     BEGIN_CASE(JSOP_OBJECT)
2427     LOAD_OBJECT(0);
2428     PUSH_OPND(OBJECT_TO_JSVAL(obj));
2429     END_CASE(JSOP_OBJECT)
2430    
2431     BEGIN_CASE(JSOP_REGEXP)
2432     {
2433     JSObject *funobj;
2434    
2435     /*
2436     * Push a regexp object for the atom mapped by the bytecode at pc,
2437     * cloning the literal's regexp object if necessary, to simulate in
2438     * the pre-compile/execute-later case what ECMA specifies for the
2439     * compile-and-go case: that scanning each regexp literal creates
2440     * a single corresponding RegExp object.
2441     *
2442     * To support pre-compilation transparently, we must handle the
2443     * case where a regexp object literal is used in a different global
2444     * at execution time from the global with which it was scanned at
2445     * compile time. We do this by re-wrapping the JSRegExp private
2446     * data struct with a cloned object having the right prototype and
2447     * parent, and having its own lastIndex property value storage.
2448     *
2449     * Unlike JSOP_DEFFUN and other prolog bytecodes that may clone
2450     * literal objects, we don't want to pay a script prolog execution
2451     * price for all regexp literals in a script (many may not be used
2452     * by a particular execution of that script, depending on control
2453     * flow), so we initialize lazily here.
2454     *
2455     * XXX This code is specific to regular expression objects. If we
2456     * need a similar op for other kinds of object literals, we should
2457     * push cloning down under JSObjectOps and reuse code here.
2458     */
2459     index = GET_FULL_INDEX(0);
2460     JS_ASSERT(index < script->regexps()->length);
2461    
2462     slot = index;
2463     if (fp->fun) {
2464     /*
2465     * We're in function code, not global or eval code (in eval
2466     * code, JSOP_REGEXP is never emitted). The cloned funobj
2467     * contains script->regexps()->length reserved slots
2468     * for the cloned regexps; see fun_reserveSlots, jsfun.c.
2469     */
2470     funobj = JSVAL_TO_OBJECT(fp->argv[-2]);
2471     slot += JSCLASS_RESERVED_SLOTS(&js_FunctionClass);
2472     if (script->upvarsOffset != 0)
2473     slot += script->upvars()->length;
2474     if (!JS_GetReservedSlot(cx, funobj, slot, &rval))
2475     goto error;
2476     if (JSVAL_IS_VOID(rval))
2477     rval = JSVAL_NULL;
2478     } else {
2479     /*
2480     * We're in global code. The code generator reserved a slot
2481     * for the regexp among script->nfixed slots. All such slots
2482     * are initialized to null, not void, for faster testing in
2483     * JSOP_*GVAR cases. To simplify index calculations we count
2484     * regexps in the reverse order down from script->nslots - 1.
2485     */
2486     JS_ASSERT(slot < script->nfixed);
2487     slot = script->nfixed - slot - 1;
2488     rval = fp->slots[slot];
2489     #ifdef __GNUC__
2490     funobj = NULL; /* suppress bogus gcc warnings */
2491     #endif
2492     }
2493    
2494     if (JSVAL_IS_NULL(rval)) {
2495     /* Compute the current global object in obj2. */
2496     obj2 = fp->scopeChain;
2497     while ((parent = OBJ_GET_PARENT(cx, obj2)) != NULL)
2498     obj2 = parent;
2499    
2500     /*
2501     * If obj's parent is not obj2, we must clone obj so that it
2502     * has the right parent, and therefore, the right prototype.
2503     *
2504     * Yes, this means we assume that the correct RegExp.prototype
2505     * to which regexp instances (including literals) delegate can
2506     * be distinguished solely by the instance's parent, which was
2507     * set to the parent of the RegExp constructor function object
2508     * when the instance was created. In other words,
2509     *
2510     * (/x/.__parent__ == RegExp.__parent__) implies
2511     * (/x/.__proto__ == RegExp.prototype)
2512     *
2513     * (unless you assign a different object to RegExp.prototype
2514     * at runtime, in which case, ECMA doesn't specify operation,
2515     * and you get what you deserve).
2516     *
2517     * This same coupling between instance parent and constructor
2518     * parent turns up everywhere (see jsobj.c's FindClassObject,
2519     * js_ConstructObject, and js_NewObject). It's fundamental to
2520     * the design of the language when you consider multiple global
2521     * objects and separate compilation and execution, even though
2522     * it is not specified fully in ECMA.
2523     */
2524     obj = script->getRegExp(index);
2525     if (OBJ_GET_PARENT(cx, obj) != obj2) {
2526     obj = js_CloneRegExpObject(cx, obj, obj2);
2527     if (!obj)
2528     goto error;