1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sw=4 et tw=78:
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 /*
42  * JavaScript bytecode interpreter.
43  */
44 #include "jsstddef.h"
45 #include <stdio.h>
46 #include <string.h>
47 #include <math.h>
48 #include "jstypes.h"
49 #include "jsarena.h" /* Added by JSIFY */
50 #include "jsutil.h" /* Added by JSIFY */
51 #include "jsprf.h"
52 #include "jsapi.h"
53 #include "jsarray.h"
54 #include "jsatom.h"
55 #include "jsbool.h"
56 #include "jscntxt.h"
57 #include "jsconfig.h"
58 #include "jsdbgapi.h"
59 #include "jsfun.h"
60 #include "jsgc.h"
61 #include "jsinterp.h"
62 #include "jsiter.h"
63 #include "jslock.h"
64 #include "jsnum.h"
65 #include "jsobj.h"
66 #include "jsopcode.h"
67 #include "jsscan.h"
68 #include "jsscope.h"
69 #include "jsscript.h"
70 #include "jsstr.h"
71 
72 #if JS_HAS_XML_SUPPORT
73 #include "jsxml.h"
74 #endif
75 
76 #ifdef DEBUG
77 #define ASSERT_CACHE_IS_EMPTY(cache)                                          \
78     JS_BEGIN_MACRO                                                            \
79         JSPropertyCacheEntry *end_, *pce_, entry_;                            \
80         JSPropertyCache *cache_ = (cache);                                    \
81         JS_ASSERT(cache_->empty);                                             \
82         end_ = &cache_->table[PROPERTY_CACHE_SIZE];                           \
83         for (pce_ = &cache_->table[0]; pce_ < end_; pce_++) {                 \
84             PCE_LOAD(cache_, pce_, entry_);                                   \
85             JS_ASSERT(!PCE_OBJECT(entry_));                                   \
86             JS_ASSERT(!PCE_PROPERTY(entry_));                                 \
87         }                                                                     \
88     JS_END_MACRO
89 #else
90 #define ASSERT_CACHE_IS_EMPTY(cache) ((void)0)
91 #endif
92 
93 void
js_FlushPropertyCache(JSContext * cx)94 js_FlushPropertyCache(JSContext *cx)
95 {
96     JSPropertyCache *cache;
97 
98     cache = &cx->runtime->propertyCache;
99     if (cache->empty) {
100         ASSERT_CACHE_IS_EMPTY(cache);
101         return;
102     }
103     memset(cache->table, 0, sizeof cache->table);
104     cache->empty = JS_TRUE;
105 #ifdef JS_PROPERTY_CACHE_METERING
106     cache->flushes++;
107 #endif
108 }
109 
110 void
js_DisablePropertyCache(JSContext * cx)111 js_DisablePropertyCache(JSContext *cx)
112 {
113     JS_ASSERT(!cx->runtime->propertyCache.disabled);
114     cx->runtime->propertyCache.disabled = JS_TRUE;
115 }
116 
117 void
js_EnablePropertyCache(JSContext * cx)118 js_EnablePropertyCache(JSContext *cx)
119 {
120     JS_ASSERT(cx->runtime->propertyCache.disabled);
121     ASSERT_CACHE_IS_EMPTY(&cx->runtime->propertyCache);
122     cx->runtime->propertyCache.disabled = JS_FALSE;
123 }
124 
125 /*
126  * Stack macros and functions.  These all use a local variable, jsval *sp, to
127  * point to the next free stack slot.  SAVE_SP must be called before any call
128  * to a function that may invoke the interpreter.  RESTORE_SP must be called
129  * only after return from js_Invoke, because only js_Invoke changes fp->sp.
130  */
131 #define PUSH(v)         (*sp++ = (v))
132 #define POP()           (*--sp)
133 #ifdef DEBUG
134 #define SAVE_SP(fp)                                                           \
135     (JS_ASSERT((fp)->script || !(fp)->spbase || (sp) == (fp)->spbase),        \
136      (fp)->sp = sp)
137 #else
138 #define SAVE_SP(fp)     ((fp)->sp = sp)
139 #endif
140 #define RESTORE_SP(fp)  (sp = (fp)->sp)
141 
142 /*
143  * SAVE_SP_AND_PC commits deferred stores of interpreter registers to their
144  * homes in fp, when calling out of the interpreter loop or threaded code.
145  * RESTORE_SP_AND_PC copies the other way, to update registers after a call
146  * to a subroutine that interprets a piece of the current script.
147  */
148 #define SAVE_SP_AND_PC(fp)      (SAVE_SP(fp), (fp)->pc = pc)
149 #define RESTORE_SP_AND_PC(fp)   (RESTORE_SP(fp), pc = (fp)->pc)
150 
151 /*
152  * Push the generating bytecode's pc onto the parallel pc stack that runs
153  * depth slots below the operands.
154  *
155  * NB: PUSH_OPND uses sp, depth, and pc from its lexical environment.  See
156  * js_Interpret for these local variables' declarations and uses.
157  */
158 #define PUSH_OPND(v)    (sp[-depth] = (jsval)pc, PUSH(v))
159 #define STORE_OPND(n,v) (sp[(n)-depth] = (jsval)pc, sp[n] = (v))
160 #define POP_OPND()      POP()
161 #define FETCH_OPND(n)   (sp[n])
162 
163 /*
164  * Push the jsdouble d using sp, depth, and pc from the lexical environment.
165  * Try to convert d to a jsint that fits in a jsval, otherwise GC-alloc space
166  * for it and push a reference.
167  */
168 #define STORE_NUMBER(cx, n, d)                                                \
169     JS_BEGIN_MACRO                                                            \
170         jsint i_;                                                             \
171         jsval v_;                                                             \
172                                                                               \
173         if (JSDOUBLE_IS_INT(d, i_) && INT_FITS_IN_JSVAL(i_)) {                \
174             v_ = INT_TO_JSVAL(i_);                                            \
175         } else {                                                              \
176             ok = js_NewDoubleValue(cx, d, &v_);                               \
177             if (!ok)                                                          \
178                 goto out;                                                     \
179         }                                                                     \
180         STORE_OPND(n, v_);                                                    \
181     JS_END_MACRO
182 
183 #define STORE_INT(cx, n, i)                                                   \
184     JS_BEGIN_MACRO                                                            \
185         jsval v_;                                                             \
186                                                                               \
187         if (INT_FITS_IN_JSVAL(i)) {                                           \
188             v_ = INT_TO_JSVAL(i);                                             \
189         } else {                                                              \
190             ok = js_NewDoubleValue(cx, (jsdouble)(i), &v_);                   \
191             if (!ok)                                                          \
192                 goto out;                                                     \
193         }                                                                     \
194         STORE_OPND(n, v_);                                                    \
195     JS_END_MACRO
196 
197 #define STORE_UINT(cx, n, u)                                                  \
198     JS_BEGIN_MACRO                                                            \
199         jsval v_;                                                             \
200                                                                               \
201         if ((u) <= JSVAL_INT_MAX) {                                           \
202             v_ = INT_TO_JSVAL(u);                                             \
203         } else {                                                              \
204             ok = js_NewDoubleValue(cx, (jsdouble)(u), &v_);                   \
205             if (!ok)                                                          \
206                 goto out;                                                     \
207         }                                                                     \
208         STORE_OPND(n, v_);                                                    \
209     JS_END_MACRO
210 
211 #define FETCH_NUMBER(cx, n, d)                                                \
212     JS_BEGIN_MACRO                                                            \
213         jsval v_;                                                             \
214                                                                               \
215         v_ = FETCH_OPND(n);                                                   \
216         VALUE_TO_NUMBER(cx, v_, d);                                           \
217     JS_END_MACRO
218 
219 #define FETCH_INT(cx, n, i)                                                   \
220     JS_BEGIN_MACRO                                                            \
221         jsval v_ = FETCH_OPND(n);                                             \
222         if (JSVAL_IS_INT(v_)) {                                               \
223             i = JSVAL_TO_INT(v_);                                             \
224         } else {                                                              \
225             SAVE_SP_AND_PC(fp);                                               \
226             ok = js_ValueToECMAInt32(cx, v_, &i);                             \
227             if (!ok)                                                          \
228                 goto out;                                                     \
229         }                                                                     \
230     JS_END_MACRO
231 
232 #define FETCH_UINT(cx, n, ui)                                                 \
233     JS_BEGIN_MACRO                                                            \
234         jsval v_ = FETCH_OPND(n);                                             \
235         jsint i_;                                                             \
236         if (JSVAL_IS_INT(v_) && (i_ = JSVAL_TO_INT(v_)) >= 0) {               \
237             ui = (uint32) i_;                                                 \
238         } else {                                                              \
239             SAVE_SP_AND_PC(fp);                                               \
240             ok = js_ValueToECMAUint32(cx, v_, &ui);                           \
241             if (!ok)                                                          \
242                 goto out;                                                     \
243         }                                                                     \
244     JS_END_MACRO
245 
246 /*
247  * Optimized conversion macros that test for the desired type in v before
248  * homing sp and calling a conversion function.
249  */
250 #define VALUE_TO_NUMBER(cx, v, d)                                             \
251     JS_BEGIN_MACRO                                                            \
252         if (JSVAL_IS_INT(v)) {                                                \
253             d = (jsdouble)JSVAL_TO_INT(v);                                    \
254         } else if (JSVAL_IS_DOUBLE(v)) {                                      \
255             d = *JSVAL_TO_DOUBLE(v);                                          \
256         } else {                                                              \
257             SAVE_SP_AND_PC(fp);                                               \
258             ok = js_ValueToNumber(cx, v, &d);                                 \
259             if (!ok)                                                          \
260                 goto out;                                                     \
261         }                                                                     \
262     JS_END_MACRO
263 
264 #define POP_BOOLEAN(cx, v, b)                                                 \
265     JS_BEGIN_MACRO                                                            \
266         v = FETCH_OPND(-1);                                                   \
267         if (v == JSVAL_NULL) {                                                \
268             b = JS_FALSE;                                                     \
269         } else if (JSVAL_IS_BOOLEAN(v)) {                                     \
270             b = JSVAL_TO_BOOLEAN(v);                                          \
271         } else {                                                              \
272             SAVE_SP_AND_PC(fp);                                               \
273             ok = js_ValueToBoolean(cx, v, &b);                                \
274             if (!ok)                                                          \
275                 goto out;                                                     \
276         }                                                                     \
277         sp--;                                                                 \
278     JS_END_MACRO
279 
280 /*
281  * Convert a primitive string, number or boolean to a corresponding object.
282  * v must not be an object, null or undefined when using this macro.
283  */
284 #define PRIMITIVE_TO_OBJECT(cx, v, obj)                                       \
285     JS_BEGIN_MACRO                                                            \
286         SAVE_SP(fp);                                                          \
287         if (JSVAL_IS_STRING(v)) {                                             \
288             obj = js_StringToObject(cx, JSVAL_TO_STRING(v));                  \
289         } else if (JSVAL_IS_INT(v)) {                                         \
290             obj = js_NumberToObject(cx, (jsdouble)JSVAL_TO_INT(v));           \
291         } else if (JSVAL_IS_DOUBLE(v)) {                                      \
292             obj = js_NumberToObject(cx, *JSVAL_TO_DOUBLE(v));                 \
293         } else {                                                              \
294             JS_ASSERT(JSVAL_IS_BOOLEAN(v));                                   \
295             obj = js_BooleanToObject(cx, JSVAL_TO_BOOLEAN(v));                \
296         }                                                                     \
297     JS_END_MACRO
298 
299 #define VALUE_TO_OBJECT(cx, v, obj)                                           \
300     JS_BEGIN_MACRO                                                            \
301         if (!JSVAL_IS_PRIMITIVE(v)) {                                         \
302             obj = JSVAL_TO_OBJECT(v);                                         \
303         } else {                                                              \
304             SAVE_SP_AND_PC(fp);                                               \
305             obj = js_ValueToNonNullObject(cx, v);                             \
306             if (!obj) {                                                       \
307                 ok = JS_FALSE;                                                \
308                 goto out;                                                     \
309             }                                                                 \
310         }                                                                     \
311     JS_END_MACRO
312 
313 #define FETCH_OBJECT(cx, n, v, obj)                                           \
314     JS_BEGIN_MACRO                                                            \
315         v = FETCH_OPND(n);                                                    \
316         VALUE_TO_OBJECT(cx, v, obj);                                          \
317         STORE_OPND(n, OBJECT_TO_JSVAL(obj));                                  \
318     JS_END_MACRO
319 
320 #define VALUE_TO_PRIMITIVE(cx, v, hint, vp)                                   \
321     JS_BEGIN_MACRO                                                            \
322         if (JSVAL_IS_PRIMITIVE(v)) {                                          \
323             *vp = v;                                                          \
324         } else {                                                              \
325             SAVE_SP_AND_PC(fp);                                               \
326             ok = OBJ_DEFAULT_VALUE(cx, JSVAL_TO_OBJECT(v), hint, vp);         \
327             if (!ok)                                                          \
328                 goto out;                                                     \
329         }                                                                     \
330     JS_END_MACRO
331 
332 JS_FRIEND_API(jsval *)
js_AllocRawStack(JSContext * cx,uintN nslots,void ** markp)333 js_AllocRawStack(JSContext *cx, uintN nslots, void **markp)
334 {
335     jsval *sp;
336 
337     if (markp)
338         *markp = JS_ARENA_MARK(&cx->stackPool);
339     JS_ARENA_ALLOCATE_CAST(sp, jsval *, &cx->stackPool, nslots * sizeof(jsval));
340     if (!sp) {
341         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_STACK_OVERFLOW,
342                              (cx->fp && cx->fp->fun)
343                              ? JS_GetFunctionName(cx->fp->fun)
344                              : "script");
345     }
346     return sp;
347 }
348 
349 JS_FRIEND_API(void)
js_FreeRawStack(JSContext * cx,void * mark)350 js_FreeRawStack(JSContext *cx, void *mark)
351 {
352     JS_ARENA_RELEASE(&cx->stackPool, mark);
353 }
354 
355 JS_FRIEND_API(jsval *)
js_AllocStack(JSContext * cx,uintN nslots,void ** markp)356 js_AllocStack(JSContext *cx, uintN nslots, void **markp)
357 {
358     jsval *sp, *vp, *end;
359     JSArena *a;
360     JSStackHeader *sh;
361     JSStackFrame *fp;
362 
363     /* Callers don't check for zero nslots: we do to avoid empty segments. */
364     if (nslots == 0) {
365         *markp = NULL;
366         return JS_ARENA_MARK(&cx->stackPool);
367     }
368 
369     /* Allocate 2 extra slots for the stack segment header we'll likely need. */
370     sp = js_AllocRawStack(cx, 2 + nslots, markp);
371     if (!sp)
372         return NULL;
373 
374     /* Try to avoid another header if we can piggyback on the last segment. */
375     a = cx->stackPool.current;
376     sh = cx->stackHeaders;
377     if (sh && JS_STACK_SEGMENT(sh) + sh->nslots == sp) {
378         /* Extend the last stack segment, give back the 2 header slots. */
379         sh->nslots += nslots;
380         a->avail -= 2 * sizeof(jsval);
381     } else {
382         /*
383          * Need a new stack segment, so we must initialize unused slots in the
384          * current frame.  See js_GC, just before marking the "operand" jsvals,
385          * where we scan from fp->spbase to fp->sp or through fp->script->depth
386          * (whichever covers fewer slots).
387          */
388         fp = cx->fp;
389         if (fp && fp->script && fp->spbase) {
390 #ifdef DEBUG
391             jsuword depthdiff = fp->script->depth * sizeof(jsval);
392             JS_ASSERT(JS_UPTRDIFF(fp->sp, fp->spbase) <= depthdiff);
393             JS_ASSERT(JS_UPTRDIFF(*markp, fp->spbase) >= depthdiff);
394 #endif
395             end = fp->spbase + fp->script->depth;
396             for (vp = fp->sp; vp < end; vp++)
397                 *vp = JSVAL_VOID;
398         }
399 
400         /* Allocate and push a stack segment header from the 2 extra slots. */
401         sh = (JSStackHeader *)sp;
402         sh->nslots = nslots;
403         sh->down = cx->stackHeaders;
404         cx->stackHeaders = sh;
405         sp += 2;
406     }
407 
408     /*
409      * Store JSVAL_NULL using memset, to let compilers optimize as they see
410      * fit, in case a caller allocates and pushes GC-things one by one, which
411      * could nest a last-ditch GC that will scan this segment.
412      */
413     memset(sp, 0, nslots * sizeof(jsval));
414     return sp;
415 }
416 
417 JS_FRIEND_API(void)
js_FreeStack(JSContext * cx,void * mark)418 js_FreeStack(JSContext *cx, void *mark)
419 {
420     JSStackHeader *sh;
421     jsuword slotdiff;
422 
423     /* Check for zero nslots allocation special case. */
424     if (!mark)
425         return;
426 
427     /* We can assert because js_FreeStack always balances js_AllocStack. */
428     sh = cx->stackHeaders;
429     JS_ASSERT(sh);
430 
431     /* If mark is in the current segment, reduce sh->nslots, else pop sh. */
432     slotdiff = JS_UPTRDIFF(mark, JS_STACK_SEGMENT(sh)) / sizeof(jsval);
433     if (slotdiff < (jsuword)sh->nslots)
434         sh->nslots = slotdiff;
435     else
436         cx->stackHeaders = sh->down;
437 
438     /* Release the stackPool space allocated since mark was set. */
439     JS_ARENA_RELEASE(&cx->stackPool, mark);
440 }
441 
442 JSBool
js_GetArgument(JSContext * cx,JSObject * obj,jsval id,jsval * vp)443 js_GetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
444 {
445     return JS_TRUE;
446 }
447 
448 JSBool
js_SetArgument(JSContext * cx,JSObject * obj,jsval id,jsval * vp)449 js_SetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
450 {
451     return JS_TRUE;
452 }
453 
454 JSBool
js_GetLocalVariable(JSContext * cx,JSObject * obj,jsval id,jsval * vp)455 js_GetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
456 {
457     return JS_TRUE;
458 }
459 
460 JSBool
js_SetLocalVariable(JSContext * cx,JSObject * obj,jsval id,jsval * vp)461 js_SetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
462 {
463     return JS_TRUE;
464 }
465 
466 JSObject *
js_GetScopeChain(JSContext * cx,JSStackFrame * fp)467 js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
468 {
469     JSObject *obj, *cursor, *clonedChild, *parent;
470     JSTempValueRooter tvr;
471 
472     obj = fp->blockChain;
473     if (!obj) {
474         /*
475          * Don't force a call object for a lightweight function call, but do
476          * insist that there is a call object for a heavyweight function call.
477          */
478         JS_ASSERT(!fp->fun ||
479                   !(fp->fun->flags & JSFUN_HEAVYWEIGHT) ||
480                   fp->callobj);
481         JS_ASSERT(fp->scopeChain);
482         return fp->scopeChain;
483     }
484 
485     /*
486      * We have one or more lexical scopes to reflect into fp->scopeChain, so
487      * make sure there's a call object at the current head of the scope chain,
488      * if this frame is a call frame.
489      */
490     if (fp->fun && !fp->callobj) {
491         JS_ASSERT(OBJ_GET_CLASS(cx, fp->scopeChain) != &js_BlockClass ||
492                   JS_GetPrivate(cx, fp->scopeChain) != fp);
493         if (!js_GetCallObject(cx, fp, fp->scopeChain))
494             return NULL;
495     }
496 
497     /*
498      * Clone the block chain. To avoid recursive cloning we set the parent of
499      * the cloned child after we clone the parent. In the following loop when
500      * clonedChild is null it indicates the first iteration when no special GC
501      * rooting is necessary. On the second and the following iterations we
502      * have to protect cloned so far chain against the GC during cloning of
503      * the cursor object.
504      */
505     cursor = obj;
506     clonedChild = NULL;
507     for (;;) {
508         parent = OBJ_GET_PARENT(cx, cursor);
509 
510         /*
511          * We pass fp->scopeChain and not null even if we override the parent
512          * slot later as null triggers useless calculations of slot's value in
513          * js_NewObject that js_CloneBlockObject calls.
514          */
515         cursor = js_CloneBlockObject(cx, cursor, fp->scopeChain, fp);
516         if (!cursor) {
517             if (clonedChild)
518                 JS_POP_TEMP_ROOT(cx, &tvr);
519             return NULL;
520         }
521         if (!clonedChild) {
522             /*
523              * The first iteration. Check if other follow and root obj if so
524              * to protect the whole cloned chain against GC.
525              */
526             obj = cursor;
527             if (!parent)
528                 break;
529             JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr);
530         } else {
531             /*
532              * Avoid OBJ_SET_PARENT overhead as clonedChild cannot escape to
533              * other threads.
534              */
535             clonedChild->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(cursor);
536             if (!parent) {
537                 JS_ASSERT(tvr.u.value == OBJECT_TO_JSVAL(obj));
538                 JS_POP_TEMP_ROOT(cx, &tvr);
539                 break;
540             }
541         }
542         clonedChild = cursor;
543         cursor = parent;
544     }
545     fp->flags |= JSFRAME_POP_BLOCKS;
546     fp->scopeChain = obj;
547     fp->blockChain = NULL;
548     return obj;
549 }
550 
551 /*
552  * Walk the scope chain looking for block scopes whose locals need to be
553  * copied from stack slots into object slots before fp goes away.
554  */
555 static JSBool
PutBlockObjects(JSContext * cx,JSStackFrame * fp)556 PutBlockObjects(JSContext *cx, JSStackFrame *fp)
557 {
558     JSBool ok;
559     JSObject *obj;
560 
561     ok = JS_TRUE;
562     for (obj = fp->scopeChain; obj; obj = OBJ_GET_PARENT(cx, obj)) {
563         if (OBJ_GET_CLASS(cx, obj) == &js_BlockClass) {
564             if (JS_GetPrivate(cx, obj) != fp)
565                 break;
566             ok &= js_PutBlockObject(cx, obj);
567         }
568     }
569     return ok;
570 }
571 
572 JSObject *
js_ComputeThis(JSContext * cx,JSObject * thisp,jsval * argv)573 js_ComputeThis(JSContext *cx, JSObject *thisp, jsval *argv)
574 {
575     if (thisp && OBJ_GET_CLASS(cx, thisp) != &js_CallClass) {
576         /* Some objects (e.g., With) delegate 'this' to another object. */
577         thisp = OBJ_THIS_OBJECT(cx, thisp);
578         if (!thisp)
579             return NULL;
580     } else {
581         /*
582          * ECMA requires "the global object", but in the presence of multiple
583          * top-level objects (windows, frames, or certain layers in the client
584          * object model), we prefer fun's parent.  An example that causes this
585          * code to run:
586          *
587          *   // in window w1
588          *   function f() { return this }
589          *   function g() { return f }
590          *
591          *   // in window w2
592          *   var h = w1.g()
593          *   alert(h() == w1)
594          *
595          * The alert should display "true".
596          */
597         if (JSVAL_IS_PRIMITIVE(argv[-2]) ||
598             !OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(argv[-2]))) {
599             thisp = cx->globalObject;
600         } else {
601             jsid id;
602             jsval v;
603             uintN attrs;
604 
605             /* Walk up the parent chain. */
606             thisp = JSVAL_TO_OBJECT(argv[-2]);
607             id = ATOM_TO_JSID(cx->runtime->atomState.parentAtom);
608             for (;;) {
609                 if (!OBJ_CHECK_ACCESS(cx, thisp, id, JSACC_PARENT, &v, &attrs))
610                     return NULL;
611                 if (JSVAL_IS_VOID(v))
612                     v = OBJ_GET_SLOT(cx, thisp, JSSLOT_PARENT);
613                 if (JSVAL_IS_NULL(v))
614                     break;
615                 thisp = JSVAL_TO_OBJECT(v);
616             }
617         }
618     }
619     argv[-1] = OBJECT_TO_JSVAL(thisp);
620     return thisp;
621 }
622 
623 #if JS_HAS_NO_SUCH_METHOD
624 
625 static JSBool
NoSuchMethod(JSContext * cx,JSStackFrame * fp,jsval * vp,uint32 flags,uintN argc)626 NoSuchMethod(JSContext *cx, JSStackFrame *fp, jsval *vp, uint32 flags,
627              uintN argc)
628 {
629     JSObject *thisp, *argsobj;
630     jsval *sp, roots[3];
631     JSTempValueRooter tvr;
632     jsid id;
633     JSBool ok;
634     jsbytecode *pc;
635     jsatomid atomIndex;
636 
637     /*
638      * We must call js_ComputeThis here to censor Call objects.  A performance
639      * hit, since we'll call it again in the normal sequence of invoke events,
640      * but at least it's idempotent.
641      *
642      * Normally, we call ComputeThis after all frame members have been set,
643      * and in particular, after any revision of the callee value at *vp  due
644      * to clasp->convert (see below).  This matters because ComputeThis may
645      * access *vp via fp->argv[-2], to follow the parent chain to a global
646      * object to use as the 'this' parameter.
647      *
648      * Obviously, here in the JSVAL_IS_PRIMITIVE(v) case, there can't be any
649      * such defaulting of 'this' to callee (v, *vp) ancestor.
650      */
651     JS_ASSERT(JSVAL_IS_PRIMITIVE(vp[0]));
652     RESTORE_SP(fp);
653     if (JSVAL_IS_OBJECT(vp[1])) {
654         thisp = JSVAL_TO_OBJECT(vp[1]);
655     } else {
656         PRIMITIVE_TO_OBJECT(cx, vp[1], thisp);
657         if (!thisp)
658             return JS_FALSE;
659         vp[1] = OBJECT_TO_JSVAL(thisp);
660     }
661     thisp = js_ComputeThis(cx, thisp, vp + 2);
662     if (!thisp)
663         return JS_FALSE;
664     vp[1] = OBJECT_TO_JSVAL(thisp);
665 
666     /* From here on, control must flow through label out: to return. */
667     memset(roots, 0, sizeof roots);
668     JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr);
669 
670     id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom);
671 #if JS_HAS_XML_SUPPORT
672     if (OBJECT_IS_XML(cx, thisp)) {
673         JSXMLObjectOps *ops;
674 
675         ops = (JSXMLObjectOps *) thisp->map->ops;
676         thisp = ops->getMethod(cx, thisp, id, &roots[2]);
677         if (!thisp) {
678             ok = JS_FALSE;
679             goto out;
680         }
681         vp[1] = OBJECT_TO_JSVAL(thisp);
682     } else
683 #endif
684     {
685         ok = OBJ_GET_PROPERTY(cx, thisp, id, &roots[2]);
686         if (!ok)
687             goto out;
688     }
689     if (JSVAL_IS_PRIMITIVE(roots[2]))
690         goto not_function;
691 
692     pc = (jsbytecode *) vp[-(intN)fp->script->depth];
693     switch ((JSOp) *pc) {
694       case JSOP_NAME:
695       case JSOP_GETPROP:
696 #if JS_HAS_XML_SUPPORT
697       case JSOP_GETMETHOD:
698 #endif
699         atomIndex = GET_ATOM_INDEX(pc);
700         roots[0] = ATOM_KEY(js_GetAtom(cx, &fp->script->atomMap, atomIndex));
701         argsobj = js_NewArrayObject(cx, argc, vp + 2);
702         if (!argsobj) {
703             ok = JS_FALSE;
704             goto out;
705         }
706         roots[1] = OBJECT_TO_JSVAL(argsobj);
707         ok = js_InternalInvoke(cx, thisp, roots[2], flags | JSINVOKE_INTERNAL,
708                                2, roots, &vp[0]);
709         break;
710 
711       default:
712         goto not_function;
713     }
714 
715   out:
716     JS_POP_TEMP_ROOT(cx, &tvr);
717     return ok;
718 
719   not_function:
720     js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_FUNFLAGS);
721     ok = JS_FALSE;
722     goto out;
723 }
724 
725 #endif /* JS_HAS_NO_SUCH_METHOD */
726 
727 #ifdef DUMP_CALL_TABLE
728 
729 #include "jsclist.h"
730 #include "jshash.h"
731 #include "jsdtoa.h"
732 
733 typedef struct CallKey {
734     jsval               callee;                 /* callee value */
735     const char          *filename;              /* function filename or null */
736     uintN               lineno;                 /* function lineno or 0 */
737 } CallKey;
738 
739 /* Compensate for typeof null == "object" brain damage. */
740 #define JSTYPE_NULL     JSTYPE_LIMIT
741 #define TYPEOF(cx,v)    (JSVAL_IS_NULL(v) ? JSTYPE_NULL : JS_TypeOfValue(cx,v))
742 #define TYPENAME(t)     (((t) == JSTYPE_NULL) ? js_null_str : js_type_str[t])
743 #define NTYPEHIST       (JSTYPE_LIMIT + 1)
744 
745 typedef struct CallValue {
746     uint32              total;                  /* total call count */
747     uint32              recycled;               /* LRU-recycled calls lost */
748     uint16              minargc;                /* minimum argument count */
749     uint16              maxargc;                /* maximum argument count */
750     struct ArgInfo {
751         uint32          typeHist[NTYPEHIST];    /* histogram by type */
752         JSCList         lruList;                /* top 10 values LRU list */
753         struct ArgValCount {
754             JSCList     lruLink;                /* LRU list linkage */
755             jsval       value;                  /* recently passed value */
756             uint32      count;                  /* number of times passed */
757             char        strbuf[112];            /* string conversion buffer */
758         } topValCounts[10];                     /* top 10 value storage */
759     } argInfo[8];
760 } CallValue;
761 
762 typedef struct CallEntry {
763     JSHashEntry         entry;
764     CallKey             key;
765     CallValue           value;
766     char                name[32];               /* function name copy */
767 } CallEntry;
768 
769 static void *
AllocCallTable(void * pool,size_t size)770 AllocCallTable(void *pool, size_t size)
771 {
772     return malloc(size);
773 }
774 
775 static void
FreeCallTable(void * pool,void * item)776 FreeCallTable(void *pool, void *item)
777 {
778     free(item);
779 }
780 
781 static JSHashEntry *
AllocCallEntry(void * pool,const void * key)782 AllocCallEntry(void *pool, const void *key)
783 {
784     return (JSHashEntry*) calloc(1, sizeof(CallEntry));
785 }
786 
787 static void
FreeCallEntry(void * pool,JSHashEntry * he,uintN flag)788 FreeCallEntry(void *pool, JSHashEntry *he, uintN flag)
789 {
790     JS_ASSERT(flag == HT_FREE_ENTRY);
791     free(he);
792 }
793 
794 static JSHashAllocOps callTableAllocOps = {
795     AllocCallTable, FreeCallTable,
796     AllocCallEntry, FreeCallEntry
797 };
798 
799 JS_STATIC_DLL_CALLBACK(JSHashNumber)
js_hash_call_key(const void * key)800 js_hash_call_key(const void *key)
801 {
802     CallKey *ck = (CallKey *) key;
803     JSHashNumber hash = (jsuword)ck->callee >> 3;
804 
805     if (ck->filename) {
806         hash = (hash << 4) ^ JS_HashString(ck->filename);
807         hash = (hash << 4) ^ ck->lineno;
808     }
809     return hash;
810 }
811 
812 JS_STATIC_DLL_CALLBACK(intN)
js_compare_call_keys(const void * k1,const void * k2)813 js_compare_call_keys(const void *k1, const void *k2)
814 {
815     CallKey *ck1 = (CallKey *)k1, *ck2 = (CallKey *)k2;
816 
817     return ck1->callee == ck2->callee &&
818            ((ck1->filename && ck2->filename)
819             ? strcmp(ck1->filename, ck2->filename) == 0
820             : ck1->filename == ck2->filename) &&
821            ck1->lineno == ck2->lineno;
822 }
823 
824 JSHashTable *js_CallTable;
825 size_t      js_LogCallToSourceLimit;
826 
827 JS_STATIC_DLL_CALLBACK(intN)
CallTableDumper(JSHashEntry * he,intN k,void * arg)828 CallTableDumper(JSHashEntry *he, intN k, void *arg)
829 {
830     CallEntry *ce = (CallEntry *)he;
831     FILE *fp = (FILE *)arg;
832     uintN argc, i, n;
833     struct ArgInfo *ai;
834     JSType save, type;
835     JSCList *cl;
836     struct ArgValCount *avc;
837     jsval argval;
838 
839     if (ce->key.filename) {
840         /* We're called at the end of the mark phase, so mark our filenames. */
841         js_MarkScriptFilename(ce->key.filename);
842         fprintf(fp, "%s:%u ", ce->key.filename, ce->key.lineno);
843     } else {
844         fprintf(fp, "@%p ", (void *) ce->key.callee);
845     }
846 
847     if (ce->name[0])
848         fprintf(fp, "name %s ", ce->name);
849     fprintf(fp, "calls %lu (%lu) argc %u/%u\n",
850             (unsigned long) ce->value.total,
851             (unsigned long) ce->value.recycled,
852             ce->value.minargc, ce->value.maxargc);
853 
854     argc = JS_MIN(ce->value.maxargc, 8);
855     for (i = 0; i < argc; i++) {
856         ai = &ce->value.argInfo[i];
857 
858         n = 0;
859         save = -1;
860         for (type = JSTYPE_VOID; type <= JSTYPE_LIMIT; type++) {
861             if (ai->typeHist[type]) {
862                 save = type;
863                 ++n;
864             }
865         }
866         if (n == 1) {
867             fprintf(fp, "  arg %u type %s: %lu\n",
868                     i, TYPENAME(save), (unsigned long) ai->typeHist[save]);
869         } else {
870             fprintf(fp, "  arg %u type histogram:\n", i);
871             for (type = JSTYPE_VOID; type <= JSTYPE_LIMIT; type++) {
872                 fprintf(fp, "  %9s: %8lu ",
873                        TYPENAME(type), (unsigned long) ai->typeHist[type]);
874                 for (n = (uintN) JS_HOWMANY(ai->typeHist[type], 10); n > 0; --n)
875                     fputc('*', fp);
876                 fputc('\n', fp);
877             }
878         }
879 
880         fprintf(fp, "  arg %u top 10 values:\n", i);
881         n = 1;
882         for (cl = ai->lruList.prev; cl != &ai->lruList; cl = cl->prev) {
883             avc = (struct ArgValCount *)cl;
884             if (!avc->count)
885                 break;
886             argval = avc->value;
887             fprintf(fp, "  %9u: %8lu %.*s (%#lx)\n",
888                     n, (unsigned long) avc->count,
889                     sizeof avc->strbuf, avc->strbuf, argval);
890             ++n;
891         }
892     }
893 
894     return HT_ENUMERATE_NEXT;
895 }
896 
897 void
js_DumpCallTable(JSContext * cx)898 js_DumpCallTable(JSContext *cx)
899 {
900     char name[24];
901     FILE *fp;
902     static uintN dumpCount;
903 
904     if (!js_CallTable)
905         return;
906 
907     JS_snprintf(name, sizeof name, "/tmp/calltable.dump.%u", dumpCount & 7);
908     dumpCount++;
909     fp = fopen(name, "w");
910     if (!fp)
911         return;
912 
913     JS_HashTableEnumerateEntries(js_CallTable, CallTableDumper, fp);
914     fclose(fp);
915 }
916 
917 static void
LogCall(JSContext * cx,jsval callee,uintN argc,jsval * argv)918 LogCall(JSContext *cx, jsval callee, uintN argc, jsval *argv)
919 {
920     CallKey key;
921     const char *name, *cstr;
922     JSFunction *fun;
923     JSHashNumber keyHash;
924     JSHashEntry **hep, *he;
925     CallEntry *ce;
926     uintN i, j;
927     jsval argval;
928     JSType type;
929     struct ArgInfo *ai;
930     struct ArgValCount *avc;
931     JSString *str;
932 
933     if (!js_CallTable) {
934         js_CallTable = JS_NewHashTable(1024, js_hash_call_key,
935                                        js_compare_call_keys, NULL,
936                                        &callTableAllocOps, NULL);
937         if (!js_CallTable)
938             return;
939     }
940 
941     key.callee = callee;
942     key.filename = NULL;
943     key.lineno = 0;
944     name = "";
945     if (VALUE_IS_FUNCTION(cx, callee)) {
946         fun = (JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(callee));
947         if (fun->atom)
948             name = js_AtomToPrintableString(cx, fun->atom);
949         if (FUN_INTERPRETED(fun)) {
950             key.filename = fun->u.i.script->filename;
951             key.lineno = fun->u.i.script->lineno;
952         }
953     }
954     keyHash = js_hash_call_key(&key);
955 
956     hep = JS_HashTableRawLookup(js_CallTable, keyHash, &key);
957     he = *hep;
958     if (he) {
959         ce = (CallEntry *) he;
960         JS_ASSERT(strncmp(ce->name, name, sizeof ce->name) == 0);
961     } else {
962         he = JS_HashTableRawAdd(js_CallTable, hep, keyHash, &key, NULL);
963         if (!he)
964             return;
965         ce = (CallEntry *) he;
966         ce->entry.key = &ce->key;
967         ce->entry.value = &ce->value;
968         ce->key = key;
969         for (i = 0; i < 8; i++) {
970             ai = &ce->value.argInfo[i];
971             JS_INIT_CLIST(&ai->lruList);
972             for (j = 0; j < 10; j++)
973                 JS_APPEND_LINK(&ai->topValCounts[j].lruLink, &ai->lruList);
974         }
975         strncpy(ce->name, name, sizeof ce->name);
976     }
977 
978     ++ce->value.total;
979     if (ce->value.minargc < argc)
980         ce->value.minargc = argc;
981     if (ce->value.maxargc < argc)
982         ce->value.maxargc = argc;
983     if (argc > 8)
984         argc = 8;
985     for (i = 0; i < argc; i++) {
986         ai = &ce->value.argInfo[i];
987         argval = argv[i];
988         type = TYPEOF(cx, argval);
989         ++ai->typeHist[type];
990 
991         for (j = 0; ; j++) {
992             if (j == 10) {
993                 avc = (struct ArgValCount *) ai->lruList.next;
994                 ce->value.recycled += avc->count;
995                 avc->value = argval;
996                 avc->count = 1;
997                 break;
998             }
999             avc = &ai->topValCounts[j];
1000             if (avc->value == argval) {
1001                 ++avc->count;
1002                 break;
1003             }
1004         }
1005 
1006         /* Move avc to the back of the LRU list. */
1007         JS_REMOVE_LINK(&avc->lruLink);
1008         JS_APPEND_LINK(&avc->lruLink, &ai->lruList);
1009 
1010         str = NULL;
1011         cstr = "";
1012         switch (TYPEOF(cx, argval)) {
1013           case JSTYPE_VOID:
1014             cstr = js_type_str[JSTYPE_VOID];
1015             break;
1016           case JSTYPE_NULL:
1017             cstr = js_null_str;
1018             break;
1019           case JSTYPE_BOOLEAN:
1020             cstr = js_boolean_str[JSVAL_TO_BOOLEAN(argval)];
1021             break;
1022           case JSTYPE_NUMBER:
1023             if (JSVAL_IS_INT(argval)) {
1024                 JS_snprintf(avc->strbuf, sizeof avc->strbuf, "%ld",
1025                             JSVAL_TO_INT(argval));
1026             } else {
1027                 JS_dtostr(avc->strbuf, sizeof avc->strbuf, DTOSTR_STANDARD, 0,
1028                           *JSVAL_TO_DOUBLE(argval));
1029             }
1030             continue;
1031           case JSTYPE_STRING:
1032             str = js_QuoteString(cx, JSVAL_TO_STRING(argval), (jschar)'"');
1033             break;
1034           case JSTYPE_FUNCTION:
1035             if (VALUE_IS_FUNCTION(cx, argval)) {
1036                 fun = (JSFunction *)JS_GetPrivate(cx, JSVAL_TO_OBJECT(argval));
1037                 if (fun && fun->atom) {
1038                     str = ATOM_TO_STRING(fun->atom);
1039                     break;
1040                 }
1041             }
1042             /* FALL THROUGH */
1043           case JSTYPE_OBJECT:
1044             js_LogCallToSourceLimit = sizeof avc->strbuf;
1045             cx->options |= JSOPTION_LOGCALL_TOSOURCE;
1046             str = js_ValueToSource(cx, argval);
1047             cx->options &= ~JSOPTION_LOGCALL_TOSOURCE;
1048             break;
1049         }
1050         if (str)
1051             cstr = JS_GetStringBytes(str);
1052         strncpy(avc->strbuf, cstr, sizeof avc->strbuf);
1053     }
1054 }
1055 
1056 #endif /* DUMP_CALL_TABLE */
1057 
1058 /*
1059  * Conditional assert to detect failure to clear a pending exception that is
1060  * suppressed (or unintentional suppression of a wanted exception).
1061  */
1062 #if defined DEBUG_brendan || defined DEBUG_mrbkap || defined DEBUG_shaver
1063 # define DEBUG_NOT_THROWING 1
1064 #endif
1065 
1066 #ifdef DEBUG_NOT_THROWING
1067 # define ASSERT_NOT_THROWING(cx) JS_ASSERT(!(cx)->throwing)
1068 #else
1069 # define ASSERT_NOT_THROWING(cx) /* nothing */
1070 #endif
1071 
1072 /*
1073  * Find a function reference and its 'this' object implicit first parameter
1074  * under argc arguments on cx's stack, and call the function.  Push missing
1075  * required arguments, allocate declared local variables, and pop everything
1076  * when done.  Then push the return value.
1077  */
1078 JS_FRIEND_API(JSBool)
js_Invoke(JSContext * cx,uintN argc,uintN flags)1079 js_Invoke(JSContext *cx, uintN argc, uintN flags)
1080 {
1081     void *mark;
1082     JSStackFrame *fp, frame;
1083     jsval *sp, *newsp, *limit;
1084     jsval *vp, v, thisv;
1085     JSObject *funobj, *parent, *thisp;
1086     JSBool ok;
1087     JSClass *clasp;
1088     JSObjectOps *ops;
1089     JSNative native;
1090     JSFunction *fun;
1091     JSScript *script;
1092     uintN nslots, nvars, nalloc, surplus;
1093     JSInterpreterHook hook;
1094     void *hookData;
1095 
1096     /* Mark the top of stack and load frequently-used registers. */
1097     mark = JS_ARENA_MARK(&cx->stackPool);
1098     fp = cx->fp;
1099     sp = fp->sp;
1100 
1101     /*
1102      * Set vp to the callee value's stack slot (it's where rval goes).
1103      * Once vp is set, control should flow through label out2: to return.
1104      * Set frame.rval early so native class and object ops can throw and
1105      * return false, causing a goto out2 with ok set to false.
1106      */
1107     vp = sp - (2 + argc);
1108     v = *vp;
1109     frame.rval = JSVAL_VOID;
1110 
1111     /*
1112      * A callee must be an object reference, unless its 'this' parameter
1113      * implements the __noSuchMethod__ method, in which case that method will
1114      * be called like so:
1115      *
1116      *   thisp.__noSuchMethod__(id, args)
1117      *
1118      * where id is the name of the method that this invocation attempted to
1119      * call by name, and args is an Array containing this invocation's actual
1120      * parameters.
1121      */
1122     if (JSVAL_IS_PRIMITIVE(v)) {
1123 #if JS_HAS_NO_SUCH_METHOD
1124         if (fp->script && !(flags & JSINVOKE_INTERNAL)) {
1125             ok = NoSuchMethod(cx, fp, vp, flags, argc);
1126             if (ok)
1127                 frame.rval = *vp;
1128             goto out2;
1129         }
1130 #endif
1131         goto bad;
1132     }
1133 
1134     /* Load thisv after potentially calling NoSuchMethod, which may set it. */
1135     thisv = vp[1];
1136 
1137     funobj = JSVAL_TO_OBJECT(v);
1138     parent = OBJ_GET_PARENT(cx, funobj);
1139     clasp = OBJ_GET_CLASS(cx, funobj);
1140     if (clasp != &js_FunctionClass) {
1141         /* Function is inlined, all other classes use object ops. */
1142         ops = funobj->map->ops;
1143 
1144         /*
1145          * XXX this makes no sense -- why convert to function if clasp->call?
1146          * XXX better to call that hook without converting
1147          * XXX the only thing that needs fixing is liveconnect
1148          *
1149          * Try converting to function, for closure and API compatibility.
1150          * We attempt the conversion under all circumstances for 1.2, but
1151          * only if there is a call op defined otherwise.
1152          */
1153         if ((ops == &js_ObjectOps) ? clasp->call : ops->call) {
1154             ok = clasp->convert(cx, funobj, JSTYPE_FUNCTION, &v);
1155             if (!ok)
1156                 goto out2;
1157 
1158             if (VALUE_IS_FUNCTION(cx, v)) {
1159                 /* Make vp refer to funobj to keep it available as argv[-2]. */
1160                 *vp = v;
1161                 funobj = JSVAL_TO_OBJECT(v);
1162                 parent = OBJ_GET_PARENT(cx, funobj);
1163                 goto have_fun;
1164             }
1165         }
1166         fun = NULL;
1167         script = NULL;
1168         nslots = nvars = 0;
1169 
1170         /* Try a call or construct native object op. */
1171         native = (flags & JSINVOKE_CONSTRUCT) ? ops->construct : ops->call;
1172         if (!native)
1173             goto bad;
1174 
1175         if (JSVAL_IS_OBJECT(thisv)) {
1176             thisp = JSVAL_TO_OBJECT(thisv);
1177         } else {
1178             PRIMITIVE_TO_OBJECT(cx, thisv, thisp);
1179             if (!thisp)
1180                 goto out2;
1181             vp[1] = thisv = OBJECT_TO_JSVAL(thisp);
1182         }
1183     } else {
1184 have_fun:
1185         /* Get private data and set derived locals from it. */
1186         fun = (JSFunction *) JS_GetPrivate(cx, funobj);
1187         nslots = (fun->nargs > argc) ? fun->nargs - argc : 0;
1188         if (FUN_INTERPRETED(fun)) {
1189             native = NULL;
1190             script = fun->u.i.script;
1191             nvars = fun->u.i.nvars;
1192         } else {
1193             native = fun->u.n.native;
1194             script = NULL;
1195             nvars = 0;
1196             nslots += fun->u.n.extra;
1197         }
1198 
1199         if (JSFUN_BOUND_METHOD_TEST(fun->flags)) {
1200             /* Handle bound method special case. */
1201             thisp = parent;
1202         } else if (JSVAL_IS_OBJECT(thisv)) {
1203             thisp = JSVAL_TO_OBJECT(thisv);
1204         } else {
1205             uintN thispflags = JSFUN_THISP_FLAGS(fun->flags);
1206 
1207             JS_ASSERT(!(flags & JSINVOKE_CONSTRUCT));
1208             if (JSVAL_IS_STRING(thisv)) {
1209                 if (JSFUN_THISP_TEST(thispflags, JSFUN_THISP_STRING)) {
1210                     thisp = (JSObject *) thisv;
1211                     goto init_frame;
1212                 }
1213                 thisp = js_StringToObject(cx, JSVAL_TO_STRING(thisv));
1214             } else if (JSVAL_IS_INT(thisv)) {
1215                 if (JSFUN_THISP_TEST(thispflags, JSFUN_THISP_NUMBER)) {
1216                     thisp = (JSObject *) thisv;
1217                     goto init_frame;
1218                 }
1219                 thisp = js_NumberToObject(cx, (jsdouble)JSVAL_TO_INT(thisv));
1220             } else if (JSVAL_IS_DOUBLE(thisv)) {
1221                 if (JSFUN_THISP_TEST(thispflags, JSFUN_THISP_NUMBER)) {
1222                     thisp = (JSObject *) thisv;
1223                     goto init_frame;
1224                 }
1225                 thisp = js_NumberToObject(cx, *JSVAL_TO_DOUBLE(thisv));
1226             } else {
1227                 JS_ASSERT(JSVAL_IS_BOOLEAN(thisv));
1228                 if (JSFUN_THISP_TEST(thispflags, JSFUN_THISP_BOOLEAN)) {
1229                     thisp = (JSObject *) thisv;
1230                     goto init_frame;
1231                 }
1232                 thisp = js_BooleanToObject(cx, JSVAL_TO_BOOLEAN(thisv));
1233             }
1234             if (!thisp) {
1235                 ok = JS_FALSE;
1236                 goto out2;
1237             }
1238             goto init_frame;
1239         }
1240     }
1241 
1242     if (flags & JSINVOKE_CONSTRUCT) {
1243         /* Default return value for a constructor is the new object. */
1244         frame.rval = OBJECT_TO_JSVAL(thisp);
1245     } else {
1246         thisp = js_ComputeThis(cx, thisp, vp + 2);
1247         if (!thisp) {
1248             ok = JS_FALSE;
1249             goto out2;
1250         }
1251     }
1252 
1253   init_frame:
1254     /* Initialize the rest of frame, except for sp (set by SAVE_SP later). */
1255     frame.thisp = thisp;
1256     frame.varobj = NULL;
1257     frame.callobj = frame.argsobj = NULL;
1258     frame.script = script;
1259     frame.fun = fun;
1260     frame.argc = argc;
1261     frame.argv = sp - argc;
1262     frame.nvars = nvars;
1263     frame.vars = sp;
1264     frame.down = fp;
1265     frame.annotation = NULL;
1266     frame.scopeChain = NULL;    /* set below for real, after cx->fp is set */
1267     frame.pc = NULL;
1268     frame.spbase = NULL;
1269     frame.sharpDepth = 0;
1270     frame.sharpArray = NULL;
1271     frame.flags = flags;
1272     frame.dormantNext = NULL;
1273     frame.xmlNamespace = NULL;
1274     frame.blockChain = NULL;
1275 
1276     /* From here on, control must flow through label out: to return. */
1277     cx->fp = &frame;
1278 
1279     /* Init these now in case we goto out before first hook call. */
1280     hook = cx->runtime->callHook;
1281     hookData = NULL;
1282 
1283     /* Check for argument slots required by the function. */
1284     if (nslots) {
1285         /* All arguments must be contiguous, so we may have to copy actuals. */
1286         nalloc = nslots;
1287         limit = (jsval *) cx->stackPool.current->limit;
1288         JS_ASSERT((jsval *) cx->stackPool.current->base <= sp && sp <= limit);
1289         if (sp + nslots > limit) {
1290             /* Hit end of arena: we have to copy argv[-2..(argc+nslots-1)]. */
1291             nalloc += 2 + argc;
1292         } else {
1293             /* Take advantage of surplus slots in the caller's frame depth. */
1294             JS_ASSERT((jsval *)mark >= sp);
1295             surplus = (jsval *)mark - sp;
1296             nalloc -= surplus;
1297         }
1298 
1299         /* Check whether we have enough space in the caller's frame. */
1300         if ((intN)nalloc > 0) {
1301             /* Need space for actuals plus missing formals minus surplus. */
1302             newsp = js_AllocRawStack(cx, nalloc, NULL);
1303             if (!newsp) {
1304                 ok = JS_FALSE;
1305                 goto out;
1306             }
1307 
1308             /* If we couldn't allocate contiguous args, copy actuals now. */
1309             if (newsp != mark) {
1310                 JS_ASSERT(sp + nslots > limit);
1311                 JS_ASSERT(2 + argc + nslots == nalloc);
1312                 *newsp++ = vp[0];
1313                 *newsp++ = vp[1];
1314                 if (argc)
1315                     memcpy(newsp, frame.argv, argc * sizeof(jsval));
1316                 frame.argv = newsp;
1317                 sp = frame.vars = newsp + argc;
1318             }
1319         }
1320 
1321         /* Advance frame.vars to make room for the missing args. */
1322         frame.vars += nslots;
1323 
1324         /* Push void to initialize missing args. */
1325         do {
1326             PUSH(JSVAL_VOID);
1327         } while (--nslots != 0);
1328     }
1329     JS_ASSERT(nslots == 0);
1330 
1331     /* Now allocate stack space for local variables. */
1332     if (nvars) {
1333         JS_ASSERT((jsval *)cx->stackPool.current->avail >= frame.vars);
1334         surplus = (jsval *)cx->stackPool.current->avail - frame.vars;
1335         if (surplus < nvars) {
1336             newsp = js_AllocRawStack(cx, nvars, NULL);
1337             if (!newsp) {
1338                 ok = JS_FALSE;
1339                 goto out;
1340             }
1341             if (newsp != sp) {
1342                 /* NB: Discontinuity between argv and vars. */
1343                 sp = frame.vars = newsp;
1344             }
1345         }
1346 
1347         /* Push void to initialize local variables. */
1348         do {
1349             PUSH(JSVAL_VOID);
1350         } while (--nvars != 0);
1351     }
1352     JS_ASSERT(nvars == 0);
1353 
1354     /* Store the current sp in frame before calling fun. */
1355     SAVE_SP(&frame);
1356 
1357     /* call the hook if present */
1358     if (hook && (native || script))
1359         hookData = hook(cx, &frame, JS_TRUE, 0, cx->runtime->callHookData);
1360 
1361     /* Call the function, either a native method or an interpreted script. */
1362     if (native) {
1363 #ifdef DEBUG_NOT_THROWING
1364         JSBool alreadyThrowing = cx->throwing;
1365 #endif
1366 
1367 #if JS_HAS_LVALUE_RETURN
1368         /* Set by JS_SetCallReturnValue2, used to return reference types. */
1369         cx->rval2set = JS_FALSE;
1370 #endif
1371 
1372         /* If native, use caller varobj and scopeChain for eval. */
1373         frame.varobj = fp->varobj;
1374         frame.scopeChain = fp->scopeChain;
1375         ok = native(cx, frame.thisp, argc, frame.argv, &frame.rval);
1376         JS_RUNTIME_METER(cx->runtime, nativeCalls);
1377 #ifdef DEBUG_NOT_THROWING
1378         if (ok && !alreadyThrowing)
1379             ASSERT_NOT_THROWING(cx);
1380 #endif
1381     } else if (script) {
1382 #ifdef DUMP_CALL_TABLE
1383         LogCall(cx, *vp, argc, frame.argv);
1384 #endif
1385         /* Use parent scope so js_GetCallObject can find the right "Call". */
1386         frame.scopeChain = parent;
1387         if (JSFUN_HEAVYWEIGHT_TEST(fun->flags)) {
1388             /* Scope with a call object parented by the callee's parent. */
1389             if (!js_GetCallObject(cx, &frame, parent)) {
1390                 ok = JS_FALSE;
1391                 goto out;
1392             }
1393         }
1394         ok = js_Interpret(cx, script->code, &v);
1395     } else {
1396         /* fun might be onerror trying to report a syntax error in itself. */
1397         frame.scopeChain = NULL;
1398         ok = JS_TRUE;
1399     }
1400 
1401 out:
1402     if (hookData) {
1403         hook = cx->runtime->callHook;
1404         if (hook)
1405             hook(cx, &frame, JS_FALSE, &ok, hookData);
1406     }
1407 
1408     /* If frame has a call object, sync values and clear back-pointer. */
1409     if (frame.callobj)
1410         ok &= js_PutCallObject(cx, &frame);
1411 
1412     /* If frame has an arguments object, sync values and clear back-pointer. */
1413     if (frame.argsobj)
1414         ok &= js_PutArgsObject(cx, &frame);
1415 
1416     /* Restore cx->fp now that we're done releasing frame objects. */
1417     cx->fp = fp;
1418 
1419 out2:
1420     /* Pop everything we may have allocated off the stack. */
1421     JS_ARENA_RELEASE(&cx->stackPool, mark);
1422 
1423     /* Store the return value and restore sp just above it. */
1424     *vp = frame.rval;
1425     fp->sp = vp + 1;
1426 
1427     /*
1428      * Store the location of the JSOP_CALL or JSOP_EVAL that generated the
1429      * return value, but only if this is an external (compiled from script
1430      * source) call that has stack budget for the generating pc.
1431      */
1432     if (fp->script && !(flags & JSINVOKE_INTERNAL))
1433         vp[-(intN)fp->script->depth] = (jsval)fp->pc;
1434     return ok;
1435 
1436 bad:
1437     js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_FUNFLAGS);
1438     ok = JS_FALSE;
1439     goto out2;
1440 }
1441 
1442 JSBool
js_InternalInvoke(JSContext * cx,JSObject * obj,jsval fval,uintN flags,uintN argc,jsval * argv,jsval * rval)1443 js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags,
1444                   uintN argc, jsval *argv, jsval *rval)
1445 {
1446     JSStackFrame *fp, *oldfp, frame;
1447     jsval *oldsp, *sp;
1448     void *mark;
1449     uintN i;
1450     JSBool ok;
1451 
1452     fp = oldfp = cx->fp;
1453     if (!fp) {
1454         memset(&frame, 0, sizeof frame);
1455         cx->fp = fp = &frame;
1456     }
1457     oldsp = fp->sp;
1458     sp = js_AllocStack(cx, 2 + argc, &mark);
1459     if (!sp) {
1460         ok = JS_FALSE;
1461         goto out;
1462     }
1463 
1464     PUSH(fval);
1465     PUSH(OBJECT_TO_JSVAL(obj));
1466     for (i = 0; i < argc; i++)
1467         PUSH(argv[i]);
1468     SAVE_SP(fp);
1469     ok = js_Invoke(cx, argc, flags | JSINVOKE_INTERNAL);
1470     if (ok) {
1471         RESTORE_SP(fp);
1472 
1473         /*
1474          * Store *rval in the a scoped local root if a scope is open, else in
1475          * the lastInternalResult pigeon-hole GC root, solely so users of
1476          * js_InternalInvoke and its direct and indirect (js_ValueToString for
1477          * example) callers do not need to manage roots for local, temporary
1478          * references to such results.
1479          */
1480         *rval = POP_OPND();
1481         if (JSVAL_IS_GCTHING(*rval)) {
1482             if (cx->localRootStack) {
1483                 if (js_PushLocalRoot(cx, cx->localRootStack, *rval) < 0)
1484                     ok = JS_FALSE;
1485             } else {
1486                 cx->weakRoots.lastInternalResult = *rval;
1487             }
1488         }
1489     }
1490 
1491     js_FreeStack(cx, mark);
1492 out:
1493     fp->sp = oldsp;
1494     if (oldfp != fp)
1495         cx->fp = oldfp;
1496 
1497     return ok;
1498 }
1499 
1500 JSBool
js_InternalGetOrSet(JSContext * cx,JSObject * obj,jsid id,jsval fval,JSAccessMode mode,uintN argc,jsval * argv,jsval * rval)1501 js_InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, jsval fval,
1502                     JSAccessMode mode, uintN argc, jsval *argv, jsval *rval)
1503 {
1504     int stackDummy;
1505 
1506     /*
1507      * js_InternalInvoke could result in another try to get or set the same id
1508      * again, see bug 355497.
1509      */
1510     if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) {
1511         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1512                              JSMSG_OVER_RECURSED);
1513         return JS_FALSE;
1514     }
1515     /*
1516      * Check general (not object-ops/class-specific) access from the running
1517      * script to obj.id only if id has a scripted getter or setter that we're
1518      * about to invoke.  If we don't check this case, nothing else will -- no
1519      * other native code has the chance to check.
1520      *
1521      * Contrast this non-native (scripted) case with native getter and setter
1522      * accesses, where the native itself must do an access check, if security
1523      * policies requires it.  We make a checkAccess or checkObjectAccess call
1524      * back to the embedding program only in those cases where we're not going
1525      * to call an embedding-defined native function, getter, setter, or class
1526      * hook anyway.  Where we do call such a native, there's no need for the
1527      * engine to impose a separate access check callback on all embeddings --
1528      * many embeddings have no security policy at all.
1529      */
1530     JS_ASSERT(mode == JSACC_READ || mode == JSACC_WRITE);
1531     if (cx->runtime->checkObjectAccess &&
1532         VALUE_IS_FUNCTION(cx, fval) &&
1533         FUN_INTERPRETED((JSFunction *)
1534                         JS_GetPrivate(cx, JSVAL_TO_OBJECT(fval))) &&
1535         !cx->runtime->checkObjectAccess(cx, obj, ID_TO_VALUE(id), mode,
1536                                         &fval)) {
1537         return JS_FALSE;
1538     }
1539 
1540     return js_InternalCall(cx, obj, fval, argc, argv, rval);
1541 }
1542 
1543 JSBool
js_Execute(JSContext * cx,JSObject * chain,JSScript * script,JSStackFrame * down,uintN flags,jsval * result)1544 js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
1545            JSStackFrame *down, uintN flags, jsval *result)
1546 {
1547     JSInterpreterHook hook;
1548     void *hookData, *mark;
1549     JSStackFrame *oldfp, frame;
1550     JSObject *obj, *tmp;
1551     JSBool ok;
1552 
1553     hook = cx->runtime->executeHook;
1554     hookData = mark = NULL;
1555     oldfp = cx->fp;
1556     frame.script = script;
1557     if (down) {
1558         /* Propagate arg/var state for eval and the debugger API. */
1559         frame.callobj = down->callobj;
1560         frame.argsobj = down->argsobj;
1561         frame.varobj = down->varobj;
1562         frame.fun = down->fun;
1563         frame.thisp = down->thisp;
1564         frame.argc = down->argc;
1565         frame.argv = down->argv;
1566         frame.nvars = down->nvars;
1567         frame.vars = down->vars;
1568         frame.annotation = down->annotation;
1569         frame.sharpArray = down->sharpArray;
1570     } else {
1571         frame.callobj = frame.argsobj = NULL;
1572         obj = chain;
1573         if (cx->options & JSOPTION_VAROBJFIX) {
1574             while ((tmp = OBJ_GET_PARENT(cx, obj)) != NULL)
1575                 obj = tmp;
1576         }
1577         frame.varobj = obj;
1578         frame.fun = NULL;
1579         frame.thisp = chain;
1580         frame.argc = 0;
1581         frame.argv = NULL;
1582         frame.nvars = script->numGlobalVars;
1583         if (frame.nvars) {
1584             frame.vars = js_AllocRawStack(cx, frame.nvars, &mark);
1585             if (!frame.vars)
1586                 return JS_FALSE;
1587             memset(frame.vars, 0, frame.nvars * sizeof(jsval));
1588         } else {
1589             frame.vars = NULL;
1590         }
1591         frame.annotation = NULL;
1592         frame.sharpArray = NULL;
1593     }
1594     frame.rval = JSVAL_VOID;
1595     frame.down = down;
1596     frame.scopeChain = chain;
1597     frame.pc = NULL;
1598     frame.sp = oldfp ? oldfp->sp : NULL;
1599     frame.spbase = NULL;
1600     frame.sharpDepth = 0;
1601     frame.flags = flags;
1602     frame.dormantNext = NULL;
1603     frame.xmlNamespace = NULL;
1604     frame.blockChain = NULL;
1605 
1606     /*
1607      * Here we wrap the call to js_Interpret with code to (conditionally)
1608      * save and restore the old stack frame chain into a chain of 'dormant'
1609      * frame chains.  Since we are replacing cx->fp, we were running into
1610      * the problem that if GC was called under this frame, some of the GC
1611      * things associated with the old frame chain (available here only in
1612      * the C variable 'oldfp') were not rooted and were being collected.
1613      *
1614      * So, now we preserve the links to these 'dormant' frame chains in cx
1615      * before calling js_Interpret and cleanup afterwards.  The GC walks
1616      * these dormant chains and marks objects in the same way that it marks
1617      * objects in the primary cx->fp chain.
1618      */
1619     if (oldfp && oldfp != down) {
1620         JS_ASSERT(!oldfp->dormantNext);
1621         oldfp->dormantNext = cx->dormantFrameChain;
1622         cx->dormantFrameChain = oldfp;
1623     }
1624 
1625     cx->fp = &frame;
1626     if (hook)
1627         hookData = hook(cx, &frame, JS_TRUE, 0, cx->runtime->executeHookData);
1628 
1629     /*
1630      * Use frame.rval, not result, so the last result stays rooted across any
1631      * GC activations nested within this js_Interpret.
1632      */
1633     ok = js_Interpret(cx, script->code, &frame.rval);
1634     *result = frame.rval;
1635 
1636     if (hookData) {
1637         hook = cx->runtime->executeHook;
1638         if (hook)
1639             hook(cx, &frame, JS_FALSE, &ok, hookData);
1640     }
1641     if (mark)
1642         js_FreeRawStack(cx, mark);
1643     cx->fp = oldfp;
1644 
1645     if (oldfp && oldfp != down) {
1646         JS_ASSERT(cx->dormantFrameChain == oldfp);
1647         cx->dormantFrameChain = oldfp->dormantNext;
1648         oldfp->dormantNext = NULL;
1649     }
1650 
1651     return ok;
1652 }
1653 
1654 #if JS_HAS_EXPORT_IMPORT
1655 /*
1656  * If id is JSVAL_VOID, import all exported properties from obj.
1657  */
1658 static JSBool
ImportProperty(JSContext * cx,JSObject * obj,jsid id)1659 ImportProperty(JSContext *cx, JSObject *obj, jsid id)
1660 {
1661     JSBool ok;
1662     JSIdArray *ida;
1663     JSProperty *prop;
1664     JSObject *obj2, *target, *funobj, *closure;
1665     JSString *str;
1666     uintN attrs;
1667     jsint i;
1668     jsval value;
1669 
1670     if (JSVAL_IS_VOID(id)) {
1671         ida = JS_Enumerate(cx, obj);
1672         if (!ida)
1673             return JS_FALSE;
1674         ok = JS_TRUE;
1675         if (ida->length == 0)
1676             goto out;
1677     } else {
1678         ida = NULL;
1679         if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
1680             return JS_FALSE;
1681         if (!prop) {
1682             str = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK,
1683                                              ID_TO_VALUE(id), NULL);
1684             if (str)
1685                 js_ReportIsNotDefined(cx, JS_GetStringBytes(str));
1686             return JS_FALSE;
1687         }
1688         ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, &attrs);
1689         OBJ_DROP_PROPERTY(cx, obj2, prop);
1690         if (!ok)
1691             return JS_FALSE;
1692         if (!(attrs & JSPROP_EXPORTED)) {
1693             str = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK,
1694                                              ID_TO_VALUE(id), NULL);
1695             if (str) {
1696                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1697                                      JSMSG_NOT_EXPORTED,
1698                                      JS_GetStringBytes(str));
1699             }
1700             return JS_FALSE;
1701         }
1702     }
1703 
1704     target = cx->fp->varobj;
1705     i = 0;
1706     do {
1707         if (ida) {
1708             id = ida->vector[i];
1709             ok = OBJ_GET_ATTRIBUTES(cx, obj, id, NULL, &attrs);
1710             if (!ok)
1711                 goto out;
1712             if (!(attrs & JSPROP_EXPORTED))
1713                 continue;
1714         }
1715         ok = OBJ_CHECK_ACCESS(cx, obj, id, JSACC_IMPORT, &value, &attrs);
1716         if (!ok)
1717             goto out;
1718         if (VALUE_IS_FUNCTION(cx, value)) {
1719             funobj = JSVAL_TO_OBJECT(value);
1720             closure = js_CloneFunctionObject(cx, funobj, obj);
1721             if (!closure) {
1722                 ok = JS_FALSE;
1723                 goto out;
1724             }
1725             value = OBJECT_TO_JSVAL(closure);
1726         }
1727 
1728         /*
1729          * Handle the case of importing a property that refers to a local
1730          * variable or formal parameter of a function activation.  These
1731          * properties are accessed by opcodes using stack slot numbers
1732          * generated by the compiler rather than runtime name-lookup.  These
1733          * local references, therefore, bypass the normal scope chain lookup.
1734          * So, instead of defining a new property in the activation object,
1735          * modify the existing value in the stack slot.
1736          */
1737         if (OBJ_GET_CLASS(cx, target) == &js_CallClass) {
1738             ok = OBJ_LOOKUP_PROPERTY(cx, target, id, &obj2, &prop);
1739             if (!ok)
1740                 goto out;
1741         } else {
1742             prop = NULL;
1743         }
1744         if (prop && target == obj2) {
1745             ok = OBJ_SET_PROPERTY(cx, target, id, &value);
1746         } else {
1747             ok = OBJ_DEFINE_PROPERTY(cx, target, id, value, NULL, NULL,
1748                                      attrs & ~(JSPROP_EXPORTED |
1749                                                JSPROP_GETTER |
1750                                                JSPROP_SETTER),
1751                                      NULL);
1752         }
1753         if (prop)
1754             OBJ_DROP_PROPERTY(cx, obj2, prop);
1755         if (!ok)
1756             goto out;
1757     } while (ida && ++i < ida->length);
1758 
1759 out:
1760     if (ida)
1761         JS_DestroyIdArray(cx, ida);
1762     return ok;
1763 }
1764 #endif /* JS_HAS_EXPORT_IMPORT */
1765 
1766 JSBool
js_CheckRedeclaration(JSContext * cx,JSObject * obj,jsid id,uintN attrs,JSObject ** objp,JSProperty ** propp)1767 js_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs,
1768                       JSObject **objp, JSProperty **propp)
1769 {
1770     JSObject *obj2;
1771     JSProperty *prop;
1772     uintN oldAttrs, report;
1773     JSBool isFunction;
1774     jsval value;
1775     const char *type, *name;
1776 
1777     if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
1778         return JS_FALSE;
1779     if (propp) {
1780         *objp = obj2;
1781         *propp = prop;
1782     }
1783     if (!prop)
1784         return JS_TRUE;
1785 
1786     /*
1787      * Use prop as a speedup hint to OBJ_GET_ATTRIBUTES, but drop it on error.
1788      * An assertion at label bad: will insist that it is null.
1789      */
1790     if (!OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &oldAttrs)) {
1791         OBJ_DROP_PROPERTY(cx, obj2, prop);
1792 #ifdef DEBUG
1793         prop = NULL;
1794 #endif
1795         goto bad;
1796     }
1797 
1798     /*
1799      * From here, return true, or else goto bad on failure to null out params.
1800      * If our caller doesn't want prop, drop it (we don't need it any longer).
1801      */
1802     if (!propp) {
1803         OBJ_DROP_PROPERTY(cx, obj2, prop);
1804         prop = NULL;
1805     }
1806 
1807     /* If either property is readonly, we have an error. */
1808     report = ((oldAttrs | attrs) & JSPROP_READONLY)
1809              ? JSREPORT_ERROR
1810              : JSREPORT_WARNING | JSREPORT_STRICT;
1811 
1812     if (report != JSREPORT_ERROR) {
1813         /*
1814          * Allow redeclaration of variables and functions, but insist that the
1815          * new value is not a getter if the old value was, ditto for setters --
1816          * unless prop is impermanent (in which case anyone could delete it and
1817          * redefine it, willy-nilly).
1818          */
1819         if (!(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
1820             return JS_TRUE;
1821         if ((~(oldAttrs ^ attrs) & (JSPROP_GETTER | JSPROP_SETTER)) == 0)
1822             return JS_TRUE;
1823         if (!(oldAttrs & JSPROP_PERMANENT))
1824             return JS_TRUE;
1825         report = JSREPORT_ERROR;
1826     }
1827 
1828     isFunction = (oldAttrs & (JSPROP_GETTER | JSPROP_SETTER)) != 0;
1829     if (!isFunction) {
1830         if (!OBJ_GET_PROPERTY(cx, obj, id, &value))
1831             goto bad;
1832         isFunction = VALUE_IS_FUNCTION(cx, value);
1833     }
1834     type = (oldAttrs & attrs & JSPROP_GETTER)
1835            ? js_getter_str
1836            : (oldAttrs & attrs & JSPROP_SETTER)
1837            ? js_setter_str
1838            : (oldAttrs & JSPROP_READONLY)
1839            ? js_const_str
1840            : isFunction
1841            ? js_function_str
1842            : js_var_str;
1843     name = js_AtomToPrintableString(cx, JSID_TO_ATOM(id));
1844     if (!name)
1845         goto bad;
1846     return JS_ReportErrorFlagsAndNumber(cx, report,
1847                                         js_GetErrorMessage, NULL,
1848                                         JSMSG_REDECLARED_VAR,
1849                                         type, name);
1850 
1851 bad:
1852     if (propp) {
1853         *objp = NULL;
1854         *propp = NULL;
1855     }
1856     JS_ASSERT(!prop);
1857     return JS_FALSE;
1858 }
1859 
1860 JSBool
js_StrictlyEqual(jsval lval,jsval rval)1861 js_StrictlyEqual(jsval lval, jsval rval)
1862 {
1863     jsval ltag = JSVAL_TAG(lval), rtag = JSVAL_TAG(rval);
1864     jsdouble ld, rd;
1865 
1866     if (ltag == rtag) {
1867         if (ltag == JSVAL_STRING) {
1868             JSString *lstr = JSVAL_TO_STRING(lval),
1869                      *rstr = JSVAL_TO_STRING(rval);
1870             return js_EqualStrings(lstr, rstr);
1871         }
1872         if (ltag == JSVAL_DOUBLE) {
1873             ld = *JSVAL_TO_DOUBLE(lval);
1874             rd = *JSVAL_TO_DOUBLE(rval);
1875             return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
1876         }
1877         return lval == rval;
1878     }
1879     if (ltag == JSVAL_DOUBLE && JSVAL_IS_INT(rval)) {
1880         ld = *JSVAL_TO_DOUBLE(lval);
1881         rd = JSVAL_TO_INT(rval);
1882         return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
1883     }
1884     if (JSVAL_IS_INT(lval) && rtag == JSVAL_DOUBLE) {
1885         ld = JSVAL_TO_INT(lval);
1886         rd = *JSVAL_TO_DOUBLE(rval);
1887         return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
1888     }
1889     return lval == rval;
1890 }
1891 
1892 JSBool
js_InvokeConstructor(JSContext * cx,jsval * vp,uintN argc)1893 js_InvokeConstructor(JSContext *cx, jsval *vp, uintN argc)
1894 {
1895     JSFunction *fun;
1896     JSObject *obj, *obj2, *proto, *parent;
1897     jsval lval, rval;
1898     JSClass *clasp, *funclasp;
1899 
1900     fun = NULL;
1901     obj2 = NULL;
1902     lval = *vp;
1903     if (!JSVAL_IS_OBJECT(lval) ||
1904         (obj2 = JSVAL_TO_OBJECT(lval)) == NULL ||
1905         /* XXX clean up to avoid special cases above ObjectOps layer */
1906         OBJ_GET_CLASS(cx, obj2) == &js_FunctionClass ||
1907         !obj2->map->ops->construct)
1908     {
1909         fun = js_ValueToFunction(cx, vp, JSV2F_CONSTRUCT);
1910         if (!fun)
1911             return JS_FALSE;
1912     }
1913 
1914     clasp = &js_ObjectClass;
1915     if (!obj2) {
1916         proto = parent = NULL;
1917         fun = NULL;
1918     } else {
1919         /*
1920          * Get the constructor prototype object for this function.
1921          * Use the nominal 'this' parameter slot, vp[1], as a local
1922          * root to protect this prototype, in case it has no other
1923          * strong refs.
1924          */
1925         if (!OBJ_GET_PROPERTY(cx, obj2,
1926                               ATOM_TO_JSID(cx->runtime->atomState
1927                                            .classPrototypeAtom),
1928                               &vp[1])) {
1929             return JS_FALSE;
1930         }
1931         rval = vp[1];
1932         proto = JSVAL_IS_OBJECT(rval) ? JSVAL_TO_OBJECT(rval) : NULL;
1933         parent = OBJ_GET_PARENT(cx, obj2);
1934 
1935         if (OBJ_GET_CLASS(cx, obj2) == &js_FunctionClass) {
1936             funclasp = ((JSFunction *)JS_GetPrivate(cx, obj2))->clasp;
1937             if (funclasp)
1938                 clasp = funclasp;
1939         }
1940     }
1941     obj = js_NewObject(cx, clasp, proto, parent);
1942     if (!obj)
1943         return JS_FALSE;
1944 
1945     /* Now we have an object with a constructor method; call it. */
1946     vp[1] = OBJECT_TO_JSVAL(obj);
1947     if (!js_Invoke(cx, argc, JSINVOKE_CONSTRUCT)) {
1948         cx->weakRoots.newborn[GCX_OBJECT] = NULL;
1949         return JS_FALSE;
1950     }
1951 
1952     /* Check the return value and if it's primitive, force it to be obj. */
1953     rval = *vp;
1954     if (JSVAL_IS_PRIMITIVE(rval)) {
1955         if (!fun) {
1956             /* native [[Construct]] returning primitive is error */
1957             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1958                                  JSMSG_BAD_NEW_RESULT,
1959                                  js_ValueToPrintableString(cx, rval));
1960             return JS_FALSE;
1961         }
1962         *vp = OBJECT_TO_JSVAL(obj);
1963     }
1964 
1965     JS_RUNTIME_METER(cx->runtime, constructs);
1966     return JS_TRUE;
1967 }
1968 
1969 static JSBool
InternStringElementId(JSContext * cx,jsval idval,jsid * idp)1970 InternStringElementId(JSContext *cx, jsval idval, jsid *idp)
1971 {
1972     JSAtom *atom;
1973 
1974     atom = js_ValueToStringAtom(cx, idval);
1975     if (!atom)
1976         return JS_FALSE;
1977     *idp = ATOM_TO_JSID(atom);
1978     return JS_TRUE;
1979 }
1980 
1981 static JSBool
InternNonIntElementId(JSContext * cx,jsval idval,jsid * idp)1982 InternNonIntElementId(JSContext *cx, jsval idval, jsid *idp)
1983 {
1984     JS_ASSERT(!JSVAL_IS_INT(idval));
1985 
1986 #if JS_HAS_XML_SUPPORT
1987     if (JSVAL_IS_OBJECT(idval)) {
1988         *idp = OBJECT_JSVAL_TO_JSID(idval);
1989         return JS_TRUE;
1990     }
1991 #endif
1992 
1993     return InternStringElementId(cx, idval, idp);
1994 }
1995 
1996 #if JS_HAS_XML_SUPPORT
1997 #define CHECK_ELEMENT_ID(obj, id)                                             \
1998     JS_BEGIN_MACRO                                                            \
1999         if (JSID_IS_OBJECT(id) && !OBJECT_IS_XML(cx, obj)) {                  \
2000             SAVE_SP_AND_PC(fp);                                               \
2001             ok = InternStringElementId(cx, OBJECT_JSID_TO_JSVAL(id), &id);    \
2002             if (!ok)                                                          \
2003                 goto out;                                                     \
2004         }                                                                     \
2005     JS_END_MACRO
2006 
2007 #else
2008 #define CHECK_ELEMENT_ID(obj, id)       JS_ASSERT(!JSID_IS_OBJECT(id))
2009 #endif
2010 
2011 #ifndef MAX_INTERP_LEVEL
2012 #if defined(XP_OS2)
2013 #define MAX_INTERP_LEVEL 250
2014 #else
2015 #define MAX_INTERP_LEVEL 1000
2016 #endif
2017 #endif
2018 
2019 #define MAX_INLINE_CALL_COUNT 1000
2020 
2021 /*
2022  * Threaded interpretation via computed goto appears to be well-supported by
2023  * GCC 3 and higher.  IBM's C compiler when run with the right options (e.g.,
2024  * -qlanglvl=extended) also supports threading.  Ditto the SunPro C compiler.
2025  * Currently it's broken for JS_VERSION < 160, though this isn't worth fixing.
2026  * Add your compiler support macros here.
2027  */
2028 #if JS_VERSION >= 160 && (                                                    \
2029     __GNUC__ >= 3 ||                                                          \
2030     (__IBMC__ >= 700 && defined __IBM_COMPUTED_GOTO) ||                       \
2031     __SUNPRO_C >= 0x570)
2032 # define JS_THREADED_INTERP 1
2033 #else
2034 # undef JS_THREADED_INTERP
2035 #endif
2036 
2037 JSBool
js_Interpret(JSContext * cx,jsbytecode * pc,jsval * result)2038 js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
2039 {
2040     JSRuntime *rt;
2041     JSStackFrame *fp;
2042     JSScript *script;
2043     uintN inlineCallCount;
2044     JSObject *obj, *obj2, *parent;
2045     JSVersion currentVersion, originalVersion;
2046     JSBranchCallback onbranch;
2047     JSBool ok, cond;
2048     JSTrapHandler interruptHandler;
2049     jsint depth, len;
2050     jsval *sp, *newsp;
2051     void *mark;
2052     jsbytecode *endpc, *pc2;
2053     JSOp op, op2;
2054     jsatomid atomIndex;
2055     JSAtom *atom;
2056     uintN argc, attrs, flags, slot;
2057     jsval *vp, lval, rval, ltmp, rtmp;
2058     jsid id;
2059     JSObject *withobj, *iterobj;
2060     JSProperty *prop;
2061     JSScopeProperty *sprop;
2062     JSString *str, *str2;
2063     jsint i, j;
2064     jsdouble d, d2;
2065     JSClass *clasp;
2066     JSFunction *fun;
2067     JSType type;
2068 #if !defined JS_THREADED_INTERP && defined DEBUG
2069     FILE *tracefp = NULL;
2070 #endif
2071 #if JS_HAS_EXPORT_IMPORT
2072     JSIdArray *ida;
2073 #endif
2074     jsint low, high, off, npairs;
2075     JSBool match;
2076 #if JS_HAS_GETTER_SETTER
2077     JSPropertyOp getter, setter;
2078 #endif
2079     int stackDummy;
2080 
2081 #ifdef __GNUC__
2082 # define JS_EXTENSION __extension__
2083 # define JS_EXTENSION_(s) __extension__ ({ s; })
2084 #else
2085 # define JS_EXTENSION
2086 # define JS_EXTENSION_(s) s
2087 #endif
2088 
2089 #ifdef JS_THREADED_INTERP
2090     static void *normalJumpTable[] = {
2091 # define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
2092         JS_EXTENSION &&L_##op,
2093 # include "jsopcode.tbl"
2094 # undef OPDEF
2095     };
2096 
2097     static void *interruptJumpTable[] = {
2098 # define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format)              \
2099         ((op != JSOP_PUSHOBJ)                                                 \
2100          ? JS_EXTENSION &&interrupt                                           \
2101          : JS_EXTENSION &&L_JSOP_PUSHOBJ),
2102 # include "jsopcode.tbl"
2103 # undef OPDEF
2104     };
2105 
2106     register void **jumpTable = normalJumpTable;
2107 
2108 # define DO_OP()            JS_EXTENSION_(goto *jumpTable[op])
2109 # define DO_NEXT_OP(n)      do { op = *(pc += (n)); DO_OP(); } while (0)
2110 # define BEGIN_CASE(OP)     L_##OP:
2111 # define END_CASE(OP)       DO_NEXT_OP(OP##_LENGTH);
2112 # define END_VARLEN_CASE    DO_NEXT_OP(len);
2113 # define EMPTY_CASE(OP)     BEGIN_CASE(OP) op = *++pc; DO_OP();
2114 #else
2115 # define DO_OP()            goto do_op
2116 # define DO_NEXT_OP(n)      goto advance_pc
2117 # define BEGIN_CASE(OP)     case OP:
2118 # define END_CASE(OP)       break;
2119 # define END_VARLEN_CASE    break;
2120 # define EMPTY_CASE(OP)     BEGIN_CASE(OP) END_CASE(OP)
2121 #endif
2122 
2123     *result = JSVAL_VOID;
2124     rt = cx->runtime;
2125 
2126     /* Set registerized frame pointer and derived script pointer. */
2127     fp = cx->fp;
2128     script = fp->script;
2129     JS_ASSERT(script->length != 0);
2130 
2131     /* Count of JS function calls that nest in this C js_Interpret frame. */
2132     inlineCallCount = 0;
2133 
2134     /*
2135      * Optimized Get and SetVersion for proper script language versioning.
2136      *
2137      * If any native method or JSClass/JSObjectOps hook calls js_SetVersion
2138      * and changes cx->version, the effect will "stick" and we will stop
2139      * maintaining currentVersion.  This is relied upon by testsuites, for
2140      * the most part -- web browsers select version before compiling and not
2141      * at run-time.
2142      */
2143     currentVersion = script->version;
2144     originalVersion = cx->version;
2145     if (currentVersion != originalVersion)
2146         js_SetVersion(cx, currentVersion);
2147 
2148 #ifdef __GNUC__
2149     flags = 0;  /* suppress gcc warnings */
2150     id = 0;
2151 #endif
2152 
2153     /*
2154      * Prepare to call a user-supplied branch handler, and abort the script
2155      * if it returns false.  We reload onbranch after calling out to native
2156      * functions (but not to getters, setters, or other native hooks).
2157      */
2158 #define LOAD_BRANCH_CALLBACK(cx)    (onbranch = (cx)->branchCallback)
2159 
2160     LOAD_BRANCH_CALLBACK(cx);
2161 #define CHECK_BRANCH(len)                                                     \
2162     JS_BEGIN_MACRO                                                            \
2163         if (len <= 0 && onbranch) {                                           \
2164             SAVE_SP_AND_PC(fp);                                               \
2165             if (!(ok = (*onbranch)(cx, script)))                              \
2166                 goto out;                                                     \
2167         }                                                                     \
2168     JS_END_MACRO
2169 
2170     /*
2171      * Load the debugger's interrupt hook here and after calling out to native
2172      * functions (but not to getters, setters, or other native hooks), so we do
2173      * not have to reload it each time through the interpreter loop -- we hope
2174      * the compiler can keep it in a register when it is non-null.
2175      */
2176 #ifdef JS_THREADED_INTERP
2177 # define LOAD_JUMP_TABLE()                                                    \
2178     (jumpTable = interruptHandler ? interruptJumpTable : normalJumpTable)
2179 #else
2180 # define LOAD_JUMP_TABLE()      /* nothing */
2181 #endif
2182 
2183 #define LOAD_INTERRUPT_HANDLER(rt)                                            \
2184     JS_BEGIN_MACRO                                                            \
2185         interruptHandler = (rt)->interruptHandler;                            \
2186         LOAD_JUMP_TABLE();                                                    \
2187     JS_END_MACRO
2188 
2189     LOAD_INTERRUPT_HANDLER(rt);
2190 
2191     /* Check for too much js_Interpret nesting, or too deep a C stack. */
2192     if (++cx->interpLevel == MAX_INTERP_LEVEL ||
2193         !JS_CHECK_STACK_SIZE(cx, stackDummy)) {
2194         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED);
2195         ok = JS_FALSE;
2196         goto out2;
2197     }
2198 
2199     /*
2200      * Allocate operand and pc stack slots for the script's worst-case depth,
2201      * unless we're called to interpret a part of an already active script, a
2202      * filtering predicate expression for example.
2203      */
2204     depth = (jsint) script->depth;
2205     if (JS_LIKELY(!fp->spbase)) {
2206         newsp = js_AllocRawStack(cx, (uintN)(2 * depth), &mark);
2207         if (!newsp) {
2208             ok = JS_FALSE;
2209             goto out2;
2210         }
2211         sp = newsp + depth;
2212         fp->spbase = sp;
2213         SAVE_SP(fp);
2214     } else {
2215         sp = fp->sp;
2216         JS_ASSERT(JS_UPTRDIFF(sp, fp->spbase) <= depth * sizeof(jsval));
2217         newsp = fp->spbase - depth;
2218         mark = NULL;
2219     }
2220 
2221     /*
2222      * To support generator_throw and to catch ignored exceptions, fail right
2223      * away if cx->throwing is set.  If no exception is pending, null obj in
2224      * case a callable object is being sent into a yield expression, and the
2225      * yield's result is invoked.
2226      */
2227     ok = !cx->throwing;
2228     if (!ok) {
2229 #ifdef DEBUG_NOT_THROWING
2230         printf("JS INTERPRETER CALLED WITH PENDING EXCEPTION %lx\n",
2231                (unsigned long) cx->exception);
2232 #endif
2233         goto out;
2234     }
2235     obj = NULL;
2236 
2237 #ifdef JS_THREADED_INTERP
2238 
2239     /*
2240      * This is a loop, but it does not look like a loop.  The loop-closing
2241      * jump is distributed throughout interruptJumpTable, and comes back to
2242      * the interrupt label.  The dispatch on op is through normalJumpTable.
2243      * The trick is LOAD_INTERRUPT_HANDLER setting jumpTable appropriately.
2244      *
2245      * It is important that "op" be initialized before the interrupt label
2246      * because it is possible for "op" to be specially assigned during the
2247      * normally processing of an opcode while looping (in particular, this
2248      * happens in JSOP_TRAP while debugging).  We rely on DO_NEXT_OP to
2249      * correctly manage "op" in all other cases.
2250      */
2251     op = (JSOp) *pc;
2252     if (interruptHandler) {
2253 interrupt:
2254         SAVE_SP_AND_PC(fp);
2255         switch (interruptHandler(cx, script, pc, &rval,
2256                                  rt->interruptHandlerData)) {
2257           case JSTRAP_ERROR:
2258             ok = JS_FALSE;
2259             goto out;
2260           case JSTRAP_CONTINUE:
2261             break;
2262           case JSTRAP_RETURN:
2263             fp->rval = rval;
2264             goto out;
2265           case JSTRAP_THROW:
2266             cx->throwing = JS_TRUE;
2267             cx->exception = rval;
2268             ok = JS_FALSE;
2269             goto out;
2270           default:;
2271         }
2272         LOAD_INTERRUPT_HANDLER(rt);
2273     }
2274 
2275     JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT);
2276     JS_EXTENSION_(goto *normalJumpTable[op]);
2277 
2278 #else  /* !JS_THREADED_INTERP */
2279 
2280     for (;;) {
2281         op = (JSOp) *pc;
2282       do_op:
2283         len = js_CodeSpec[op].length;
2284 
2285 #ifdef DEBUG
2286         tracefp = (FILE *) cx->tracefp;
2287         if (tracefp) {
2288             intN nuses, n;
2289 
2290             fprintf(tracefp, "%4u: ", js_PCToLineNumber(cx, script, pc));
2291             js_Disassemble1(cx, script, pc,
2292                             PTRDIFF(pc, script->code, jsbytecode), JS_FALSE,
2293                             tracefp);
2294             nuses = js_CodeSpec[op].nuses;
2295             if (nuses) {
2296                 SAVE_SP_AND_PC(fp);
2297                 for (n = -nuses; n < 0; n++) {
2298                     str = js_DecompileValueGenerator(cx, n, sp[n], NULL);
2299                     if (str) {
2300                         fprintf(tracefp, "%s %s",
2301                                 (n == -nuses) ? "  inputs:" : ",",
2302                                 JS_GetStringBytes(str));
2303                     }
2304                 }
2305                 fprintf(tracefp, " @ %d\n", sp - fp->spbase);
2306             }
2307         }
2308 #endif /* DEBUG */
2309 
2310         if (interruptHandler && op != JSOP_PUSHOBJ) {
2311             SAVE_SP_AND_PC(fp);
2312             switch (interruptHandler(cx, script, pc, &rval,
2313                                      rt->interruptHandlerData)) {
2314               case JSTRAP_ERROR:
2315                 ok = JS_FALSE;
2316                 goto out;
2317               case JSTRAP_CONTINUE:
2318                 break;
2319               case JSTRAP_RETURN:
2320                 fp->rval = rval;
2321                 goto out;
2322               case JSTRAP_THROW:
2323                 cx->throwing = JS_TRUE;
2324                 cx->exception = rval;
2325                 ok = JS_FALSE;
2326                 goto out;
2327               default:;
2328             }
2329             LOAD_INTERRUPT_HANDLER(rt);
2330         }
2331 
2332         switch (op) {
2333 
2334 #endif /* !JS_THREADED_INTERP */
2335 
2336           BEGIN_CASE(JSOP_STOP)
2337             goto out;
2338 
2339           EMPTY_CASE(JSOP_NOP)
2340 
2341           BEGIN_CASE(JSOP_GROUP)
2342             obj = NULL;
2343           END_CASE(JSOP_GROUP)
2344 
2345           BEGIN_CASE(JSOP_PUSH)
2346             PUSH_OPND(JSVAL_VOID);
2347           END_CASE(JSOP_PUSH)
2348 
2349           BEGIN_CASE(JSOP_POP)
2350             sp--;
2351           END_CASE(JSOP_POP)
2352 
2353           BEGIN_CASE(JSOP_POP2)
2354             sp -= 2;
2355           END_CASE(JSOP_POP2)
2356 
2357           BEGIN_CASE(JSOP_SWAP)
2358             vp = sp - depth;    /* swap generating pc's for the decompiler */
2359             ltmp = vp[-1];
2360             vp[-1] = vp[-2];
2361             sp[-2] = ltmp;
2362             rtmp = sp[-1];
2363             sp[-1] = sp[-2];
2364             sp[-2] = rtmp;
2365           END_CASE(JSOP_SWAP)
2366 
2367           BEGIN_CASE(JSOP_POPV)
2368             *result = POP_OPND();
2369           END_CASE(JSOP_POPV)
2370 
2371           BEGIN_CASE(JSOP_ENTERWITH)
2372             FETCH_OBJECT(cx, -1, rval, obj);
2373             SAVE_SP_AND_PC(fp);
2374             OBJ_TO_INNER_OBJECT(cx, obj);
2375             if (!obj || !(obj2 = js_GetScopeChain(cx, fp))) {
2376                 ok = JS_FALSE;
2377                 goto out;
2378             }
2379             withobj = js_NewWithObject(cx, obj, obj2, sp - fp->spbase - 1);
2380             if (!withobj) {
2381                 ok = JS_FALSE;
2382                 goto out;
2383             }
2384             fp->scopeChain = withobj;
2385             STORE_OPND(-1, OBJECT_TO_JSVAL(withobj));
2386           END_CASE(JSOP_ENTERWITH)
2387 
2388           BEGIN_CASE(JSOP_LEAVEWITH)
2389             rval = POP_OPND();
2390             JS_ASSERT(JSVAL_IS_OBJECT(rval));
2391             withobj = JSVAL_TO_OBJECT(rval);
2392             JS_ASSERT(OBJ_GET_CLASS(cx, withobj) == &js_WithClass);
2393             fp->scopeChain = OBJ_GET_PARENT(cx, withobj);
2394             JS_SetPrivate(cx, withobj, NULL);
2395           END_CASE(JSOP_LEAVEWITH)
2396 
2397           BEGIN_CASE(JSOP_SETRVAL)
2398             ASSERT_NOT_THROWING(cx);
2399             fp->rval = POP_OPND();
2400           END_CASE(JSOP_SETRVAL)
2401 
2402           BEGIN_CASE(JSOP_RETURN)
2403             CHECK_BRANCH(-1);
2404             fp->rval = POP_OPND();
2405             /* FALL THROUGH */
2406 
2407           BEGIN_CASE(JSOP_RETRVAL)    /* fp->rval already set */
2408             ASSERT_NOT_THROWING(cx);
2409             if (inlineCallCount)
2410           inline_return:
2411             {
2412                 JSInlineFrame *ifp = (JSInlineFrame *) fp;
2413                 void *hookData = ifp->hookData;
2414 
2415                 /*
2416                  * If fp has blocks on its scope chain, home their locals now,
2417                  * before calling any debugger hook, and before freeing stack.
2418                  * This matches the order of block putting and hook calling in
2419                  * the "out-of-line" return code at the bottom of js_Interpret
2420                  * and in js_Invoke.
2421                  */
2422                 if (fp->flags & JSFRAME_POP_BLOCKS) {
2423                     SAVE_SP_AND_PC(fp);
2424                     ok &= PutBlockObjects(cx, fp);
2425                 }
2426 
2427                 if (hookData) {
2428                     JSInterpreterHook hook = rt->callHook;
2429                     if (hook) {
2430                         SAVE_SP_AND_PC(fp);
2431                         hook(cx, fp, JS_FALSE, &ok, hookData);
2432                         LOAD_INTERRUPT_HANDLER(rt);
2433                     }
2434                 }
2435 
2436                 /*
2437                  * If fp has a call object, sync values and clear the back-
2438                  * pointer. This can happen for a lightweight function if it
2439                  * calls eval unexpectedly (in a way that is hidden from the
2440                  * compiler). See bug 325540.
2441                  */
2442                 if (fp->callobj) {
2443                     SAVE_SP_AND_PC(fp);
2444                     ok &= js_PutCallObject(cx, fp);
2445                 }
2446 
2447                 if (fp->argsobj) {
2448                     SAVE_SP_AND_PC(fp);
2449                     ok &= js_PutArgsObject(cx, fp);
2450                 }
2451 
2452                 /* Restore context version only if callee hasn't set version. */
2453                 if (JS_LIKELY(cx->version == currentVersion)) {
2454                     currentVersion = ifp->callerVersion;
2455                     if (currentVersion != cx->version)
2456                         js_SetVersion(cx, currentVersion);
2457                 }
2458 
2459                 /* Store the return value in the caller's operand frame. */
2460                 vp = ifp->rvp;
2461                 *vp = fp->rval;
2462 
2463                 /* Restore cx->fp and release the inline frame's space. */
2464                 cx->fp = fp = fp->down;
2465                 JS_ARENA_RELEASE(&cx->stackPool, ifp->mark);
2466 
2467                 /* Restore sp to point just above the return value. */
2468                 fp->sp = vp + 1;
2469                 RESTORE_SP(fp);
2470 
2471                 /* Restore the calling script's interpreter registers. */
2472                 obj = NULL;
2473                 script = fp->script;
2474                 depth = (jsint) script->depth;
2475                 pc = fp->pc;
2476 #ifndef JS_THREADED_INTERP
2477                 endpc = script->code + script->length;
2478 #endif
2479 
2480                 /* Store the generating pc for the return value. */
2481                 vp[-depth] = (jsval)pc;
2482 
2483                 /* Resume execution in the calling frame. */
2484                 inlineCallCount--;
2485                 if (JS_LIKELY(ok)) {
2486                     JS_ASSERT(js_CodeSpec[*pc].length == JSOP_CALL_LENGTH);
2487                     len = JSOP_CALL_LENGTH;
2488                     DO_NEXT_OP(len);
2489                 }
2490             }
2491             goto out;
2492 
2493           BEGIN_CASE(JSOP_DEFAULT)
2494             (void) POP();
2495             /* FALL THROUGH */
2496           BEGIN_CASE(JSOP_GOTO)
2497             len = GET_JUMP_OFFSET(pc);
2498             CHECK_BRANCH(len);
2499           END_VARLEN_CASE
2500 
2501           BEGIN_CASE(JSOP_IFEQ)
2502             POP_BOOLEAN(cx, rval, cond);
2503             if (cond == JS_FALSE) {
2504                 len = GET_JUMP_OFFSET(pc);
2505                 CHECK_BRANCH(len);
2506                 DO_NEXT_OP(len);
2507             }
2508           END_CASE(JSOP_IFEQ)
2509 
2510           BEGIN_CASE(JSOP_IFNE)
2511             POP_BOOLEAN(cx, rval, cond);
2512             if (cond != JS_FALSE) {
2513                 len = GET_JUMP_OFFSET(pc);
2514                 CHECK_BRANCH(len);
2515                 DO_NEXT_OP(len);
2516             }
2517           END_CASE(JSOP_IFNE)
2518 
2519           BEGIN_CASE(JSOP_OR)
2520             POP_BOOLEAN(cx, rval, cond);
2521             if (cond == JS_TRUE) {
2522                 len = GET_JUMP_OFFSET(pc);
2523                 PUSH_OPND(rval);
2524                 DO_NEXT_OP(len);
2525             }
2526           END_CASE(JSOP_OR)
2527 
2528           BEGIN_CASE(JSOP_AND)
2529             POP_BOOLEAN(cx, rval, cond);
2530             if (cond == JS_FALSE) {
2531                 len = GET_JUMP_OFFSET(pc);
2532                 PUSH_OPND(rval);
2533                 DO_NEXT_OP(len);
2534             }
2535           END_CASE(JSOP_AND)
2536 
2537           BEGIN_CASE(JSOP_DEFAULTX)
2538             (void) POP();
2539             /* FALL THROUGH */
2540           BEGIN_CASE(JSOP_GOTOX)
2541             len = GET_JUMPX_OFFSET(pc);
2542             CHECK_BRANCH(len);
2543           END_VARLEN_CASE
2544 
2545           BEGIN_CASE(JSOP_IFEQX)
2546             POP_BOOLEAN(cx, rval, cond);
2547             if (cond == JS_FALSE) {
2548                 len = GET_JUMPX_OFFSET(pc);
2549                 CHECK_BRANCH(len);
2550                 DO_NEXT_OP(len);
2551             }
2552           END_CASE(JSOP_IFEQX)
2553 
2554           BEGIN_CASE(JSOP_IFNEX)
2555             POP_BOOLEAN(cx, rval, cond);
2556             if (cond != JS_FALSE) {
2557                 len = GET_JUMPX_OFFSET(pc);
2558                 CHECK_BRANCH(len);
2559                 DO_NEXT_OP(len);
2560             }
2561           END_CASE(JSOP_IFNEX)
2562 
2563           BEGIN_CASE(JSOP_ORX)
2564             POP_BOOLEAN(cx, rval, cond);
2565             if (cond == JS_TRUE) {
2566                 len = GET_JUMPX_OFFSET(pc);
2567                 PUSH_OPND(rval);
2568                 DO_NEXT_OP(len);
2569             }
2570           END_CASE(JSOP_ORX)
2571 
2572           BEGIN_CASE(JSOP_ANDX)
2573             POP_BOOLEAN(cx, rval, cond);
2574             if (cond == JS_FALSE) {
2575                 len = GET_JUMPX_OFFSET(pc);
2576                 PUSH_OPND(rval);
2577                 DO_NEXT_OP(len);
2578             }
2579           END_CASE(JSOP_ANDX)
2580 
2581 /*
2582  * If the index value at sp[n] is not an int that fits in a jsval, it could
2583  * be an object (an XML QName, AttributeName, or AnyName), but only if we are
2584  * compiling with JS_HAS_XML_SUPPORT.  Otherwise convert the index value to a
2585  * string atom id.
2586  */
2587 #define FETCH_ELEMENT_ID(n, id)                                               \
2588     JS_BEGIN_MACRO                                                            \
2589         jsval idval_ = FETCH_OPND(n);                                         \
2590         if (JSVAL_IS_INT(idval_)) {                                           \
2591             id = INT_JSVAL_TO_JSID(idval_);                                   \
2592         } else {                                                              \
2593             SAVE_SP_AND_PC(fp);                                               \
2594             ok = InternNonIntElementId(cx, idval_, &id);                      \
2595             if (!ok)                                                          \
2596                 goto out;                                                     \
2597         }                                                                     \
2598     JS_END_MACRO
2599 
2600           BEGIN_CASE(JSOP_IN)
2601             SAVE_SP_AND_PC(fp);
2602             rval = FETCH_OPND(-1);
2603             if (JSVAL_IS_PRIMITIVE(rval)) {
2604                 str = js_DecompileValueGenerator(cx, -1, rval, NULL);
2605                 if (str) {
2606                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2607                                          JSMSG_IN_NOT_OBJECT,
2608                                          JS_GetStringBytes(str));
2609                 }
2610                 ok = JS_FALSE;
2611                 goto out;
2612             }
2613             obj = JSVAL_TO_OBJECT(rval);
2614             FETCH_ELEMENT_ID(-2, id);
2615             CHECK_ELEMENT_ID(obj, id);
2616             ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
2617             if (!ok)
2618                 goto out;
2619             sp--;
2620             STORE_OPND(-1, BOOLEAN_TO_JSVAL(prop != NULL));
2621             if (prop)
2622                 OBJ_DROP_PROPERTY(cx, obj2, prop);
2623           END_CASE(JSOP_IN)
2624 
2625           BEGIN_CASE(JSOP_FOREACH)
2626             flags = JSITER_ENUMERATE | JSITER_FOREACH;
2627             goto value_to_iter;
2628 
2629 #if JS_HAS_DESTRUCTURING
2630           BEGIN_CASE(JSOP_FOREACHKEYVAL)
2631             flags = JSITER_ENUMERATE | JSITER_FOREACH | JSITER_KEYVALUE;
2632             goto value_to_iter;
2633 #endif
2634 
2635           BEGIN_CASE(JSOP_FORIN)
2636             /*
2637              * Set JSITER_ENUMERATE to indicate that for-in loop should use
2638              * the enumeration protocol's iterator for compatibility if an
2639              * explicit iterator is not given via the optional __iterator__
2640              * method.
2641              */
2642             flags = JSITER_ENUMERATE;
2643 
2644           value_to_iter:
2645             JS_ASSERT(sp > fp->spbase);
2646             SAVE_SP_AND_PC(fp);
2647             ok = js_ValueToIterator(cx, flags, &sp[-1]);
2648             if (!ok)
2649                 goto out;
2650             JS_ASSERT(!JSVAL_IS_PRIMITIVE(sp[-1]));
2651             JS_ASSERT(JSOP_FORIN_LENGTH == js_CodeSpec[op].length);
2652           END_CASE(JSOP_FORIN)
2653 
2654           BEGIN_CASE(JSOP_FORPROP)
2655             /*
2656              * Handle JSOP_FORPROP first, so the cost of the goto do_forinloop
2657              * is not paid for the more common cases.
2658              */
2659             lval = FETCH_OPND(-1);
2660             atom = GET_ATOM(cx, script, pc);
2661             id   = ATOM_TO_JSID(atom);
2662             i = -2;
2663             goto do_forinloop;
2664 
2665           BEGIN_CASE(JSOP_FORNAME)
2666             atom = GET_ATOM(cx, script, pc);
2667             id   = ATOM_TO_JSID(atom);
2668 
2669             /*
2670              * ECMA 12.6.3 says to eval the LHS after looking for properties
2671              * to enumerate, and bail without LHS eval if there are no props.
2672              * We do Find here to share the most code at label do_forinloop.
2673              * If looking for enumerable properties could have side effects,
2674              * then we'd have to move this into the common code and condition
2675              * it on op == JSOP_FORNAME.
2676              */
2677             SAVE_SP_AND_PC(fp);
2678             ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
2679             if (!ok)
2680                 goto out;
2681             if (prop)
2682                 OBJ_DROP_PROPERTY(cx, obj2, prop);
2683             lval = OBJECT_TO_JSVAL(obj);
2684             /* FALL THROUGH */
2685 
2686           BEGIN_CASE(JSOP_FORARG)
2687           BEGIN_CASE(JSOP_FORVAR)
2688           BEGIN_CASE(JSOP_FORLOCAL)
2689             /*
2690              * JSOP_FORARG and JSOP_FORVAR don't require any lval computation
2691              * here, because they address slots on the stack (in fp->args and
2692              * fp->vars, respectively).  Same applies to JSOP_FORLOCAL, which
2693              * addresses fp->spbase.
2694              */
2695             /* FALL THROUGH */
2696 
2697           BEGIN_CASE(JSOP_FORELEM)
2698             /*
2699              * JSOP_FORELEM simply initializes or updates the iteration state
2700              * and leaves the index expression evaluation and assignment to the
2701              * enumerator until after the next property has been acquired, via
2702              * a JSOP_ENUMELEM bytecode.
2703              */
2704             i = -1;
2705 
2706           do_forinloop:
2707             /*
2708              * Reach under the top of stack to find our property iterator, a
2709              * JSObject that contains the iteration state.
2710              */
2711             JS_ASSERT(!JSVAL_IS_PRIMITIVE(sp[i]));
2712             iterobj = JSVAL_TO_OBJECT(sp[i]);
2713 
2714             SAVE_SP_AND_PC(fp);
2715             ok = js_CallIteratorNext(cx, iterobj, &rval);
2716             if (!ok)
2717                 goto out;
2718             if (rval == JSVAL_HOLE) {
2719                 rval = JSVAL_FALSE;
2720                 goto end_forinloop;
2721             }
2722 
2723             switch (op) {
2724               case JSOP_FORARG:
2725                 slot = GET_ARGNO(pc);
2726                 JS_ASSERT(slot < fp->fun->nargs);
2727                 fp->argv[slot] = rval;
2728                 break;
2729 
2730               case JSOP_FORVAR:
2731                 slot = GET_VARNO(pc);
2732                 JS_ASSERT(slot < fp->fun->u.i.nvars);
2733                 fp->vars[slot] = rval;
2734                 break;
2735 
2736               case JSOP_FORLOCAL:
2737                 slot = GET_UINT16(pc);
2738                 JS_ASSERT(slot < (uintN)depth);
2739                 vp = &fp->spbase[slot];
2740                 GC_POKE(cx, *vp);
2741                 *vp = rval;
2742                 break;
2743 
2744               case JSOP_FORELEM:
2745                 /* FORELEM is not a SET operation, it's more like BINDNAME. */
2746                 PUSH_OPND(rval);
2747                 break;
2748 
2749               default:
2750                 JS_ASSERT(op == JSOP_FORPROP || op == JSOP_FORNAME);
2751 
2752                 /* Convert lval to a non-null object containing id. */
2753                 VALUE_TO_OBJECT(cx, lval, obj);
2754                 if (op == JSOP_FORPROP)
2755                     STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
2756 
2757                 /* Set the variable obj[id] to refer to rval. */
2758                 fp->flags |= JSFRAME_ASSIGNING;
2759                 ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
2760                 fp->flags &= ~JSFRAME_ASSIGNING;
2761                 if (!ok)
2762                     goto out;
2763                 break;
2764             }
2765 
2766             /* Push true to keep looping through properties. */
2767             rval = JSVAL_TRUE;
2768 
2769           end_forinloop:
2770             sp += i + 1;
2771             PUSH_OPND(rval);
2772             len = js_CodeSpec[op].length;
2773             DO_NEXT_OP(len);
2774 
2775           BEGIN_CASE(JSOP_DUP)
2776             JS_ASSERT(sp > fp->spbase);
2777             vp = sp - 1;                /* address top of stack */
2778             rval = *vp;
2779             vp -= depth;                /* address generating pc */
2780             vp[1] = *vp;
2781             PUSH(rval);
2782           END_CASE(JSOP_DUP)
2783 
2784           BEGIN_CASE(JSOP_DUP2)
2785             JS_ASSERT(sp - 2 >= fp->spbase);
2786             vp = sp - 1;                /* address top of stack */
2787             lval = vp[-1];
2788             rval = *vp;
2789             vp -= depth;                /* address generating pc */
2790             vp[1] = vp[2] = *vp;
2791             PUSH(lval);
2792             PUSH(rval);
2793           END_CASE(JSOP_DUP2)
2794 
2795 #define PROPERTY_OP(n, call)                                                  \
2796     JS_BEGIN_MACRO                                                            \
2797         /* Fetch the left part and resolve it to a non-null object. */        \
2798         FETCH_OBJECT(cx, n, lval, obj);                                       \
2799                                                                               \
2800         /* Get or set the property, set ok false if error, true if success. */\
2801         SAVE_SP_AND_PC(fp);                                                   \
2802         call;                                                                 \
2803         if (!ok)                                                              \
2804             goto out;                                                         \
2805     JS_END_MACRO
2806 
2807 #define ELEMENT_OP(n, call)                                                   \
2808     JS_BEGIN_MACRO                                                            \
2809         /* Fetch the right part and resolve it to an internal id. */          \
2810         FETCH_ELEMENT_ID(n, id);                                              \
2811                                                                               \
2812         /* Fetch the left part and resolve it to a non-null object. */        \
2813         FETCH_OBJECT(cx, n - 1, lval, obj);                                   \
2814                                                                               \
2815         /* Ensure that id has a type suitable for use with obj. */            \
2816         CHECK_ELEMENT_ID(obj, id);                                            \
2817                                                                               \
2818         /* Get or set the element, set ok false if error, true if success. */ \
2819         SAVE_SP_AND_PC(fp);                                                   \
2820         call;                                                                 \
2821         if (!ok)                                                              \
2822             goto out;                                                         \
2823     JS_END_MACRO
2824 
2825 #define NATIVE_GET(cx,obj,pobj,sprop,vp)                                      \
2826     JS_BEGIN_MACRO                                                            \
2827         if (SPROP_HAS_STUB_GETTER(sprop)) {                                   \
2828             /* Fast path for Object instance properties. */                   \
2829             JS_ASSERT((sprop)->slot != SPROP_INVALID_SLOT ||                  \
2830                       !SPROP_HAS_STUB_SETTER(sprop));                         \
2831             *vp = ((sprop)->slot != SPROP_INVALID_SLOT)                       \
2832                   ? LOCKED_OBJ_GET_SLOT(pobj, (sprop)->slot)                  \
2833                   : JSVAL_VOID;                                               \
2834         } else {                                                              \
2835             SAVE_SP_AND_PC(fp);                                               \
2836             ok = js_NativeGet(cx, obj, pobj, sprop, vp);                      \
2837             if (!ok)                                                          \
2838                 goto out;                                                     \
2839         }                                                                     \
2840     JS_END_MACRO
2841 
2842 #define NATIVE_SET(cx,obj,sprop,vp)                                           \
2843     JS_BEGIN_MACRO                                                            \
2844         if (SPROP_HAS_STUB_SETTER(sprop) &&                                   \
2845             (sprop)->slot != SPROP_INVALID_SLOT) {                            \
2846             /* Fast path for Object instance properties. */                   \
2847             LOCKED_OBJ_SET_SLOT(obj, (sprop)->slot, *vp);                     \
2848         } else {                                                              \
2849             SAVE_SP_AND_PC(fp);                                               \
2850             ok = js_NativeSet(cx, obj, sprop, vp);                            \
2851             if (!ok)                                                          \
2852                 goto out;                                                     \
2853         }                                                                     \
2854     JS_END_MACRO
2855 
2856 /*
2857  * CACHED_GET and CACHED_SET use cx, obj, id, and rval from their callers'
2858  * environments.
2859  */
2860 #define CACHED_GET(call)                                                      \
2861     JS_BEGIN_MACRO                                                            \
2862         if (!OBJ_IS_NATIVE(obj)) {                                            \
2863             ok = call;                                                        \
2864         } else {                                                              \
2865             JS_LOCK_OBJ(cx, obj);                                             \
2866             PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, sprop);          \
2867             if (sprop) {                                                      \
2868                 NATIVE_GET(cx, obj, obj, sprop, &rval);                       \
2869                 JS_UNLOCK_OBJ(cx, obj);                                       \
2870             } else {                                                          \
2871                 JS_UNLOCK_OBJ(cx, obj);                                       \
2872                 ok = call;                                                    \
2873                 /* No fill here: js_GetProperty fills the cache. */           \
2874             }                                                                 \
2875         }                                                                     \
2876     JS_END_MACRO
2877 
2878 #define CACHED_SET(call)                                                      \
2879     JS_BEGIN_MACRO                                                            \
2880         if (!OBJ_IS_NATIVE(obj)) {                                            \
2881             ok = call;                                                        \
2882         } else {                                                              \
2883             JSScope *scope_;                                                  \
2884             JS_LOCK_OBJ(cx, obj);                                             \
2885             PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, sprop);          \
2886             if (sprop &&                                                      \
2887                 !(sprop->attrs & JSPROP_READONLY) &&                          \
2888                 (scope_ = OBJ_SCOPE(obj), !SCOPE_IS_SEALED(scope_))) {        \
2889                 NATIVE_SET(cx, obj, sprop, &rval);                            \
2890                 JS_UNLOCK_SCOPE(cx, scope_);                                  \
2891             } else {                                                          \
2892                 JS_UNLOCK_OBJ(cx, obj);                                       \
2893                 ok = call;                                                    \
2894                 /* No fill here: js_SetProperty writes through the cache. */  \
2895             }                                                                 \
2896         }                                                                     \
2897     JS_END_MACRO
2898 
2899 #define BEGIN_LITOPX_CASE(OP,PCOFF)                                           \
2900           BEGIN_CASE(OP)                                                      \
2901             pc2 = pc;                                                         \
2902             atomIndex = GET_ATOM_INDEX(pc + PCOFF);                           \
2903           do_##OP:                                                            \
2904             atom = js_GetAtom(cx, &script->atomMap, atomIndex);
2905 
2906 #define END_LITOPX_CASE(OP)                                                   \
2907           END_CASE(OP)
2908 
2909           BEGIN_LITOPX_CASE(JSOP_SETCONST, 0)
2910             obj = fp->varobj;
2911             rval = FETCH_OPND(-1);
2912             SAVE_SP_AND_PC(fp);
2913             ok = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval,
2914                                      NULL, NULL,
2915                                      JSPROP_ENUMERATE | JSPROP_PERMANENT |
2916                                      JSPROP_READONLY,
2917                                      NULL);
2918             if (!ok)
2919                 goto out;
2920             STORE_OPND(-1, rval);
2921           END_LITOPX_CASE(JSOP_SETCONST)
2922 
2923 #if JS_HAS_DESTRUCTURING
2924           BEGIN_CASE(JSOP_ENUMCONSTELEM)
2925             FETCH_ELEMENT_ID(-1, id);
2926             FETCH_OBJECT(cx, -2, lval, obj);
2927             CHECK_ELEMENT_ID(obj, id);
2928             rval = FETCH_OPND(-3);
2929             SAVE_SP_AND_PC(fp);
2930             ok = OBJ_DEFINE_PROPERTY(cx, obj, id, rval, NULL, NULL,
2931                                      JSPROP_ENUMERATE | JSPROP_PERMANENT |
2932                                      JSPROP_READONLY,
2933                                      NULL);
2934             if (!ok)
2935                 goto out;
2936             sp -= 3;
2937           END_CASE(JSOP_ENUMCONSTELEM)
2938 #endif
2939 
2940           BEGIN_LITOPX_CASE(JSOP_BINDNAME, 0)
2941             SAVE_SP_AND_PC(fp);
2942             obj = js_FindIdentifierBase(cx, ATOM_TO_JSID(atom));
2943             if (!obj) {
2944                 ok = JS_FALSE;
2945                 goto out;
2946             }
2947             PUSH_OPND(OBJECT_TO_JSVAL(obj));
2948           END_LITOPX_CASE(JSOP_BINDNAME)
2949 
2950           BEGIN_CASE(JSOP_SETNAME)
2951             atom = GET_ATOM(cx, script, pc);
2952             id   = ATOM_TO_JSID(atom);
2953             rval = FETCH_OPND(-1);
2954             lval = FETCH_OPND(-2);
2955             JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval));
2956             obj  = JSVAL_TO_OBJECT(lval);
2957             SAVE_SP_AND_PC(fp);
2958             CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval));
2959             if (!ok)
2960                 goto out;
2961             sp--;
2962             STORE_OPND(-1, rval);
2963             obj = NULL;
2964           END_CASE(JSOP_SETNAME)
2965 
2966 #define INTEGER_OP(OP, EXTRA_CODE)                                            \
2967     JS_BEGIN_MACRO                                                            \
2968         FETCH_INT(cx, -1, j);                                                 \
2969         FETCH_INT(cx, -2, i);                                                 \
2970         EXTRA_CODE                                                            \
2971         i = i OP j;                                                           \
2972         sp--;                                                                 \
2973         STORE_INT(cx, -1, i);                                                 \
2974     JS_END_MACRO
2975 
2976 #define BITWISE_OP(OP)          INTEGER_OP(OP, (void) 0;)
2977 #define SIGNED_SHIFT_OP(OP)     INTEGER_OP(OP, j &= 31;)
2978 
2979           BEGIN_CASE(JSOP_BITOR)
2980             BITWISE_OP(|);
2981           END_CASE(JSOP_BITOR)
2982 
2983           BEGIN_CASE(JSOP_BITXOR)
2984             BITWISE_OP(^);
2985           END_CASE(JSOP_BITXOR)
2986 
2987           BEGIN_CASE(JSOP_BITAND)
2988             BITWISE_OP(&);
2989           END_CASE(JSOP_BITAND)
2990 
2991 #define RELATIONAL_OP(OP)                                                     \
2992     JS_BEGIN_MACRO                                                            \
2993         rval = FETCH_OPND(-1);                                                \
2994         lval = FETCH_OPND(-2);                                                \
2995         /* Optimize for two int-tagged operands (typical loop control). */    \
2996         if ((lval & rval) & JSVAL_INT) {                                      \
2997             ltmp = lval ^ JSVAL_VOID;                                         \
2998             rtmp = rval ^ JSVAL_VOID;                                         \
2999             if (ltmp && rtmp) {                                               \
3000                 cond = JSVAL_TO_INT(lval) OP JSVAL_TO_INT(rval);              \
3001             } else {                                                          \
3002                 d  = ltmp ? JSVAL_TO_INT(lval) : *rt->jsNaN;                  \
3003                 d2 = rtmp ? JSVAL_TO_INT(rval) : *rt->jsNaN;                  \
3004                 cond = JSDOUBLE_COMPARE(d, OP, d2, JS_FALSE);                 \
3005             }                                                                 \
3006         } else {                                                              \
3007             VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_NUMBER, &lval);               \
3008             sp[-2] = lval;                                                    \
3009             VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_NUMBER, &rval);               \
3010             if (JSVAL_IS_STRING(lval) && JSVAL_IS_STRING(rval)) {             \
3011                 str  = JSVAL_TO_STRING(lval);                                 \
3012                 str2 = JSVAL_TO_STRING(rval);                                 \
3013                 cond = js_CompareStrings(str, str2) OP 0;                     \
3014             } else {                                                          \
3015                 VALUE_TO_NUMBER(cx, lval, d);                                 \
3016                 VALUE_TO_NUMBER(cx, rval, d2);                                \
3017                 cond = JSDOUBLE_COMPARE(d, OP, d2, JS_FALSE);                 \
3018             }                                                                 \
3019         }                                                                     \
3020         sp--;                                                                 \
3021         STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));                               \
3022     JS_END_MACRO
3023 
3024 /*
3025  * NB: These macros can't use JS_BEGIN_MACRO/JS_END_MACRO around their bodies
3026  * because they begin if/else chains, so callers must not put semicolons after
3027  * the call expressions!
3028  */
3029 #if JS_HAS_XML_SUPPORT
3030 #define XML_EQUALITY_OP(OP)                                                   \
3031     if ((ltmp == JSVAL_OBJECT &&                                              \
3032          (obj2 = JSVAL_TO_OBJECT(lval)) &&                                    \
3033          OBJECT_IS_XML(cx, obj2)) ||                                          \
3034         (rtmp == JSVAL_OBJECT &&                                              \
3035          (obj2 = JSVAL_TO_OBJECT(rval)) &&                                    \
3036          OBJECT_IS_XML(cx, obj2))) {                                          \
3037         JSXMLObjectOps *ops;                                                  \
3038                                                                               \
3039         ops = (JSXMLObjectOps *) obj2->map->ops;                              \
3040         if (obj2 == JSVAL_TO_OBJECT(rval))                                    \
3041             rval = lval;                                                      \
3042         SAVE_SP_AND_PC(fp);                                                   \
3043         ok = ops->equality(cx, obj2, rval, &cond);                            \
3044         if (!ok)                                                              \
3045             goto out;                                                         \
3046         cond = cond OP JS_TRUE;                                               \
3047     } else
3048 
3049 #define EXTENDED_EQUALITY_OP(OP)                                              \
3050     if (ltmp == JSVAL_OBJECT &&                                               \
3051         (obj2 = JSVAL_TO_OBJECT(lval)) &&                                     \
3052         ((clasp = OBJ_GET_CLASS(cx, obj2))->flags & JSCLASS_IS_EXTENDED)) {   \
3053         JSExtendedClass *xclasp;                                              \
3054                                                                               \
3055         xclasp = (JSExtendedClass *) clasp;                                   \
3056         SAVE_SP_AND_PC(fp);                                                   \
3057         ok = xclasp->equality(cx, obj2, rval, &cond);                         \
3058         if (!ok)                                                              \
3059             goto out;                                                         \
3060         cond = cond OP JS_TRUE;                                               \
3061     } else
3062 #else
3063 #define XML_EQUALITY_OP(OP)             /* nothing */
3064 #define EXTENDED_EQUALITY_OP(OP)        /* nothing */
3065 #endif
3066 
3067 #define EQUALITY_OP(OP, IFNAN)                                                \
3068     JS_BEGIN_MACRO                                                            \
3069         rval = FETCH_OPND(-1);                                                \
3070         lval = FETCH_OPND(-2);                                                \
3071         ltmp = JSVAL_TAG(lval);                                               \
3072         rtmp = JSVAL_TAG(rval);                                               \
3073         XML_EQUALITY_OP(OP)                                                   \
3074         if (ltmp == rtmp) {                                                   \
3075             if (ltmp == JSVAL_STRING) {                                       \
3076                 str  = JSVAL_TO_STRING(lval);                                 \
3077                 str2 = JSVAL_TO_STRING(rval);                                 \
3078                 cond = js_EqualStrings(str, str2) OP JS_TRUE;                 \
3079             } else if (ltmp == JSVAL_DOUBLE) {                                \
3080                 d  = *JSVAL_TO_DOUBLE(lval);                                  \
3081                 d2 = *JSVAL_TO_DOUBLE(rval);                                  \
3082                 cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN);                    \
3083             } else {                                                          \
3084                 EXTENDED_EQUALITY_OP(OP)                                      \
3085                 /* Handle all undefined (=>NaN) and int combinations. */      \
3086                 cond = lval OP rval;                                          \
3087             }                                                                 \
3088         } else {                                                              \
3089             if (JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval)) {                 \
3090                 cond = (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) OP 1;     \
3091             } else if (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) {          \
3092                 cond = 1 OP 0;                                                \
3093             } else {                                                          \
3094                 if (ltmp == JSVAL_OBJECT) {                                   \
3095                     VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_VOID, &sp[-2]);       \
3096                     lval = sp[-2];                                            \
3097                     ltmp = JSVAL_TAG(lval);                                   \
3098                 } else if (rtmp == JSVAL_OBJECT) {                            \
3099                     VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_VOID, &sp[-1]);       \
3100                     rval = sp[-1];                                            \
3101                     rtmp = JSVAL_TAG(rval);                                   \
3102                 }                                                             \
3103                 if (ltmp == JSVAL_STRING && rtmp == JSVAL_STRING) {           \
3104                     str  = JSVAL_TO_STRING(lval);                             \
3105                     str2 = JSVAL_TO_STRING(rval);                             \
3106                     cond = js_EqualStrings(str, str2) OP JS_TRUE;             \
3107                 } else {                                                      \
3108                     VALUE_TO_NUMBER(cx, lval, d);                             \
3109                     VALUE_TO_NUMBER(cx, rval, d2);                            \
3110                     cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN);                \
3111                 }                                                             \
3112             }                                                                 \
3113         }                                                                     \
3114         sp--;                                                                 \
3115         STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));                               \
3116     JS_END_MACRO
3117 
3118           BEGIN_CASE(JSOP_EQ)
3119             EQUALITY_OP(==, JS_FALSE);
3120           END_CASE(JSOP_EQ)
3121 
3122           BEGIN_CASE(JSOP_NE)
3123             EQUALITY_OP(!=, JS_TRUE);
3124           END_CASE(JSOP_NE)
3125 
3126 #define NEW_EQUALITY_OP(OP)                                                   \
3127     JS_BEGIN_MACRO                                                            \
3128         rval = FETCH_OPND(-1);                                                \
3129         lval = FETCH_OPND(-2);                                                \
3130         cond = js_StrictlyEqual(lval, rval) OP JS_TRUE;                       \
3131         sp--;                                                                 \
3132         STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));                               \
3133     JS_END_MACRO
3134 
3135           BEGIN_CASE(JSOP_NEW_EQ)
3136             NEW_EQUALITY_OP(==);
3137           END_CASE(JSOP_NEW_EQ)
3138 
3139           BEGIN_CASE(JSOP_NEW_NE)
3140             NEW_EQUALITY_OP(!=);
3141           END_CASE(JSOP_NEW_NE)
3142 
3143           BEGIN_CASE(JSOP_CASE)
3144             pc2 = (jsbytecode *) sp[-2-depth];
3145             NEW_EQUALITY_OP(==);
3146             (void) POP();
3147             if (cond) {
3148                 len = GET_JUMP_OFFSET(pc);
3149                 CHECK_BRANCH(len);
3150                 DO_NEXT_OP(len);
3151             }
3152             sp[-depth] = (jsval)pc2;
3153             PUSH(lval);
3154           END_CASE(JSOP_CASE)
3155 
3156           BEGIN_CASE(JSOP_CASEX)
3157             pc2 = (jsbytecode *) sp[-2-depth];
3158             NEW_EQUALITY_OP(==);
3159             (void) POP();
3160             if (cond) {
3161                 len = GET_JUMPX_OFFSET(pc);
3162                 CHECK_BRANCH(len);
3163                 DO_NEXT_OP(len);
3164             }
3165             sp[-depth] = (jsval)pc2;
3166             PUSH(lval);
3167           END_CASE(JSOP_CASEX)
3168 
3169           BEGIN_CASE(JSOP_LT)
3170             RELATIONAL_OP(<);
3171           END_CASE(JSOP_LT)
3172 
3173           BEGIN_CASE(JSOP_LE)
3174             RELATIONAL_OP(<=);
3175           END_CASE(JSOP_LE)
3176 
3177           BEGIN_CASE(JSOP_GT)
3178             RELATIONAL_OP(>);
3179           END_CASE(JSOP_GT)
3180 
3181           BEGIN_CASE(JSOP_GE)
3182             RELATIONAL_OP(>=);
3183           END_CASE(JSOP_GE)
3184 
3185 #undef EQUALITY_OP
3186 #undef RELATIONAL_OP
3187 
3188           BEGIN_CASE(JSOP_LSH)
3189             SIGNED_SHIFT_OP(<<);
3190           END_CASE(JSOP_LSH)
3191 
3192           BEGIN_CASE(JSOP_RSH)
3193             SIGNED_SHIFT_OP(>>);
3194           END_CASE(JSOP_RSH)
3195 
3196           BEGIN_CASE(JSOP_URSH)
3197           {
3198             uint32 u;
3199 
3200             FETCH_INT(cx, -1, j);
3201             FETCH_UINT(cx, -2, u);
3202             u >>= j & 31;
3203             sp--;
3204             STORE_UINT(cx, -1, u);
3205           }
3206           END_CASE(JSOP_URSH)
3207 
3208 #undef INTEGER_OP
3209 #undef BITWISE_OP
3210 #undef SIGNED_SHIFT_OP
3211 
3212           BEGIN_CASE(JSOP_ADD)
3213             rval = FETCH_OPND(-1);
3214             lval = FETCH_OPND(-2);
3215 #if JS_HAS_XML_SUPPORT
3216             if (!JSVAL_IS_PRIMITIVE(lval) &&
3217                 (obj2 = JSVAL_TO_OBJECT(lval), OBJECT_IS_XML(cx, obj2)) &&
3218                 VALUE_IS_XML(cx, rval)) {
3219                 JSXMLObjectOps *ops;
3220 
3221                 ops = (JSXMLObjectOps *) obj2->map->ops;
3222                 SAVE_SP_AND_PC(fp);
3223                 ok = ops->concatenate(cx, obj2, rval, &rval);
3224                 if (!ok)
3225                     goto out;
3226                 sp--;
3227                 STORE_OPND(-1, rval);
3228             } else
3229 #endif
3230             {
3231                 VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_VOID, &sp[-2]);
3232                 lval = sp[-2];
3233                 VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_VOID, &sp[-1]);
3234                 rval = sp[-1];
3235                 if ((cond = JSVAL_IS_STRING(lval)) || JSVAL_IS_STRING(rval)) {
3236                     SAVE_SP_AND_PC(fp);
3237                     if (cond) {
3238                         str = JSVAL_TO_STRING(lval);
3239                         ok = (str2 = js_ValueToString(cx, rval)) != NULL;
3240                         if (!ok)
3241                             goto out;
3242                         sp[-1] = STRING_TO_JSVAL(str2);
3243                     } else {
3244                         str2 = JSVAL_TO_STRING(rval);
3245                         ok = (str = js_ValueToString(cx, lval)) != NULL;
3246                         if (!ok)
3247                             goto out;
3248                         sp[-2] = STRING_TO_JSVAL(str);
3249                     }
3250                     str = js_ConcatStrings(cx, str, str2);
3251                     if (!str) {
3252                         ok = JS_FALSE;
3253                         goto out;
3254                     }
3255                     sp--;
3256                     STORE_OPND(-1, STRING_TO_JSVAL(str));
3257                 } else {
3258                     VALUE_TO_NUMBER(cx, lval, d);
3259                     VALUE_TO_NUMBER(cx, rval, d2);
3260                     d += d2;
3261                     sp--;
3262                     STORE_NUMBER(cx, -1, d);
3263                 }
3264             }
3265           END_CASE(JSOP_ADD)
3266 
3267 #define BINARY_OP(OP)                                                         \
3268     JS_BEGIN_MACRO                                                            \
3269         FETCH_NUMBER(cx, -1, d2);                                             \
3270         FETCH_NUMBER(cx, -2, d);                                              \
3271         d = d OP d2;                                                          \
3272         sp--;                                                                 \
3273         STORE_NUMBER(cx, -1, d);                                              \
3274     JS_END_MACRO
3275 
3276           BEGIN_CASE(JSOP_SUB)
3277             BINARY_OP(-);
3278           END_CASE(JSOP_SUB)
3279 
3280           BEGIN_CASE(JSOP_MUL)
3281             BINARY_OP(*);
3282           END_CASE(JSOP_MUL)
3283 
3284           BEGIN_CASE(JSOP_DIV)
3285             FETCH_NUMBER(cx, -1, d2);
3286             FETCH_NUMBER(cx, -2, d);
3287             sp--;
3288             if (d2 == 0) {
3289 #ifdef XP_WIN
3290                 /* XXX MSVC miscompiles such that (NaN == 0) */
3291                 if (JSDOUBLE_IS_NaN(d2))
3292                     rval = DOUBLE_TO_JSVAL(rt->jsNaN);
3293                 else
3294 #endif
3295                 if (d == 0 || JSDOUBLE_IS_NaN(d))
3296                     rval = DOUBLE_TO_JSVAL(rt->jsNaN);
3297                 else if ((JSDOUBLE_HI32(d) ^ JSDOUBLE_HI32(d2)) >> 31)
3298                     rval = DOUBLE_TO_JSVAL(rt->jsNegativeInfinity);
3299                 else
3300                     rval = DOUBLE_TO_JSVAL(rt->jsPositiveInfinity);
3301                 STORE_OPND(-1, rval);
3302             } else {
3303                 d /= d2;
3304                 STORE_NUMBER(cx, -1, d);
3305             }
3306           END_CASE(JSOP_DIV)
3307 
3308           BEGIN_CASE(JSOP_MOD)
3309             FETCH_NUMBER(cx, -1, d2);
3310             FETCH_NUMBER(cx, -2, d);
3311             sp--;
3312             if (d2 == 0) {
3313                 STORE_OPND(-1, DOUBLE_TO_JSVAL(rt->jsNaN));
3314             } else {
3315 #ifdef XP_WIN
3316               /* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
3317               if (!(JSDOUBLE_IS_FINITE(d) && JSDOUBLE_IS_INFINITE(d2)))
3318 #endif
3319                 d = fmod(d, d2);
3320                 STORE_NUMBER(cx, -1, d);
3321             }
3322           END_CASE(JSOP_MOD)
3323 
3324           BEGIN_CASE(JSOP_NOT)
3325             POP_BOOLEAN(cx, rval, cond);
3326             PUSH_OPND(BOOLEAN_TO_JSVAL(!cond));
3327           END_CASE(JSOP_NOT)
3328 
3329           BEGIN_CASE(JSOP_BITNOT)
3330             FETCH_INT(cx, -1, i);
3331             i = ~i;
3332             STORE_INT(cx, -1, i);
3333           END_CASE(JSOP_BITNOT)
3334 
3335           BEGIN_CASE(JSOP_NEG)
3336             /*
3337              * Optimize the case of an int-tagged operand by noting that
3338              * INT_FITS_IN_JSVAL(i) => INT_FITS_IN_JSVAL(-i) unless i is 0
3339              * when -i is the negative zero which is jsdouble.
3340              */
3341             rval = FETCH_OPND(-1);
3342             if (JSVAL_IS_INT(rval) && (i = JSVAL_TO_INT(rval)) != 0) {
3343                 i = -i;
3344                 JS_ASSERT(INT_FITS_IN_JSVAL(i));
3345                 rval = INT_TO_JSVAL(i);
3346             } else {
3347                 if (JSVAL_IS_DOUBLE(rval)) {
3348                     d = *JSVAL_TO_DOUBLE(rval);
3349                 } else {
3350                     SAVE_SP_AND_PC(fp);
3351                     ok = js_ValueToNumber(cx, rval, &d);
3352                     if (!ok)
3353                         goto out;
3354                 }
3355 #ifdef HPUX
3356                 /*
3357                  * Negation of a zero doesn't produce a negative
3358                  * zero on HPUX. Perform the operation by bit
3359                  * twiddling.
3360                  */
3361                 JSDOUBLE_HI32(d) ^= JSDOUBLE_HI32_SIGNBIT;
3362 #else
3363                 d = -d;
3364 #endif
3365                 ok = js_NewNumberValue(cx, d, &rval);
3366                 if (!ok)
3367                     goto out;
3368             }
3369             STORE_OPND(-1, rval);
3370           END_CASE(JSOP_NEG)
3371 
3372           BEGIN_CASE(JSOP_POS)
3373             rval = FETCH_OPND(-1);
3374             if (!JSVAL_IS_NUMBER(rval)) {
3375                 SAVE_SP_AND_PC(fp);
3376                 ok = js_ValueToNumber(cx, rval, &d);
3377                 if (!ok)
3378                     goto out;
3379                 ok = js_NewNumberValue(cx, d, &rval);
3380                 if (!ok)
3381                     goto out;
3382                 sp[-1] = rval;
3383             }
3384             sp[-1-depth] = (jsval)pc;
3385           END_CASE(JSOP_POS)
3386 
3387           BEGIN_CASE(JSOP_NEW)
3388             /* Get immediate argc and find the constructor function. */
3389             argc = GET_ARGC(pc);
3390 
3391           do_new:
3392             SAVE_SP_AND_PC(fp);
3393             vp = sp - (2 + argc);
3394             JS_ASSERT(vp >= fp->spbase);
3395 
3396             ok = js_InvokeConstructor(cx, vp, argc);
3397             if (!ok)
3398                 goto out;
3399             RESTORE_SP(fp);
3400             LOAD_BRANCH_CALLBACK(cx);
3401             LOAD_INTERRUPT_HANDLER(rt);
3402             obj = JSVAL_TO_OBJECT(*vp);
3403             len = js_CodeSpec[op].length;
3404             DO_NEXT_OP(len);
3405 
3406           BEGIN_CASE(JSOP_DELNAME)
3407             atom = GET_ATOM(cx, script, pc);
3408             id   = ATOM_TO_JSID(atom);
3409 
3410             SAVE_SP_AND_PC(fp);
3411             ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
3412             if (!ok)
3413                 goto out;
3414 
3415             /* ECMA says to return true if name is undefined or inherited. */
3416             rval = JSVAL_TRUE;
3417             if (prop) {
3418                 OBJ_DROP_PROPERTY(cx, obj2, prop);
3419                 ok = OBJ_DELETE_PROPERTY(cx, obj, id, &rval);
3420                 if (!ok)
3421                     goto out;
3422             }
3423             PUSH_OPND(rval);
3424           END_CASE(JSOP_DELNAME)
3425 
3426           BEGIN_CASE(JSOP_DELPROP)
3427             atom = GET_ATOM(cx, script, pc);
3428             id   = ATOM_TO_JSID(atom);
3429             PROPERTY_OP(-1, ok = OBJ_DELETE_PROPERTY(cx, obj, id, &rval));
3430             STORE_OPND(-1, rval);
3431           END_CASE(JSOP_DELPROP)
3432 
3433           BEGIN_CASE(JSOP_DELELEM)
3434             ELEMENT_OP(-1, ok = OBJ_DELETE_PROPERTY(cx, obj, id, &rval));
3435             sp--;
3436             STORE_OPND(-1, rval);
3437           END_CASE(JSOP_DELELEM)
3438 
3439           BEGIN_CASE(JSOP_TYPEOFEXPR)
3440           BEGIN_CASE(JSOP_TYPEOF)
3441             rval = FETCH_OPND(-1);
3442             SAVE_SP_AND_PC(fp);
3443             type = JS_TypeOfValue(cx, rval);
3444             atom = rt->atomState.typeAtoms[type];
3445             STORE_OPND(-1, ATOM_KEY(atom));
3446           END_CASE(JSOP_TYPEOF)
3447 
3448           BEGIN_CASE(JSOP_VOID)
3449             (void) POP_OPND();
3450             PUSH_OPND(JSVAL_VOID);
3451           END_CASE(JSOP_VOID)
3452 
3453           BEGIN_CASE(JSOP_INCNAME)
3454           BEGIN_CASE(JSOP_DECNAME)
3455           BEGIN_CASE(JSOP_NAMEINC)
3456           BEGIN_CASE(JSOP_NAMEDEC)
3457             atom = GET_ATOM(cx, script, pc);
3458             id   = ATOM_TO_JSID(atom);
3459 
3460             SAVE_SP_AND_PC(fp);
3461             ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
3462             if (!ok)
3463                 goto out;
3464             if (!prop)
3465                 goto atom_not_defined;
3466 
3467             OBJ_DROP_PROPERTY(cx, obj2, prop);
3468             lval = OBJECT_TO_JSVAL(obj);
3469             i = 0;
3470             goto do_incop;
3471 
3472           BEGIN_CASE(JSOP_INCPROP)
3473           BEGIN_CASE(JSOP_DECPROP)
3474           BEGIN_CASE(JSOP_PROPINC)
3475           BEGIN_CASE(JSOP_PROPDEC)
3476             atom = GET_ATOM(cx, script, pc);
3477             id   = ATOM_TO_JSID(atom);
3478             lval = FETCH_OPND(-1);
3479             i = -1;
3480             goto do_incop;
3481 
3482           BEGIN_CASE(JSOP_INCELEM)
3483           BEGIN_CASE(JSOP_DECELEM)
3484           BEGIN_CASE(JSOP_ELEMINC)
3485           BEGIN_CASE(JSOP_ELEMDEC)
3486             FETCH_ELEMENT_ID(-1, id);
3487             lval = FETCH_OPND(-2);
3488             i = -2;
3489 
3490           do_incop:
3491           {
3492             const JSCodeSpec *cs;
3493 
3494             VALUE_TO_OBJECT(cx, lval, obj);
3495             if (i < 0)
3496                 STORE_OPND(i, OBJECT_TO_JSVAL(obj));
3497             CHECK_ELEMENT_ID(obj, id);
3498 
3499             /* The operand must contain a number. */
3500             SAVE_SP_AND_PC(fp);
3501             CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval));
3502             if (!ok)
3503                 goto out;
3504 
3505             /* Preload for use in the if/else immediately below. */
3506             cs = &js_CodeSpec[op];
3507 
3508             /* The expression result goes in rtmp, the updated value in rval. */
3509             if (JSVAL_IS_INT(rval) &&
3510                 rval != INT_TO_JSVAL(JSVAL_INT_MIN) &&
3511                 rval != INT_TO_JSVAL(JSVAL_INT_MAX)) {
3512                 if (cs->format & JOF_POST) {
3513                     rtmp = rval;
3514                     (cs->format & JOF_INC) ? (rval += 2) : (rval -= 2);
3515                 } else {
3516                     (cs->format & JOF_INC) ? (rval += 2) : (rval -= 2);
3517                     rtmp = rval;
3518                 }
3519             } else {
3520 
3521 /*
3522  * Initially, rval contains the value to increment or decrement, which is not
3523  * yet converted.  As above, the expression result goes in rtmp, the updated
3524  * value goes in rval.  Our caller must set vp to point at a GC-rooted jsval
3525  * in which we home rtmp, to protect it from GC in case the unconverted rval
3526  * is not a number.
3527  */
3528 #define NONINT_INCREMENT_OP_MIDDLE()                                          \
3529     JS_BEGIN_MACRO                                                            \
3530         VALUE_TO_NUMBER(cx, rval, d);                                         \
3531         if (cs->format & JOF_POST) {                                          \
3532             rtmp = rval;                                                      \
3533             if (!JSVAL_IS_NUMBER(rtmp)) {                                     \
3534                 ok = js_NewNumberValue(cx, d, &rtmp);                         \
3535                 if (!ok)                                                      \
3536                     goto out;                                                 \
3537             }                                                                 \
3538             *vp = rtmp;                                                       \
3539             (cs->format & JOF_INC) ? d++ : d--;                               \
3540             ok = js_NewNumberValue(cx, d, &rval);                             \
3541         } else {                                                              \
3542             (cs->format & JOF_INC) ? ++d : --d;                               \
3543             ok = js_NewNumberValue(cx, d, &rval);                             \
3544             rtmp = rval;                                                      \
3545         }                                                                     \
3546         if (!ok)                                                              \
3547             goto out;                                                         \
3548     JS_END_MACRO
3549 
3550                 if (cs->format & JOF_POST) {
3551                     /*
3552                      * We must push early to protect the postfix increment
3553                      * or decrement result, if converted to a jsdouble from
3554                      * a non-number value, from GC nesting in the setter.
3555                      */
3556                     vp = sp;
3557                     PUSH(JSVAL_VOID);
3558                     SAVE_SP(fp);
3559                     --i;
3560                 }
3561 #ifdef __GNUC__
3562                 else vp = NULL; /* suppress bogus gcc warnings */
3563 #endif
3564 
3565                 NONINT_INCREMENT_OP_MIDDLE();
3566             }
3567 
3568             fp->flags |= JSFRAME_ASSIGNING;
3569             CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval));
3570             fp->flags &= ~JSFRAME_ASSIGNING;
3571             if (!ok)
3572                 goto out;
3573             sp += i;
3574             PUSH_OPND(rtmp);
3575             len = js_CodeSpec[op].length;
3576             DO_NEXT_OP(len);
3577           }
3578 
3579 /* NB: This macro doesn't use JS_BEGIN_MACRO/JS_END_MACRO around its body. */
3580 #define FAST_INCREMENT_OP(SLOT,COUNT,BASE,PRE,OPEQ,MINMAX)                    \
3581     slot = SLOT;                                                              \
3582     JS_ASSERT(slot < fp->fun->COUNT);                                         \
3583     vp = fp->BASE + slot;                                                     \
3584     rval = *vp;                                                               \
3585     if (!JSVAL_IS_INT(rval) || rval == INT_TO_JSVAL(JSVAL_INT_##MINMAX))      \
3586         goto do_nonint_fast_incop;                                            \
3587     PRE = rval;                                                               \
3588     rval OPEQ 2;                                                              \
3589     *vp = rval;                                                               \
3590     PUSH_OPND(PRE);                                                           \
3591     goto end_nonint_fast_incop
3592 
3593           BEGIN_CASE(JSOP_INCARG)
3594             FAST_INCREMENT_OP(GET_ARGNO(pc), nargs, argv, rval, +=, MAX);
3595           BEGIN_CASE(JSOP_DECARG)
3596             FAST_INCREMENT_OP(GET_ARGNO(pc), nargs, argv, rval, -=, MIN);
3597           BEGIN_CASE(JSOP_ARGINC)
3598             FAST_INCREMENT_OP(GET_ARGNO(pc), nargs, argv, rtmp, +=, MAX);
3599           BEGIN_CASE(JSOP_ARGDEC)
3600             FAST_INCREMENT_OP(GET_ARGNO(pc), nargs, argv, rtmp, -=, MIN);
3601 
3602           BEGIN_CASE(JSOP_INCVAR)
3603             FAST_INCREMENT_OP(GET_VARNO(pc), u.i.nvars, vars, rval, +=, MAX);
3604           BEGIN_CASE(JSOP_DECVAR)
3605             FAST_INCREMENT_OP(GET_VARNO(pc), u.i.nvars, vars, rval, -=, MIN);
3606           BEGIN_CASE(JSOP_VARINC)
3607             FAST_INCREMENT_OP(GET_VARNO(pc), u.i.nvars, vars, rtmp, +=, MAX);
3608           BEGIN_CASE(JSOP_VARDEC)
3609             FAST_INCREMENT_OP(GET_VARNO(pc), u.i.nvars, vars, rtmp, -=, MIN);
3610 
3611           end_nonint_fast_incop:
3612             len = JSOP_INCARG_LENGTH;   /* all fast incops are same length */
3613             DO_NEXT_OP(len);
3614 
3615 #undef FAST_INCREMENT_OP
3616 
3617           do_nonint_fast_incop:
3618           {
3619             const JSCodeSpec *cs = &js_CodeSpec[op];
3620 
3621             NONINT_INCREMENT_OP_MIDDLE();
3622             *vp = rval;
3623             PUSH_OPND(rtmp);
3624             len = cs->length;
3625             DO_NEXT_OP(len);
3626           }
3627 
3628 /* NB: This macro doesn't use JS_BEGIN_MACRO/JS_END_MACRO around its body. */
3629 #define FAST_GLOBAL_INCREMENT_OP(SLOWOP,PRE,OPEQ,MINMAX)                      \
3630     slot = GET_VARNO(pc);                                                     \
3631     JS_ASSERT(slot < fp->nvars);                                              \
3632     lval = fp->vars[slot];                                                    \
3633     if (JSVAL_IS_NULL(lval)) {                                                \
3634         op = SLOWOP;                                                          \
3635         DO_OP();                                                              \
3636     }                                                                         \
3637     slot = JSVAL_TO_INT(lval);                                                \
3638     obj = fp->varobj;                                                         \
3639     rval = OBJ_GET_SLOT(cx, obj, slot);                                       \
3640     if (!JSVAL_IS_INT(rval) || rval == INT_TO_JSVAL(JSVAL_INT_##MINMAX))      \
3641         goto do_nonint_fast_global_incop;                                     \
3642     PRE = rval;                                                               \
3643     rval OPEQ 2;                                                              \
3644     OBJ_SET_SLOT(cx, obj, slot, rval);                                        \
3645     PUSH_OPND(PRE);                                                           \
3646     goto end_nonint_fast_global_incop
3647 
3648           BEGIN_CASE(JSOP_INCGVAR)
3649             FAST_GLOBAL_INCREMENT_OP(JSOP_INCNAME, rval, +=, MAX);
3650           BEGIN_CASE(JSOP_DECGVAR)
3651             FAST_GLOBAL_INCREMENT_OP(JSOP_DECNAME, rval, -=, MIN);
3652           BEGIN_CASE(JSOP_GVARINC)
3653             FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEINC, rtmp, +=, MAX);
3654           BEGIN_CASE(JSOP_GVARDEC)
3655             FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEDEC, rtmp, -=, MIN);
3656 
3657           end_nonint_fast_global_incop:
3658             len = JSOP_INCGVAR_LENGTH;  /* all gvar incops are same length */
3659             JS_ASSERT(len == js_CodeSpec[op].length);
3660             DO_NEXT_OP(len);
3661 
3662 #undef FAST_GLOBAL_INCREMENT_OP
3663 
3664           do_nonint_fast_global_incop:
3665           {
3666             const JSCodeSpec *cs = &js_CodeSpec[op];
3667 
3668             vp = sp++;
3669             SAVE_SP(fp);
3670             NONINT_INCREMENT_OP_MIDDLE();
3671             OBJ_SET_SLOT(cx, obj, slot, rval);
3672             STORE_OPND(-1, rtmp);
3673             len = cs->length;
3674             DO_NEXT_OP(len);
3675           }
3676 
3677           BEGIN_CASE(JSOP_GETPROP)
3678           BEGIN_CASE(JSOP_GETXPROP)
3679             /* Get an immediate atom naming the property. */
3680             atom = GET_ATOM(cx, script, pc);
3681             lval = FETCH_OPND(-1);
3682             if (JSVAL_IS_STRING(lval) &&
3683                 atom == cx->runtime->atomState.lengthAtom) {
3684                 rval = INT_TO_JSVAL(JSSTRING_LENGTH(JSVAL_TO_STRING(lval)));
3685                 obj = NULL;
3686             } else {
3687                 id = ATOM_TO_JSID(atom);
3688                 VALUE_TO_OBJECT(cx, lval, obj);
3689                 STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
3690                 SAVE_SP_AND_PC(fp);
3691                 CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval));
3692                 if (!ok)
3693                     goto out;
3694             }
3695             STORE_OPND(-1, rval);
3696           END_CASE(JSOP_GETPROP)
3697 
3698           BEGIN_CASE(JSOP_SETPROP)
3699             /* Pop the right-hand side into rval for OBJ_SET_PROPERTY. */
3700             rval = FETCH_OPND(-1);
3701 
3702             /* Get an immediate atom naming the property. */
3703             atom = GET_ATOM(cx, script, pc);
3704             id   = ATOM_TO_JSID(atom);
3705             PROPERTY_OP(-2, CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval)));
3706             sp--;
3707             STORE_OPND(-1, rval);
3708             obj = NULL;
3709           END_CASE(JSOP_SETPROP)
3710 
3711           BEGIN_CASE(JSOP_GETELEM)
3712           BEGIN_CASE(JSOP_GETXELEM)
3713             ELEMENT_OP(-1, CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval)));
3714             sp--;
3715             STORE_OPND(-1, rval);
3716           END_CASE(JSOP_GETELEM)
3717 
3718           BEGIN_CASE(JSOP_SETELEM)
3719             rval = FETCH_OPND(-1);
3720             ELEMENT_OP(-2, CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval)));
3721             sp -= 2;
3722             STORE_OPND(-1, rval);
3723             obj = NULL;
3724           END_CASE(JSOP_SETELEM)
3725 
3726           BEGIN_CASE(JSOP_ENUMELEM)
3727             /* Funky: the value to set is under the [obj, id] pair. */
3728             FETCH_ELEMENT_ID(-1, id);
3729             FETCH_OBJECT(cx, -2, lval, obj);
3730             CHECK_ELEMENT_ID(obj, id);
3731             rval = FETCH_OPND(-3);
3732             SAVE_SP_AND_PC(fp);
3733             ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
3734             if (!ok)
3735                 goto out;
3736             sp -= 3;
3737           END_CASE(JSOP_ENUMELEM)
3738 
3739 /*
3740  * LAZY_ARGS_THISP allows the JSOP_ARGSUB bytecode to defer creation of the
3741  * arguments object until it is truly needed.  JSOP_ARGSUB optimizes away
3742  * arguments objects when the only uses of the 'arguments' parameter are to
3743  * fetch individual actual parameters.  But if such a use were then invoked,
3744  * e.g., arguments[i](), the 'this' parameter would and must bind to the
3745  * caller's arguments object.  So JSOP_ARGSUB sets obj to LAZY_ARGS_THISP.
3746  */
3747 #define LAZY_ARGS_THISP ((JSObject *) JSVAL_VOID)
3748 
3749           BEGIN_CASE(JSOP_PUSHOBJ)
3750             if (obj == LAZY_ARGS_THISP && !(obj = js_GetArgsObject(cx, fp))) {
3751                 ok = JS_FALSE;
3752                 goto out;
3753             }
3754             PUSH_OPND(OBJECT_TO_JSVAL(obj));
3755           END_CASE(JSOP_PUSHOBJ)
3756 
3757           BEGIN_CASE(JSOP_CALL)
3758           BEGIN_CASE(JSOP_EVAL)
3759             argc = GET_ARGC(pc);
3760             vp = sp - (argc + 2);
3761             lval = *vp;
3762             SAVE_SP_AND_PC(fp);
3763             if (VALUE_IS_FUNCTION(cx, lval) &&
3764                 (obj = JSVAL_TO_OBJECT(lval),
3765                  fun = (JSFunction *) JS_GetPrivate(cx, obj),
3766                  FUN_INTERPRETED(fun)))
3767           /* inline_call: */
3768             {
3769                 uintN nframeslots, nvars, nslots, missing;
3770                 JSArena *a;
3771                 jsuword avail, nbytes;
3772                 JSBool overflow;
3773                 void *newmark;
3774                 jsval *rvp;
3775                 JSInlineFrame *newifp;
3776                 JSInterpreterHook hook;
3777 
3778                 /* Restrict recursion of lightweight functions. */
3779                 if (inlineCallCount == MAX_INLINE_CALL_COUNT) {
3780                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3781                                          JSMSG_OVER_RECURSED);
3782                     ok = JS_FALSE;
3783                     goto out;
3784                 }
3785 
3786                 /* Compute the total number of stack slots needed for fun. */
3787                 nframeslots = JS_HOWMANY(sizeof(JSInlineFrame), sizeof(jsval));
3788                 nvars = fun->u.i.nvars;
3789                 script = fun->u.i.script;
3790                 depth = (jsint) script->depth;
3791                 nslots = nframeslots + nvars + 2 * depth;
3792 
3793                 /* Allocate missing expected args adjacent to actual args. */
3794                 missing = (fun->nargs > argc) ? fun->nargs - argc : 0;
3795                 a = cx->stackPool.current;
3796                 avail = a->avail;
3797                 newmark = (void *) avail;
3798                 if (missing) {
3799                     newsp = sp + missing;
3800                     overflow = (jsuword) newsp > a->limit;
3801                     if (overflow)
3802                         nslots += 2 + argc + missing;
3803                     else if ((jsuword) newsp > avail)
3804                         avail = a->avail = (jsuword) newsp;
3805                 }
3806 #ifdef __GNUC__
3807                 else overflow = JS_FALSE;   /* suppress bogus gcc warnings */
3808 #endif
3809 
3810                 /* Allocate the inline frame with its vars and operand slots. */
3811                 newsp = (jsval *) avail;
3812                 nbytes = nslots * sizeof(jsval);
3813                 avail += nbytes;
3814                 if (avail <= a->limit) {
3815                     a->avail = avail;
3816                 } else {
3817                     JS_ARENA_ALLOCATE_CAST(newsp, jsval *, &cx->stackPool,
3818                                            nbytes);
3819                     if (!newsp) {
3820                         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3821                                              JSMSG_STACK_OVERFLOW,
3822                                              (fp && fp->fun)
3823                                              ? JS_GetFunctionName(fp->fun)
3824                                              : "script");
3825                         goto bad_inline_call;
3826                     }
3827                 }
3828 
3829                 /* Move args if missing overflow arena a, push missing args. */
3830                 rvp = vp;
3831                 if (missing) {
3832                     if (overflow) {
3833                         memcpy(newsp, vp, (2 + argc) * sizeof(jsval));
3834                         vp = newsp;
3835                         sp = vp + 2 + argc;
3836                         newsp = sp + missing;
3837                     }
3838                     do {
3839                         PUSH(JSVAL_VOID);
3840                     } while (--missing != 0);
3841                 }
3842 
3843                 /* Claim space for the stack frame and initialize it. */
3844                 newifp = (JSInlineFrame *) newsp;
3845                 newsp += nframeslots;
3846                 newifp->frame.callobj = NULL;
3847                 newifp->frame.argsobj = NULL;
3848                 newifp->frame.varobj = NULL;
3849                 newifp->frame.script = script;
3850                 newifp->frame.fun = fun;
3851                 newifp->frame.argc = argc;
3852                 newifp->frame.argv = vp + 2;
3853                 newifp->frame.rval = JSVAL_VOID;
3854                 newifp->frame.nvars = nvars;
3855                 newifp->frame.vars = newsp;
3856                 newifp->frame.down = fp;
3857                 newifp->frame.annotation = NULL;
3858                 newifp->frame.scopeChain = parent = OBJ_GET_PARENT(cx, obj);
3859                 newifp->frame.sharpDepth = 0;
3860                 newifp->frame.sharpArray = NULL;
3861                 newifp->frame.flags = 0;
3862                 newifp->frame.dormantNext = NULL;
3863                 newifp->frame.xmlNamespace = NULL;
3864                 newifp->frame.blockChain = NULL;
3865                 newifp->rvp = rvp;
3866                 newifp->mark = newmark;
3867 
3868                 /* Compute the 'this' parameter now that argv is set. */
3869                 if (!JSVAL_IS_OBJECT(vp[1])) {
3870                     PRIMITIVE_TO_OBJECT(cx, vp[1], obj2);
3871                     if (!obj2)
3872                         goto bad_inline_call;
3873                     vp[1] = OBJECT_TO_JSVAL(obj2);
3874                 }
3875                 newifp->frame.thisp =
3876                     js_ComputeThis(cx,
3877                                    JSFUN_BOUND_METHOD_TEST(fun->flags)
3878                                    ? parent
3879                                    : JSVAL_TO_OBJECT(vp[1]),
3880                                    newifp->frame.argv);
3881                 if (!newifp->frame.thisp)
3882                     goto bad_inline_call;
3883 #ifdef DUMP_CALL_TABLE
3884                 LogCall(cx, *vp, argc, vp + 2);
3885 #endif
3886 
3887                 /* Push void to initialize local variables. */
3888                 sp = newsp;
3889                 while (nvars--)
3890                     PUSH(JSVAL_VOID);
3891                 sp += depth;
3892                 newifp->frame.spbase = sp;
3893                 SAVE_SP(&newifp->frame);
3894 
3895                 /* Call the debugger hook if present. */
3896                 hook = rt->callHook;
3897                 if (hook) {
3898                     newifp->frame.pc = NULL;
3899                     newifp->hookData = hook(cx, &newifp->frame, JS_TRUE, 0,
3900                                             rt->callHookData);
3901                     LOAD_INTERRUPT_HANDLER(rt);
3902                 } else {
3903                     newifp->hookData = NULL;
3904                 }
3905 
3906                 /* Scope with a call object parented by the callee's parent. */
3907                 if (JSFUN_HEAVYWEIGHT_TEST(fun->flags) &&
3908                     !js_GetCallObject(cx, &newifp->frame, parent)) {
3909                     goto bad_inline_call;
3910                 }
3911 
3912                 /* Switch to new version if currentVersion wasn't overridden. */
3913                 newifp->callerVersion = cx->version;
3914                 if (JS_LIKELY(cx->version == currentVersion)) {
3915                     currentVersion = script->version;
3916                     if (currentVersion != cx->version)
3917                         js_SetVersion(cx, currentVersion);
3918                 }
3919 
3920                 /* Push the frame and set interpreter registers. */
3921                 cx->fp = fp = &newifp->frame;
3922                 pc = script->code;
3923 #ifndef JS_THREADED_INTERP
3924                 endpc = pc + script->length;
3925 #endif
3926                 obj = NULL;
3927                 inlineCallCount++;
3928                 JS_RUNTIME_METER(rt, inlineCalls);
3929 
3930                 /* Load first opcode and dispatch it (safe since JSOP_STOP). */
3931                 op = *pc;
3932                 DO_OP();
3933 
3934               bad_inline_call:
3935                 RESTORE_SP(fp);
3936                 JS_ASSERT(fp->pc == pc);
3937                 script = fp->script;
3938                 depth = (jsint) script->depth;
3939                 js_FreeRawStack(cx, newmark);
3940                 ok = JS_FALSE;
3941                 goto out;
3942             }
3943 
3944             ok = js_Invoke(cx, argc, 0);
3945             RESTORE_SP(fp);
3946             LOAD_BRANCH_CALLBACK(cx);
3947             LOAD_INTERRUPT_HANDLER(rt);
3948             if (!ok)
3949                 goto out;
3950             JS_RUNTIME_METER(rt, nonInlineCalls);
3951 #if JS_HAS_LVALUE_RETURN
3952             if (cx->rval2set) {
3953                 /*
3954                  * Use the stack depth we didn't claim in our budget, but that
3955                  * we know is there on account of [fun, this] already having
3956                  * been pushed, at a minimum (if no args).  Those two slots
3957                  * have been popped and [rval] has been pushed, which leaves
3958                  * one more slot for rval2 before we might overflow.
3959                  *
3960                  * NB: rval2 must be the property identifier, and rval the
3961                  * object from which to get the property.  The pair form an
3962                  * ECMA "reference type", which can be used on the right- or
3963                  * left-hand side of assignment ops.  Note well: only native
3964                  * methods can return reference types.  See JSOP_SETCALL just
3965                  * below for the left-hand-side case.
3966                  */
3967                 PUSH_OPND(cx->rval2);
3968                 ELEMENT_OP(-1, ok = OBJ_GET_PROPERTY(cx, obj, id, &rval));
3969 
3970                 sp--;
3971                 STORE_OPND(-1, rval);
3972                 cx->rval2set = JS_FALSE;
3973             }
3974 #endif /* JS_HAS_LVALUE_RETURN */
3975             obj = NULL;
3976           END_CASE(JSOP_CALL)
3977 
3978 #if JS_HAS_LVALUE_RETURN
3979           BEGIN_CASE(JSOP_SETCALL)
3980             argc = GET_ARGC(pc);
3981             SAVE_SP_AND_PC(fp);
3982             ok = js_Invoke(cx, argc, 0);
3983             RESTORE_SP(fp);
3984             LOAD_BRANCH_CALLBACK(cx);
3985             LOAD_INTERRUPT_HANDLER(rt);
3986             if (!ok)
3987                 goto out;
3988             if (!cx->rval2set) {
3989                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3990                                      JSMSG_BAD_LEFTSIDE_OF_ASS);
3991                 ok = JS_FALSE;
3992                 goto out;
3993             }
3994             PUSH_OPND(cx->rval2);
3995             cx->rval2set = JS_FALSE;
3996             obj = NULL;
3997           END_CASE(JSOP_SETCALL)
3998 #endif
3999 
4000           BEGIN_CASE(JSOP_NAME)
4001             atom = GET_ATOM(cx, script, pc);
4002             id   = ATOM_TO_JSID(atom);
4003 
4004             SAVE_SP_AND_PC(fp);
4005             ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
4006             if (!ok)
4007                 goto out;
4008             if (!prop) {
4009                 /* Kludge to allow (typeof foo == "undefined") tests. */
4010                 len = JSOP_NAME_LENGTH;
4011                 endpc = script->code + script->length;
4012                 for (pc2 = pc + len; pc2 < endpc; pc2++) {
4013                     op2 = (JSOp)*pc2;
4014                     if (op2 == JSOP_TYPEOF) {
4015                         PUSH_OPND(JSVAL_VOID);
4016                         DO_NEXT_OP(len);
4017                     }
4018                     if (op2 != JSOP_GROUP)
4019                         break;
4020                 }
4021                 goto atom_not_defined;
4022             }
4023 
4024             /* Take the slow path if prop was not found in a native object. */
4025             if (!OBJ_IS_NATIVE(obj) || !OBJ_IS_NATIVE(obj2)) {
4026                 OBJ_DROP_PROPERTY(cx, obj2, prop);
4027                 ok = OBJ_GET_PROPERTY(cx, obj, id, &rval);
4028                 if (!ok)
4029                     goto out;
4030             } else {
4031                 sprop = (JSScopeProperty *)prop;
4032                 NATIVE_GET(cx, obj, obj2, sprop, &rval);
4033                 OBJ_DROP_PROPERTY(cx, obj2, prop);
4034             }
4035             PUSH_OPND(rval);
4036           END_CASE(JSOP_NAME)
4037 
4038           BEGIN_CASE(JSOP_UINT16)
4039             i = (jsint) GET_ATOM_INDEX(pc);
4040             rval = INT_TO_JSVAL(i);
4041             PUSH_OPND(rval);
4042             obj = NULL;
4043           END_CASE(JSOP_UINT16)
4044 
4045           BEGIN_CASE(JSOP_UINT24)
4046             i = (jsint) GET_LITERAL_INDEX(pc);
4047             rval = INT_TO_JSVAL(i);
4048             PUSH_OPND(rval);
4049           END_CASE(JSOP_UINT24)
4050 
4051           BEGIN_CASE(JSOP_LITERAL)
4052             atomIndex = GET_LITERAL_INDEX(pc);
4053             atom = js_GetAtom(cx, &script->atomMap, atomIndex);
4054             PUSH_OPND(ATOM_KEY(atom));
4055             obj = NULL;
4056           END_CASE(JSOP_LITERAL)
4057 
4058           BEGIN_CASE(JSOP_FINDNAME)
4059             atomIndex = GET_LITERAL_INDEX(pc);
4060             atom = js_GetAtom(cx, &script->atomMap, atomIndex);
4061             SAVE_SP_AND_PC(fp);
4062             obj = js_FindIdentifierBase(cx, ATOM_TO_JSID(atom));
4063             if (!obj) {
4064                 ok = JS_FALSE;
4065                 goto out;
4066             }
4067             PUSH_OPND(OBJECT_TO_JSVAL(obj));
4068             PUSH_OPND(ATOM_KEY(atom));
4069           END_CASE(JSOP_FINDNAME)
4070 
4071           BEGIN_CASE(JSOP_LITOPX)
4072             /*
4073              * Load atomIndex, which is used by code at each do_JSOP_* label.
4074              *
4075              * Also set pc2 to point at the bytecode extended by this prefix
4076              * to have a leading 24 bit atomIndex, instead of the unextended
4077              * 16-bit atomIndex that normally comes after op.  This enables
4078              * JOF_INDEXCONST format ops (which have multiple immediates) to
4079              * collect their other immediate via GET_VARNO(pc2) or similar.
4080              *
4081              * Finally, load op and, if threading, adjust pc so that it will
4082              * be advanced properly at the end of op's case by DO_NEXT_OP.
4083              */
4084             atomIndex = GET_LITERAL_INDEX(pc);
4085             pc2 = pc + 1 + LITERAL_INDEX_LEN;
4086             op = *pc2;
4087             pc += JSOP_LITOPX_LENGTH - (1 + ATOM_INDEX_LEN);
4088 #ifndef JS_THREADED_INTERP
4089             len = js_CodeSpec[op].length;
4090 #endif
4091             switch (op) {
4092               case JSOP_ANONFUNOBJ:   goto do_JSOP_ANONFUNOBJ;
4093               case JSOP_BINDNAME:     goto do_JSOP_BINDNAME;
4094               case JSOP_CLOSURE:      goto do_JSOP_CLOSURE;
4095               case JSOP_DEFCONST:     goto do_JSOP_DEFCONST;
4096               case JSOP_DEFFUN:       goto do_JSOP_DEFFUN;
4097               case JSOP_DEFLOCALFUN:  goto do_JSOP_DEFLOCALFUN;
4098               case JSOP_DEFVAR:       goto do_JSOP_DEFVAR;
4099 #if JS_HAS_EXPORT_IMPORT
4100               case JSOP_EXPORTNAME:   goto do_JSOP_EXPORTNAME;
4101 #endif
4102 #if JS_HAS_XML_SUPPORT
4103               case JSOP_GETMETHOD:    goto do_JSOP_GETMETHOD;
4104               case JSOP_SETMETHOD:    goto do_JSOP_SETMETHOD;
4105 #endif
4106               case JSOP_NAMEDFUNOBJ:  goto do_JSOP_NAMEDFUNOBJ;
4107               case JSOP_NUMBER:       goto do_JSOP_NUMBER;
4108               case JSOP_OBJECT:       goto do_JSOP_OBJECT;
4109 #if JS_HAS_XML_SUPPORT
4110               case JSOP_QNAMECONST:   goto do_JSOP_QNAMECONST;
4111               case JSOP_QNAMEPART:    goto do_JSOP_QNAMEPART;
4112 #endif
4113               case JSOP_REGEXP:       goto do_JSOP_REGEXP;
4114               case JSOP_SETCONST:     goto do_JSOP_SETCONST;
4115               case JSOP_STRING:       goto do_JSOP_STRING;
4116 #if JS_HAS_XML_SUPPORT
4117               case JSOP_XMLCDATA:     goto do_JSOP_XMLCDATA;
4118               case JSOP_XMLCOMMENT:   goto do_JSOP_XMLCOMMENT;
4119               case JSOP_XMLOBJECT:    goto do_JSOP_XMLOBJECT;
4120               case JSOP_XMLPI:        goto do_JSOP_XMLPI;
4121 #endif
4122               case JSOP_ENTERBLOCK:   goto do_JSOP_ENTERBLOCK;
4123               default:                JS_ASSERT(0);
4124             }
4125             /* NOTREACHED */
4126 
4127           BEGIN_CASE(JSOP_NUMBER)
4128           BEGIN_CASE(JSOP_STRING)
4129           BEGIN_CASE(JSOP_OBJECT)
4130             atomIndex = GET_ATOM_INDEX(pc);
4131 
4132           do_JSOP_NUMBER:
4133           do_JSOP_STRING:
4134           do_JSOP_OBJECT:
4135             atom = js_GetAtom(cx, &script->atomMap, atomIndex);
4136             PUSH_OPND(ATOM_KEY(atom));
4137             obj = NULL;
4138           END_CASE(JSOP_NUMBER)
4139 
4140           BEGIN_LITOPX_CASE(JSOP_REGEXP, 0)
4141           {
4142             JSRegExp *re;
4143             JSObject *funobj;
4144 
4145             /*
4146              * Push a regexp object for the atom mapped by the bytecode at pc,
4147              * cloning the literal's regexp object if necessary, to simulate in
4148              * the pre-compile/execute-later case what ECMA specifies for the
4149              * compile-and-go case: that scanning each regexp literal creates
4150              * a single corresponding RegExp object.
4151              *
4152              * To support pre-compilation transparently, we must handle the
4153              * case where a regexp object literal is used in a different global
4154              * at execution time from the global with which it was scanned at
4155              * compile time.  We do this by re-wrapping the JSRegExp private
4156              * data struct with a cloned object having the right prototype and
4157              * parent, and having its own lastIndex property value storage.
4158              *
4159              * Unlike JSOP_DEFFUN and other prolog bytecodes that may clone
4160              * literal objects, we don't want to pay a script prolog execution
4161              * price for all regexp literals in a script (many may not be used
4162              * by a particular execution of that script, depending on control
4163              * flow), so we initialize lazily here.
4164              *
4165              * XXX This code is specific to regular expression objects.  If we
4166              * need a similar op for other kinds of object literals, we should
4167              * push cloning down under JSObjectOps and reuse code here.
4168              */
4169             JS_ASSERT(ATOM_IS_OBJECT(atom));
4170             obj = ATOM_TO_OBJECT(atom);
4171             JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass);
4172 
4173             re = (JSRegExp *) JS_GetPrivate(cx, obj);
4174             slot = re->cloneIndex;
4175             if (fp->fun) {
4176                 /*
4177                  * We're in function code, not global or eval code (in eval
4178                  * code, JSOP_REGEXP is never emitted).  The code generator
4179                  * recorded in fp->fun->nregexps the number of re->cloneIndex
4180                  * slots that it reserved in the cloned funobj.
4181                  */
4182                 funobj = JSVAL_TO_OBJECT(fp->argv[-2]);
4183                 slot += JSCLASS_RESERVED_SLOTS(&js_FunctionClass);
4184                 if (!JS_GetReservedSlot(cx, funobj, slot, &rval))
4185                     return JS_FALSE;
4186                 if (JSVAL_IS_VOID(rval))
4187                     rval = JSVAL_NULL;
4188             } else {
4189                 /*
4190                  * We're in global code.  The code generator already arranged
4191                  * via script->numGlobalVars to reserve a global variable slot
4192                  * at cloneIndex.  All global variable slots are initialized
4193                  * to null, not void, for faster testing in JSOP_*GVAR cases.
4194                  */
4195                 rval = fp->vars[slot];
4196 #ifdef __GNUC__
4197                 funobj = NULL;  /* suppress bogus gcc warnings */
4198 #endif
4199             }
4200 
4201             if (JSVAL_IS_NULL(rval)) {
4202                 /* Compute the current global object in obj2. */
4203                 obj2 = fp->scopeChain;
4204                 while ((parent = OBJ_GET_PARENT(cx, obj2)) != NULL)
4205                     obj2 = parent;
4206 
4207                 /*
4208                  * We must home sp here, because either js_CloneRegExpObject
4209                  * or JS_SetReservedSlot could nest a last-ditch GC.  We home
4210                  * pc as well, in case js_CloneRegExpObject has to lookup the
4211                  * "RegExp" class in the global object, which could entail a
4212                  * JSNewResolveOp call.
4213                  */
4214                 SAVE_SP_AND_PC(fp);
4215 
4216                 /*
4217                  * If obj's parent is not obj2, we must clone obj so that it
4218                  * has the right parent, and therefore, the right prototype.
4219                  *
4220                  * Yes, this means we assume that the correct RegExp.prototype
4221                  * to which regexp instances (including literals) delegate can
4222                  * be distinguished solely by the instance's parent, which was
4223                  * set to the parent of the RegExp constructor function object
4224                  * when the instance was created.  In other words,
4225                  *
4226                  *   (/x/.__parent__ == RegExp.__parent__) implies
4227                  *   (/x/.__proto__ == RegExp.prototype)
4228                  *
4229                  * (unless you assign a different object to RegExp.prototype
4230                  * at runtime, in which case, ECMA doesn't specify operation,
4231                  * and you get what you deserve).
4232                  *
4233                  * This same coupling between instance parent and constructor
4234                  * parent turns up everywhere (see jsobj.c's FindClassObject,
4235                  * js_ConstructObject, and js_NewObject).  It's fundamental to
4236                  * the design of the language when you consider multiple global
4237                  * objects and separate compilation and execution, even though
4238                  * it is not specified fully in ECMA.
4239                  */
4240                 if (OBJ_GET_PARENT(cx, obj) != obj2) {
4241                     obj = js_CloneRegExpObject(cx, obj, obj2);
4242                     if (!obj) {
4243                         ok = JS_FALSE;
4244                         goto out;
4245                     }
4246                 }
4247                 rval = OBJECT_TO_JSVAL(obj);
4248 
4249                 /* Store the regexp object value in its cloneIndex slot. */
4250                 if (fp->fun) {
4251                     if (!JS_SetReservedSlot(cx, funobj, slot, rval))
4252                         return JS_FALSE;
4253                 } else {
4254                     fp->vars[slot] = rval;
4255                 }
4256             }
4257 
4258             PUSH_OPND(rval);
4259             obj = NULL;
4260           }
4261           END_LITOPX_CASE(JSOP_REGEXP)
4262 
4263           BEGIN_CASE(JSOP_ZERO)
4264             PUSH_OPND(JSVAL_ZERO);
4265             obj = NULL;
4266           END_CASE(JSOP_ZERO)
4267 
4268           BEGIN_CASE(JSOP_ONE)
4269             PUSH_OPND(JSVAL_ONE);
4270             obj = NULL;
4271           END_CASE(JSOP_ONE)
4272 
4273           BEGIN_CASE(JSOP_NULL)
4274             PUSH_OPND(JSVAL_NULL);
4275             obj = NULL;
4276           END_CASE(JSOP_NULL)
4277 
4278           BEGIN_CASE(JSOP_THIS)
4279             obj = fp->thisp;
4280             clasp = OBJ_GET_CLASS(cx, obj);
4281             if (clasp->flags & JSCLASS_IS_EXTENDED) {
4282                 JSExtendedClass *xclasp;
4283 
4284                 xclasp = (JSExtendedClass *) clasp;
4285                 if (xclasp->outerObject) {
4286                     obj = xclasp->outerObject(cx, obj);
4287                     if (!obj) {
4288                         ok = JS_FALSE;
4289                         goto out;
4290                     }
4291                 }
4292             }
4293 
4294             PUSH_OPND(OBJECT_TO_JSVAL(obj));
4295             obj = NULL;
4296           END_CASE(JSOP_THIS)
4297 
4298           BEGIN_CASE(JSOP_FALSE)
4299             PUSH_OPND(JSVAL_FALSE);
4300             obj = NULL;
4301           END_CASE(JSOP_FALSE)
4302 
4303           BEGIN_CASE(JSOP_TRUE)
4304             PUSH_OPND(JSVAL_TRUE);
4305             obj = NULL;
4306           END_CASE(JSOP_TRUE)
4307 
4308           BEGIN_CASE(JSOP_TABLESWITCH)
4309             pc2 = pc;
4310             len = GET_JUMP_OFFSET(pc2);
4311 
4312             /*
4313              * ECMAv2+ forbids conversion of discriminant, so we will skip to
4314              * the default case if the discriminant isn't already an int jsval.
4315              * (This opcode is emitted only for dense jsint-domain switches.)
4316              */
4317             rval = POP_OPND();
4318             if (!JSVAL_IS_INT(rval))
4319                 DO_NEXT_OP(len);
4320             i = JSVAL_TO_INT(rval);
4321 
4322             pc2 += JUMP_OFFSET_LEN;
4323             low = GET_JUMP_OFFSET(pc2);
4324             pc2 += JUMP_OFFSET_LEN;
4325             high = GET_JUMP_OFFSET(pc2);
4326 
4327             i -= low;
4328             if ((jsuint)i < (jsuint)(high - low + 1)) {
4329                 pc2 += JUMP_OFFSET_LEN + JUMP_OFFSET_LEN * i;
4330                 off = (jsint) GET_JUMP_OFFSET(pc2);
4331                 if (off)
4332                     len = off;
4333             }
4334           END_VARLEN_CASE
4335 
4336           BEGIN_CASE(JSOP_LOOKUPSWITCH)
4337             lval = POP_OPND();
4338             pc2 = pc;
4339             len = GET_JUMP_OFFSET(pc2);
4340 
4341             if (!JSVAL_IS_NUMBER(lval) &&
4342                 !JSVAL_IS_STRING(lval) &&
4343                 !JSVAL_IS_BOOLEAN(lval)) {
4344                 DO_NEXT_OP(len);
4345             }
4346 
4347             pc2 += JUMP_OFFSET_LEN;
4348             npairs = (jsint) GET_ATOM_INDEX(pc2);
4349             pc2 += ATOM_INDEX_LEN;
4350 
4351 #define SEARCH_PAIRS(MATCH_CODE)                                              \
4352     while (npairs) {                                                          \
4353         atom = GET_ATOM(cx, script, pc2);                                     \
4354         rval = ATOM_KEY(atom);                                                \
4355         MATCH_CODE                                                            \
4356         if (match) {                                                          \
4357             pc2 += ATOM_INDEX_LEN;                                            \
4358             len = GET_JUMP_OFFSET(pc2);                                       \
4359             DO_NEXT_OP(len);                                                  \
4360         }                                                                     \
4361         pc2 += ATOM_INDEX_LEN + JUMP_OFFSET_LEN;                              \
4362         npairs--;                                                             \
4363     }
4364             if (JSVAL_IS_STRING(lval)) {
4365                 str  = JSVAL_TO_STRING(lval);
4366                 SEARCH_PAIRS(
4367                     match = (JSVAL_IS_STRING(rval) &&
4368                              ((str2 = JSVAL_TO_STRING(rval)) == str ||
4369                               js_EqualStrings(str2, str)));
4370                 )
4371             } else if (JSVAL_IS_DOUBLE(lval)) {
4372                 d = *JSVAL_TO_DOUBLE(lval);
4373                 SEARCH_PAIRS(
4374                     match = (JSVAL_IS_DOUBLE(rval) &&
4375                              *JSVAL_TO_DOUBLE(rval) == d);
4376                 )
4377             } else {
4378                 SEARCH_PAIRS(
4379                     match = (lval == rval);
4380                 )
4381             }
4382 #undef SEARCH_PAIRS
4383           END_VARLEN_CASE
4384 
4385           BEGIN_CASE(JSOP_TABLESWITCHX)
4386             pc2 = pc;
4387             len = GET_JUMPX_OFFSET(pc2);
4388 
4389             /*
4390              * ECMAv2+ forbids conversion of discriminant, so we will skip to
4391              * the default case if the discriminant isn't already an int jsval.
4392              * (This opcode is emitted only for dense jsint-domain switches.)
4393              */
4394             rval = POP_OPND();
4395             if (!JSVAL_IS_INT(rval))
4396                 DO_NEXT_OP(len);
4397             i = JSVAL_TO_INT(rval);
4398 
4399             pc2 += JUMPX_OFFSET_LEN;
4400             low = GET_JUMP_OFFSET(pc2);
4401             pc2 += JUMP_OFFSET_LEN;
4402             high = GET_JUMP_OFFSET(pc2);
4403 
4404             i -= low;
4405             if ((jsuint)i < (jsuint)(high - low + 1)) {
4406                 pc2 += JUMP_OFFSET_LEN + JUMPX_OFFSET_LEN * i;
4407                 off = (jsint) GET_JUMPX_OFFSET(pc2);
4408                 if (off)
4409                     len = off;
4410             }
4411           END_VARLEN_CASE
4412 
4413           BEGIN_CASE(JSOP_LOOKUPSWITCHX)
4414             lval = POP_OPND();
4415             pc2 = pc;
4416             len = GET_JUMPX_OFFSET(pc2);
4417 
4418             if (!JSVAL_IS_NUMBER(lval) &&
4419                 !JSVAL_IS_STRING(lval) &&
4420                 !JSVAL_IS_BOOLEAN(lval)) {
4421                 DO_NEXT_OP(len);
4422             }
4423 
4424             pc2 += JUMPX_OFFSET_LEN;
4425             npairs = (jsint) GET_ATOM_INDEX(pc2);
4426             pc2 += ATOM_INDEX_LEN;
4427 
4428 #define SEARCH_EXTENDED_PAIRS(MATCH_CODE)                                     \
4429     while (npairs) {                                                          \
4430         atom = GET_ATOM(cx, script, pc2);                                     \
4431         rval = ATOM_KEY(atom);                                                \
4432         MATCH_CODE                                                            \
4433         if (match) {                                                          \
4434             pc2 += ATOM_INDEX_LEN;                                            \
4435             len = GET_JUMPX_OFFSET(pc2);                                      \
4436             DO_NEXT_OP(len);                                                  \
4437         }                                                                     \
4438         pc2 += ATOM_INDEX_LEN + JUMPX_OFFSET_LEN;                             \
4439         npairs--;                                                             \
4440     }
4441             if (JSVAL_IS_STRING(lval)) {
4442                 str  = JSVAL_TO_STRING(lval);
4443                 SEARCH_EXTENDED_PAIRS(
4444                     match = (JSVAL_IS_STRING(rval) &&
4445                              ((str2 = JSVAL_TO_STRING(rval)) == str ||
4446                               js_EqualStrings(str2, str)));
4447                 )
4448             } else if (JSVAL_IS_DOUBLE(lval)) {
4449                 d = *JSVAL_TO_DOUBLE(lval);
4450                 SEARCH_EXTENDED_PAIRS(
4451                     match = (JSVAL_IS_DOUBLE(rval) &&
4452                              *JSVAL_TO_DOUBLE(rval) == d);
4453                 )
4454             } else {
4455                 SEARCH_EXTENDED_PAIRS(
4456                     match = (lval == rval);
4457                 )
4458             }
4459 #undef SEARCH_EXTENDED_PAIRS
4460           END_VARLEN_CASE
4461 
4462           EMPTY_CASE(JSOP_CONDSWITCH)
4463 
4464 #if JS_HAS_EXPORT_IMPORT
4465           BEGIN_CASE(JSOP_EXPORTALL)
4466             obj = fp->varobj;
4467             SAVE_SP_AND_PC(fp);
4468             ida = JS_Enumerate(cx, obj);
4469             if (!ida) {
4470                 ok = JS_FALSE;
4471             } else {
4472                 for (i = 0, j = ida->length; i < j; i++) {
4473                     id = ida->vector[i];
4474                     ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
4475                     if (!ok)
4476                         break;
4477                     if (!prop)
4478                         continue;
4479                     ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, &attrs);
4480                     if (ok) {
4481                         attrs |= JSPROP_EXPORTED;
4482                         ok = OBJ_SET_ATTRIBUTES(cx, obj, id, prop, &attrs);
4483                     }
4484                     OBJ_DROP_PROPERTY(cx, obj2, prop);
4485                     if (!ok)
4486                         break;
4487                 }
4488                 JS_DestroyIdArray(cx, ida);
4489             }
4490           END_CASE(JSOP_EXPORTALL)
4491 
4492           BEGIN_LITOPX_CASE(JSOP_EXPORTNAME, 0)
4493             id   = ATOM_TO_JSID(atom);
4494             obj  = fp->varobj;
4495             SAVE_SP_AND_PC(fp);
4496             ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
4497             if (!ok)
4498                 goto out;
4499             if (!prop) {
4500                 ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, NULL, NULL,
4501                                          JSPROP_EXPORTED, NULL);
4502             } else {
4503                 ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, &attrs);
4504                 if (ok) {
4505                     attrs |= JSPROP_EXPORTED;
4506                     ok = OBJ_SET_ATTRIBUTES(cx, obj, id, prop, &attrs);
4507                 }
4508                 OBJ_DROP_PROPERTY(cx, obj2, prop);
4509             }
4510             if (!ok)
4511                 goto out;
4512           END_LITOPX_CASE(JSOP_EXPORTNAME)
4513 
4514           BEGIN_CASE(JSOP_IMPORTALL)
4515             id = (jsid) JSVAL_VOID;
4516             PROPERTY_OP(-1, ok = ImportProperty(cx, obj, id));
4517             sp--;
4518           END_CASE(JSOP_IMPORTALL)
4519 
4520           BEGIN_CASE(JSOP_IMPORTPROP)
4521             /* Get an immediate atom naming the property. */
4522             atom = GET_ATOM(cx, script, pc);
4523             id   = ATOM_TO_JSID(atom);
4524             PROPERTY_OP(-1, ok = ImportProperty(cx, obj, id));
4525             sp--;
4526           END_CASE(JSOP_IMPORTPROP)
4527 
4528           BEGIN_CASE(JSOP_IMPORTELEM)
4529             ELEMENT_OP(-1, ok = ImportProperty(cx, obj, id));
4530             sp -= 2;
4531           END_CASE(JSOP_IMPORTELEM)
4532 #endif /* JS_HAS_EXPORT_IMPORT */
4533 
4534           BEGIN_CASE(JSOP_TRAP)
4535             SAVE_SP_AND_PC(fp);
4536             switch (JS_HandleTrap(cx, script, pc, &rval)) {
4537               case JSTRAP_ERROR:
4538                 ok = JS_FALSE;
4539                 goto out;
4540               case JSTRAP_CONTINUE:
4541                 JS_ASSERT(JSVAL_IS_INT(rval));
4542                 op = (JSOp) JSVAL_TO_INT(rval);
4543                 JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT);
4544                 LOAD_INTERRUPT_HANDLER(rt);
4545                 DO_OP();
4546               case JSTRAP_RETURN:
4547                 fp->rval = rval;
4548                 goto out;
4549               case JSTRAP_THROW:
4550                 cx->throwing = JS_TRUE;
4551                 cx->exception = rval;
4552                 ok = JS_FALSE;
4553                 goto out;
4554               default:;
4555             }
4556             LOAD_INTERRUPT_HANDLER(rt);
4557           END_CASE(JSOP_TRAP)
4558 
4559           BEGIN_CASE(JSOP_ARGUMENTS)
4560             SAVE_SP_AND_PC(fp);
4561             ok = js_GetArgsValue(cx, fp, &rval);
4562             if (!ok)
4563                 goto out;
4564             PUSH_OPND(rval);
4565             obj = NULL;
4566           END_CASE(JSOP_ARGUMENTS)
4567 
4568           BEGIN_CASE(JSOP_ARGSUB)
4569             id = INT_TO_JSID(GET_ARGNO(pc));
4570             SAVE_SP_AND_PC(fp);
4571             ok = js_GetArgsProperty(cx, fp, id, &obj, &rval);
4572             if (!ok)
4573                 goto out;
4574             if (!obj) {
4575                 /*
4576                  * If arguments was not overridden by eval('arguments = ...'),
4577                  * set obj to the magic cookie respected by JSOP_PUSHOBJ, just
4578                  * in case this bytecode is part of an 'arguments[i](j, k)' or
4579                  * similar such invocation sequence, where the function that
4580                  * is invoked expects its 'this' parameter to be the caller's
4581                  * arguments object.
4582                  */
4583                 obj = LAZY_ARGS_THISP;
4584             }
4585             PUSH_OPND(rval);
4586           END_CASE(JSOP_ARGSUB)
4587 
4588 #undef LAZY_ARGS_THISP
4589 
4590           BEGIN_CASE(JSOP_ARGCNT)
4591             id = ATOM_TO_JSID(rt->atomState.lengthAtom);
4592             SAVE_SP_AND_PC(fp);
4593             ok = js_GetArgsProperty(cx, fp, id, &obj, &rval);
4594             if (!ok)
4595                 goto out;
4596             PUSH_OPND(rval);
4597           END_CASE(JSOP_ARGCNT)
4598 
4599           BEGIN_CASE(JSOP_GETARG)
4600             slot = GET_ARGNO(pc);
4601             JS_ASSERT(slot < fp->fun->nargs);
4602             PUSH_OPND(fp->argv[slot]);
4603             obj = NULL;
4604           END_CASE(JSOP_GETARG)
4605 
4606           BEGIN_CASE(JSOP_SETARG)
4607             slot = GET_ARGNO(pc);
4608             JS_ASSERT(slot < fp->fun->nargs);
4609             vp = &fp->argv[slot];
4610             GC_POKE(cx, *vp);
4611             *vp = FETCH_OPND(-1);
4612             obj = NULL;
4613           END_CASE(JSOP_SETARG)
4614 
4615           BEGIN_CASE(JSOP_GETVAR)
4616             slot = GET_VARNO(pc);
4617             JS_ASSERT(slot < fp->fun->u.i.nvars);
4618             PUSH_OPND(fp->vars[slot]);
4619             obj = NULL;
4620           END_CASE(JSOP_GETVAR)
4621 
4622           BEGIN_CASE(JSOP_SETVAR)
4623             slot = GET_VARNO(pc);
4624             JS_ASSERT(slot < fp->fun->u.i.nvars);
4625             vp = &fp->vars[slot];
4626             GC_POKE(cx, *vp);
4627             *vp = FETCH_OPND(-1);
4628             obj = NULL;
4629           END_CASE(JSOP_SETVAR)
4630 
4631           BEGIN_CASE(JSOP_GETGVAR)
4632             slot = GET_VARNO(pc);
4633             JS_ASSERT(slot < fp->nvars);
4634             lval = fp->vars[slot];
4635             if (JSVAL_IS_NULL(lval)) {
4636                 op = JSOP_NAME;
4637                 DO_OP();
4638             }
4639             slot = JSVAL_TO_INT(lval);
4640             obj = fp->varobj;
4641             rval = OBJ_GET_SLOT(cx, obj, slot);
4642             PUSH_OPND(rval);
4643           END_CASE(JSOP_GETGVAR)
4644 
4645           BEGIN_CASE(JSOP_SETGVAR)
4646             slot = GET_VARNO(pc);
4647             JS_ASSERT(slot < fp->nvars);
4648             rval = FETCH_OPND(-1);
4649             lval = fp->vars[slot];
4650             obj = fp->varobj;
4651             if (JSVAL_IS_NULL(lval)) {
4652                 /*
4653                  * Inline-clone and specialize JSOP_SETNAME code here because
4654                  * JSOP_SETGVAR has arity 1: [rval], not arity 2: [obj, rval]
4655                  * as JSOP_SETNAME does, where [obj] is due to JSOP_BINDNAME.
4656                  */
4657                 atom = GET_ATOM(cx, script, pc);
4658                 id = ATOM_TO_JSID(atom);
4659                 SAVE_SP_AND_PC(fp);
4660                 CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval));
4661                 if (!ok)
4662                     goto out;
4663                 STORE_OPND(-1, rval);
4664             } else {
4665                 slot = JSVAL_TO_INT(lval);
4666                 GC_POKE(cx, obj->slots[slot]);
4667                 OBJ_SET_SLOT(cx, obj, slot, rval);
4668             }
4669             obj = NULL;
4670           END_CASE(JSOP_SETGVAR)
4671 
4672           BEGIN_CASE(JSOP_DEFCONST)
4673           BEGIN_CASE(JSOP_DEFVAR)
4674             atomIndex = GET_ATOM_INDEX(pc);
4675 
4676           do_JSOP_DEFCONST:
4677           do_JSOP_DEFVAR:
4678             atom = js_GetAtom(cx, &script->atomMap, atomIndex);
4679             obj = fp->varobj;
4680             attrs = JSPROP_ENUMERATE;
4681             if (!(fp->flags & JSFRAME_EVAL))
4682                 attrs |= JSPROP_PERMANENT;
4683             if (op == JSOP_DEFCONST)
4684                 attrs |= JSPROP_READONLY;
4685 
4686             /* Lookup id in order to check for redeclaration problems. */
4687             id = ATOM_TO_JSID(atom);
4688             SAVE_SP_AND_PC(fp);
4689             ok = js_CheckRedeclaration(cx, obj, id, attrs, &obj2, &prop);
4690             if (!ok)
4691                 goto out;
4692 
4693             /* Bind a variable only if it's not yet defined. */
4694             if (!prop) {
4695                 ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, NULL, NULL,
4696                                          attrs, &prop);
4697                 if (!ok)
4698                     goto out;
4699                 JS_ASSERT(prop);
4700                 obj2 = obj;
4701             }
4702 
4703             /*
4704              * Try to optimize a property we either just created, or found
4705              * directly in the global object, that is permanent, has a slot,
4706              * and has stub getter and setter, into a "fast global" accessed
4707              * by the JSOP_*GVAR opcodes.
4708              */
4709             if (atomIndex < script->numGlobalVars &&
4710                 (attrs & JSPROP_PERMANENT) &&
4711                 obj2 == obj &&
4712                 OBJ_IS_NATIVE(obj)) {
4713                 sprop = (JSScopeProperty *) prop;
4714                 if (SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj)) &&
4715                     SPROP_HAS_STUB_GETTER(sprop) &&
4716                     SPROP_HAS_STUB_SETTER(sprop)) {
4717                     /*
4718                      * Fast globals use fp->vars to map the global name's
4719                      * atomIndex to the permanent fp->varobj slot number,
4720                      * tagged as a jsval.  The atomIndex for the global's
4721                      * name literal is identical to its fp->vars index.
4722                      */
4723                     fp->vars[atomIndex] = INT_TO_JSVAL(sprop->slot);
4724                 }
4725             }
4726 
4727             OBJ_DROP_PROPERTY(cx, obj2, prop);
4728           END_CASE(JSOP_DEFVAR)
4729 
4730           BEGIN_LITOPX_CASE(JSOP_DEFFUN, 0)
4731             obj = ATOM_TO_OBJECT(atom);
4732             fun = (JSFunction *) JS_GetPrivate(cx, obj);
4733             id = ATOM_TO_JSID(fun->atom);
4734 
4735             /*
4736              * We must be at top-level (either outermost block that forms a
4737              * function's body, or a global) scope, not inside an expression
4738              * (JSOP_{ANON,NAMED}FUNOBJ) or compound statement (JSOP_CLOSURE)
4739              * in the same compilation unit (ECMA Program).
4740              *
4741              * However, we could be in a Program being eval'd from inside a
4742              * with statement, so we need to distinguish scope chain head from
4743              * variables object.  Hence the obj2 vs. parent distinction below.
4744              * First we make sure the function object we're defining has the
4745              * right scope chain.  Then we define its name in fp->varobj.
4746              *
4747              * If static link is not current scope, clone fun's object to link
4748              * to the current scope via parent.  This clause exists to enable
4749              * sharing of compiled functions among multiple equivalent scopes,
4750              * splitting the cost of compilation evenly among the scopes and
4751              * amortizing it over a number of executions.  Examples include XUL
4752              * scripts and event handlers shared among Mozilla chrome windows,
4753              * and server-side JS user-defined functions shared among requests.
4754              *
4755              * NB: The Script object exposes compile and exec in the language,
4756              * such that this clause introduces an incompatible change from old
4757              * JS versions that supported Script.  Such a JS version supported
4758              * executing a script that defined and called functions scoped by
4759              * the compile-time static link, not by the exec-time scope chain.
4760              *
4761              * We sacrifice compatibility, breaking such scripts, in order to
4762              * promote compile-cost sharing and amortizing, and because Script
4763              * is not and will not be standardized.
4764              */
4765             JS_ASSERT(!fp->blockChain);
4766             obj2 = fp->scopeChain;
4767             if (OBJ_GET_PARENT(cx, obj) != obj2) {
4768                 obj = js_CloneFunctionObject(cx, obj, obj2);
4769                 if (!obj) {
4770                     ok = JS_FALSE;
4771                     goto out;
4772                 }
4773             }
4774 
4775             /*
4776              * Protect obj from any GC hiding below OBJ_DEFINE_PROPERTY.  All
4777              * paths from here must flow through the "Restore fp->scopeChain"
4778              * code below the OBJ_DEFINE_PROPERTY call.
4779              */
4780             fp->scopeChain = obj;
4781             rval = OBJECT_TO_JSVAL(obj);
4782 
4783             /*
4784              * ECMA requires functions defined when entering Global code to be
4785              * permanent, and functions defined when entering Eval code to be
4786              * impermanent.
4787              */
4788             attrs = JSPROP_ENUMERATE;
4789             if (!(fp->flags & JSFRAME_EVAL))
4790                 attrs |= JSPROP_PERMANENT;
4791 
4792             /*
4793              * Load function flags that are also property attributes.  Getters
4794              * and setters do not need a slot, their value is stored elsewhere
4795              * in the property itself, not in obj->slots.
4796              */
4797             flags = JSFUN_GSFLAG2ATTR(fun->flags);
4798             if (flags) {
4799                 attrs |= flags | JSPROP_SHARED;
4800                 rval = JSVAL_VOID;
4801             }
4802 
4803             /*
4804              * Check for a const property of the same name -- or any kind
4805              * of property if executing with the strict option.  We check
4806              * here at runtime as well as at compile-time, to handle eval
4807              * as well as multiple HTML script tags.
4808              */
4809             parent = fp->varobj;
4810             SAVE_SP_AND_PC(fp);
4811             ok = js_CheckRedeclaration(cx, parent, id, attrs, NULL, NULL);
4812             if (ok) {
4813                 ok = OBJ_DEFINE_PROPERTY(cx, parent, id, rval,
4814                                          (flags & JSPROP_GETTER)
4815                                          ? JS_EXTENSION (JSPropertyOp) obj
4816                                          : NULL,
4817                                          (flags & JSPROP_SETTER)
4818                                          ? JS_EXTENSION (JSPropertyOp) obj
4819                                          : NULL,
4820                                          attrs,
4821                                          &prop);
4822             }
4823 
4824             /* Restore fp->scopeChain now that obj is defined in fp->varobj. */
4825             fp->scopeChain = obj2;
4826             if (!ok)
4827                 goto out;
4828 
4829 #if 0
4830             if (attrs == (JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
4831                 script->numGlobalVars) {
4832                 /*
4833                  * As with JSOP_DEFVAR and JSOP_DEFCONST (above), fast globals
4834                  * use fp->vars to map the global function name's atomIndex to
4835                  * its permanent fp->varobj slot number, tagged as a jsval.
4836                  */
4837                 sprop = (JSScopeProperty *) prop;
4838                 fp->vars[atomIndex] = INT_TO_JSVAL(sprop->slot);
4839             }
4840 #endif
4841             OBJ_DROP_PROPERTY(cx, parent, prop);
4842           END_LITOPX_CASE(JSOP_DEFFUN)
4843 
4844           BEGIN_LITOPX_CASE(JSOP_DEFLOCALFUN, VARNO_LEN)
4845             /*
4846              * Define a local function (i.e., one nested at the top level of
4847              * another function), parented by the current scope chain, and
4848              * stored in a local variable slot that the compiler allocated.
4849              * This is an optimization over JSOP_DEFFUN that avoids requiring
4850              * a call object for the outer function's activation.
4851              */
4852             slot = GET_VARNO(pc2);
4853             obj = ATOM_TO_OBJECT(atom);
4854 
4855             JS_ASSERT(!fp->blockChain);
4856             if (!(fp->flags & JSFRAME_POP_BLOCKS)) {
4857                 /*
4858                  * If the compiler-created function object (obj) is scoped by a
4859                  * let-induced body block, temporarily update fp->blockChain so
4860                  * that js_GetScopeChain will clone the block into the runtime
4861                  * scope needed to parent the function object's clone.
4862                  */
4863                 parent = OBJ_GET_PARENT(cx, obj);
4864                 if (OBJ_GET_CLASS(cx, parent) == &js_BlockClass)
4865                     fp->blockChain = parent;
4866                 parent = js_GetScopeChain(cx, fp);
4867             } else {
4868                 /*
4869                  * We have already emulated JSOP_ENTERBLOCK for the enclosing
4870                  * body block, for a prior JSOP_DEFLOCALFUN in the prolog,  so
4871                  * we just load fp->scopeChain into parent.
4872                  *
4873                  * In typical execution scenarios, the prolog bytecodes that
4874                  * include this JSOP_DEFLOCALFUN run, then come main bytecodes
4875                  * including JSOP_ENTERBLOCK for the outermost (body) block.
4876                  * JSOP_ENTERBLOCK will detect that it need not do anything if
4877                  * the body block was entered above due to a local function.
4878                  * Finally the matching JSOP_LEAVEBLOCK runs.
4879                  *
4880                  * If the matching JSOP_LEAVEBLOCK for the body block does not
4881                  * run for some reason, the body block will be properly "put"
4882                  * (via js_PutBlockObject) by the PutBlockObjects call at the
4883                  * bottom of js_Interpret.
4884                  */
4885                 parent = fp->scopeChain;
4886                 JS_ASSERT(OBJ_GET_CLASS(cx, parent) == &js_BlockClass);
4887                 JS_ASSERT(OBJ_GET_PROTO(cx, parent) == OBJ_GET_PARENT(cx, obj));
4888                 JS_ASSERT(OBJ_GET_CLASS(cx, OBJ_GET_PARENT(cx, parent))
4889                           == &js_CallClass);
4890             }
4891 
4892             /* If re-parenting, store a clone of the function object. */
4893             if (OBJ_GET_PARENT(cx, obj) != parent) {
4894                 SAVE_SP_AND_PC(fp);
4895                 obj = js_CloneFunctionObject(cx, obj, parent);
4896                 if (!obj) {
4897                     ok = JS_FALSE;
4898                     goto out;
4899                 }
4900             }
4901             fp->vars[slot] = OBJECT_TO_JSVAL(obj);
4902           END_LITOPX_CASE(JSOP_DEFLOCALFUN)
4903 
4904           BEGIN_LITOPX_CASE(JSOP_ANONFUNOBJ, 0)
4905             /* Push the specified function object literal. */
4906             obj = ATOM_TO_OBJECT(atom);
4907 
4908             /* If re-parenting, push a clone of the function object. */
4909             SAVE_SP_AND_PC(fp);
4910             parent = js_GetScopeChain(cx, fp);
4911             if (!parent) {
4912                 ok = JS_FALSE;
4913                 goto out;
4914             }
4915             if (OBJ_GET_PARENT(cx, obj) != parent) {
4916                 obj = js_CloneFunctionObject(cx, obj, parent);
4917                 if (!obj) {
4918                     ok = JS_FALSE;
4919                     goto out;
4920                 }
4921             }
4922             PUSH_OPND(OBJECT_TO_JSVAL(obj));
4923             obj = NULL;
4924           END_LITOPX_CASE(JSOP_ANONFUNOBJ)
4925 
4926           BEGIN_LITOPX_CASE(JSOP_NAMEDFUNOBJ, 0)
4927             /* ECMA ed. 3 FunctionExpression: function Identifier [etc.]. */
4928             rval = ATOM_KEY(atom);
4929             JS_ASSERT(VALUE_IS_FUNCTION(cx, rval));
4930 
4931             /*
4932              * 1. Create a new object as if by the expression new Object().
4933              * 2. Add Result(1) to the front of the scope chain.
4934              *
4935              * Step 2 is achieved by making the new object's parent be the
4936              * current scope chain, and then making the new object the parent
4937              * of the Function object clone.
4938              */
4939             SAVE_SP_AND_PC(fp);
4940             obj2 = js_GetScopeChain(cx, fp);
4941             if (!obj2) {
4942                 ok = JS_FALSE;
4943                 goto out;
4944             }
4945             parent = js_NewObject(cx, &js_ObjectClass, NULL, obj2);
4946             if (!parent) {
4947                 ok = JS_FALSE;
4948                 goto out;
4949             }
4950 
4951             /*
4952              * 3. Create a new Function object as specified in section 13.2
4953              * with [parameters and body specified by the function expression
4954              * that was parsed by the compiler into a Function object, and
4955              * saved in the script's atom map].
4956              *
4957              * Protect parent from GC after js_CloneFunctionObject calls into
4958              * js_NewObject, which displaces the newborn object root in cx by
4959              * allocating the clone, then runs a last-ditch GC while trying
4960              * to allocate the clone's slots vector.  Another, multi-threaded
4961              * path: js_CloneFunctionObject => js_NewObject => OBJ_GET_CLASS
4962              * which may suspend the current request in ClaimScope, with the
4963              * newborn displaced as in the first scenario.
4964              */
4965             fp->scopeChain = parent;
4966             obj = js_CloneFunctionObject(cx, JSVAL_TO_OBJECT(rval), parent);
4967             if (!obj) {
4968                 ok = JS_FALSE;
4969                 goto out;
4970             }
4971 
4972             /*
4973              * Protect obj from any GC hiding below OBJ_DEFINE_PROPERTY.  All
4974              * paths from here must flow through the "Restore fp->scopeChain"
4975              * code below the OBJ_DEFINE_PROPERTY call.
4976              */
4977             fp->scopeChain = obj;
4978             rval = OBJECT_TO_JSVAL(obj);
4979 
4980             /*
4981              * 4. Create a property in the object Result(1).  The property's
4982              * name is [fun->atom, the identifier parsed by the compiler],
4983              * value is Result(3), and attributes are { DontDelete, ReadOnly }.
4984              */
4985             fun = (JSFunction *) JS_GetPrivate(cx, obj);
4986             attrs = JSFUN_GSFLAG2ATTR(fun->flags);
4987             if (attrs) {
4988                 attrs |= JSPROP_SHARED;
4989                 rval = JSVAL_VOID;
4990             }
4991             ok = OBJ_DEFINE_PROPERTY(cx, parent, ATOM_TO_JSID(fun->atom), rval,
4992                                      (attrs & JSPROP_GETTER)
4993                                      ? JS_EXTENSION (JSPropertyOp) obj
4994                                      : NULL,
4995                                      (attrs & JSPROP_SETTER)
4996                                      ? JS_EXTENSION (JSPropertyOp) obj
4997                                      : NULL,
4998                                      attrs |
4999                                      JSPROP_ENUMERATE | JSPROP_PERMANENT |
5000                                      JSPROP_READONLY,
5001                                      NULL);
5002 
5003             /* Restore fp->scopeChain now that obj is defined in parent. */
5004             fp->scopeChain = obj2;
5005             if (!ok) {
5006                 cx->weakRoots.newborn[GCX_OBJECT] = NULL;
5007                 goto out;
5008             }
5009 
5010             /*
5011              * 5. Remove Result(1) from the front of the scope chain [no-op].
5012              * 6. Return Result(3).
5013              */
5014             PUSH_OPND(OBJECT_TO_JSVAL(obj));
5015             obj = NULL;
5016           END_LITOPX_CASE(JSOP_NAMEDFUNOBJ)
5017 
5018           BEGIN_LITOPX_CASE(JSOP_CLOSURE, 0)
5019             /*
5020              * ECMA ed. 3 extension: a named function expression in a compound
5021              * statement (not at the top statement level of global code, or at
5022              * the top level of a function body).
5023              *
5024              * Get immediate operand atom, which is a function object literal.
5025              * From it, get the function to close.
5026              */
5027             JS_ASSERT(VALUE_IS_FUNCTION(cx, ATOM_KEY(atom)));
5028             obj = ATOM_TO_OBJECT(atom);
5029 
5030             /*
5031              * Clone the function object with the current scope chain as the
5032              * clone's parent.  The original function object is the prototype
5033              * of the clone.  Do this only if re-parenting; the compiler may
5034              * have seen the right parent already and created a sufficiently
5035              * well-scoped function object.
5036              */
5037             SAVE_SP_AND_PC(fp);
5038             obj2 = js_GetScopeChain(cx, fp);
5039             if (!obj2) {
5040                 ok = JS_FALSE;
5041                 goto out;
5042             }
5043             if (OBJ_GET_PARENT(cx, obj) != obj2) {
5044                 obj = js_CloneFunctionObject(cx, obj, obj2);
5045                 if (!obj) {
5046                     ok = JS_FALSE;
5047                     goto out;
5048                 }
5049             }
5050 
5051             /*
5052              * Protect obj from any GC hiding below OBJ_DEFINE_PROPERTY.  All
5053              * paths from here must flow through the "Restore fp->scopeChain"
5054              * code below the OBJ_DEFINE_PROPERTY call.
5055              */
5056             fp->scopeChain = obj;
5057             rval = OBJECT_TO_JSVAL(obj);
5058 
5059             /*
5060              * Make a property in fp->varobj with id fun->atom and value obj,
5061              * unless fun is a getter or setter (in which case, obj is cast to
5062              * a JSPropertyOp and passed accordingly).
5063              */
5064             fun = (JSFunction *) JS_GetPrivate(cx, obj);
5065             attrs = JSFUN_GSFLAG2ATTR(fun->flags);
5066             if (attrs) {
5067                 attrs |= JSPROP_SHARED;
5068                 rval = JSVAL_VOID;
5069             }
5070             parent = fp->varobj;
5071             ok = OBJ_DEFINE_PROPERTY(cx, parent, ATOM_TO_JSID(fun->atom), rval,
5072                                      (attrs & JSPROP_GETTER)
5073                                      ? JS_EXTENSION (JSPropertyOp) obj
5074                                      : NULL,
5075                                      (attrs & JSPROP_SETTER)
5076                                      ? JS_EXTENSION (JSPropertyOp) obj
5077                                      : NULL,
5078                                      attrs | JSPROP_ENUMERATE
5079                                            | JSPROP_PERMANENT,
5080                                      &prop);
5081 
5082             /* Restore fp->scopeChain now that obj is defined in fp->varobj. */
5083             fp->scopeChain = obj2;
5084             if (!ok) {
5085                 cx->weakRoots.newborn[GCX_OBJECT] = NULL;
5086                 goto out;
5087             }
5088 
5089 #if 0
5090             if (attrs == 0 && script->numGlobalVars) {
5091                 /*
5092                  * As with JSOP_DEFVAR and JSOP_DEFCONST (above), fast globals
5093                  * use fp->vars to map the global function name's atomIndex to
5094                  * its permanent fp->varobj slot number, tagged as a jsval.
5095                  */
5096                 sprop = (JSScopeProperty *) prop;
5097                 fp->vars[atomIndex] = INT_TO_JSVAL(sprop->slot);
5098             }
5099 #endif
5100             OBJ_DROP_PROPERTY(cx, parent, prop);
5101           END_LITOPX_CASE(JSOP_CLOSURE)
5102 
5103 #if JS_HAS_GETTER_SETTER
5104           BEGIN_CASE(JSOP_GETTER)
5105           BEGIN_CASE(JSOP_SETTER)
5106             op2 = (JSOp) *++pc;
5107             switch (op2) {
5108               case JSOP_SETNAME:
5109               case JSOP_SETPROP:
5110                 atom = GET_ATOM(cx, script, pc);
5111                 id   = ATOM_TO_JSID(atom);
5112                 rval = FETCH_OPND(-1);
5113                 i = -1;
5114                 goto gs_pop_lval;
5115 
5116               case JSOP_SETELEM:
5117                 rval = FETCH_OPND(-1);
5118                 FETCH_ELEMENT_ID(-2, id);
5119                 i = -2;
5120               gs_pop_lval:
5121                 FETCH_OBJECT(cx, i - 1, lval, obj);
5122                 break;
5123 
5124               case JSOP_INITPROP:
5125                 JS_ASSERT(sp - fp->spbase >= 2);
5126                 rval = FETCH_OPND(-1);
5127                 i = -1;
5128                 atom = GET_ATOM(cx, script, pc);
5129                 id   = ATOM_TO_JSID(atom);
5130                 goto gs_get_lval;
5131 
5132               case JSOP_INITELEM:
5133                 JS_ASSERT(sp - fp->spbase >= 3);
5134                 rval = FETCH_OPND(-1);
5135                 FETCH_ELEMENT_ID(-2, id);
5136                 i = -2;
5137               gs_get_lval:
5138                 lval = FETCH_OPND(i-1);
5139                 JS_ASSERT(JSVAL_IS_OBJECT(lval));
5140                 obj = JSVAL_TO_OBJECT(lval);
5141                 break;
5142 
5143               default:
5144                 JS_ASSERT(0);
5145             }
5146 
5147             /* Ensure that id has a type suitable for use with obj. */
5148             CHECK_ELEMENT_ID(obj, id);
5149 
5150             SAVE_SP_AND_PC(fp);
5151             if (JS_TypeOfValue(cx, rval) != JSTYPE_FUNCTION) {
5152                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
5153                                      JSMSG_BAD_GETTER_OR_SETTER,
5154                                      (op == JSOP_GETTER)
5155                                      ? js_getter_str
5156                                      : js_setter_str);
5157                 ok = JS_FALSE;
5158                 goto out;
5159             }
5160 
5161             /*
5162              * Getters and setters are just like watchpoints from an access
5163              * control point of view.
5164              */
5165             ok = OBJ_CHECK_ACCESS(cx, obj, id, JSACC_WATCH, &rtmp, &attrs);
5166             if (!ok)
5167                 goto out;
5168 
5169             if (op == JSOP_GETTER) {
5170                 getter = JS_EXTENSION (JSPropertyOp) JSVAL_TO_OBJECT(rval);
5171                 setter = NULL;
5172                 attrs = JSPROP_GETTER;
5173             } else {
5174                 getter = NULL;
5175                 setter = JS_EXTENSION (JSPropertyOp) JSVAL_TO_OBJECT(rval);
5176                 attrs = JSPROP_SETTER;
5177             }
5178             attrs |= JSPROP_ENUMERATE | JSPROP_SHARED;
5179 
5180             /* Check for a readonly or permanent property of the same name. */
5181             ok = js_CheckRedeclaration(cx, obj, id, attrs, NULL, NULL);
5182             if (!ok)
5183                 goto out;
5184 
5185             ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, getter, setter,
5186                                      attrs, NULL);
5187             if (!ok)
5188                 goto out;
5189 
5190             obj = NULL;
5191             sp += i;
5192             if (js_CodeSpec[op2].ndefs)
5193                 STORE_OPND(-1, rval);
5194             len = js_CodeSpec[op2].length;
5195             DO_NEXT_OP(len);
5196 #endif /* JS_HAS_GETTER_SETTER */
5197 
5198           BEGIN_CASE(JSOP_NEWINIT)
5199             argc = 0;
5200             fp->sharpDepth++;
5201             goto do_new;
5202 
5203           BEGIN_CASE(JSOP_ENDINIT)
5204             if (--fp->sharpDepth == 0)
5205                 fp->sharpArray = NULL;
5206 
5207             /* Re-set the newborn root to the top of this object tree. */
5208             JS_ASSERT(sp - fp->spbase >= 1);
5209             lval = FETCH_OPND(-1);
5210             JS_ASSERT(JSVAL_IS_OBJECT(lval));
5211             cx->weakRoots.newborn[GCX_OBJECT] = JSVAL_TO_GCTHING(lval);
5212           END_CASE(JSOP_ENDINIT)
5213 
5214           BEGIN_CASE(JSOP_INITPROP)
5215             /* Pop the property's value into rval. */
5216             JS_ASSERT(sp - fp->spbase >= 2);
5217             rval = FETCH_OPND(-1);
5218 
5219             /* Get the immediate property name into id. */
5220             atom = GET_ATOM(cx, script, pc);
5221             id   = ATOM_TO_JSID(atom);
5222             i = -1;
5223             goto do_init;
5224 
5225           BEGIN_CASE(JSOP_INITELEM)
5226             /* Pop the element's value into rval. */
5227             JS_ASSERT(sp - fp->spbase >= 3);
5228             rval = FETCH_OPND(-1);
5229 
5230             /* Pop and conditionally atomize the element id. */
5231             FETCH_ELEMENT_ID(-2, id);
5232             i = -2;
5233 
5234           do_init:
5235             /* Find the object being initialized at top of stack. */
5236             lval = FETCH_OPND(i-1);
5237             JS_ASSERT(JSVAL_IS_OBJECT(lval));
5238             obj = JSVAL_TO_OBJECT(lval);
5239 
5240             /* Ensure that id has a type suitable for use with obj. */
5241             CHECK_ELEMENT_ID(obj, id);
5242 
5243             /* Set the property named by obj[id] to rval. */
5244             SAVE_SP_AND_PC(fp);
5245             ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
5246             if (!ok)
5247                 goto out;
5248             sp += i;
5249             len = js_CodeSpec[op].length;
5250             DO_NEXT_OP(len);
5251 
5252 #if JS_HAS_SHARP_VARS
5253           BEGIN_CASE(JSOP_DEFSHARP)
5254             SAVE_SP_AND_PC(fp);
5255             obj = fp->sharpArray;
5256             if (!obj) {
5257                 obj = js_NewArrayObject(cx, 0, NULL);
5258                 if (!obj) {
5259                     ok = JS_FALSE;
5260                     goto out;
5261                 }
5262                 fp->sharpArray = obj;
5263             }
5264             i = (jsint) GET_ATOM_INDEX(pc);
5265             id = INT_TO_JSID(i);
5266             rval = FETCH_OPND(-1);
5267             if (JSVAL_IS_PRIMITIVE(rval)) {
5268                 char numBuf[12];
5269                 JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i);
5270                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
5271                                      JSMSG_BAD_SHARP_DEF, numBuf);
5272                 ok = JS_FALSE;
5273                 goto out;
5274             }
5275             ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
5276             if (!ok)
5277                 goto out;
5278           END_CASE(JSOP_DEFSHARP)
5279 
5280           BEGIN_CASE(JSOP_USESHARP)
5281             i = (jsint) GET_ATOM_INDEX(pc);
5282             id = INT_TO_JSID(i);
5283             obj = fp->sharpArray;
5284             if (!obj) {
5285                 rval = JSVAL_VOID;
5286             } else {
5287                 SAVE_SP_AND_PC(fp);
5288                 ok = OBJ_GET_PROPERTY(cx, obj, id, &rval);
5289                 if (!ok)
5290                     goto out;
5291             }
5292             if (!JSVAL_IS_OBJECT(rval)) {
5293                 char numBuf[12];
5294                 JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i);
5295 
5296                 SAVE_SP_AND_PC(fp);
5297                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
5298                                      JSMSG_BAD_SHARP_USE, numBuf);
5299                 ok = JS_FALSE;
5300                 goto out;
5301             }
5302             PUSH_OPND(rval);
5303           END_CASE(JSOP_USESHARP)
5304 #endif /* JS_HAS_SHARP_VARS */
5305 
5306           /* No-ops for ease of decompilation and jit'ing. */
5307           EMPTY_CASE(JSOP_TRY)
5308           EMPTY_CASE(JSOP_FINALLY)
5309 
5310           /* Reset the stack to the given depth. */
5311           BEGIN_CASE(JSOP_SETSP)
5312             i = (jsint) GET_ATOM_INDEX(pc);
5313             JS_ASSERT(i >= 0);
5314 
5315             for (obj = fp->blockChain; obj; obj = OBJ_GET_PARENT(cx, obj)) {
5316                 JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_BlockClass);
5317                 if (OBJ_BLOCK_DEPTH(cx, obj) + (jsint)OBJ_BLOCK_COUNT(cx, obj) <= i) {
5318                     JS_ASSERT(OBJ_BLOCK_DEPTH(cx, obj) < i || OBJ_BLOCK_COUNT(cx, obj) == 0);
5319                     break;
5320                 }
5321             }
5322             fp->blockChain = obj;
5323 
5324             JS_ASSERT(ok);
5325             for (obj = fp->scopeChain;
5326                  (clasp = OBJ_GET_CLASS(cx, obj)) == &js_WithClass ||
5327                  clasp == &js_BlockClass;
5328                  obj = OBJ_GET_PARENT(cx, obj)) {
5329                 if (JS_GetPrivate(cx, obj) != fp ||
5330                     OBJ_BLOCK_DEPTH(cx, obj) < i) {
5331                     break;
5332                 }
5333                 if (clasp == &js_BlockClass)
5334                     ok &= js_PutBlockObject(cx, obj);
5335                 else
5336                     JS_SetPrivate(cx, obj, NULL);
5337             }
5338 
5339             fp->scopeChain = obj;
5340 
5341             /* Set sp after js_PutBlockObject to avoid potential GC hazards. */
5342             sp = fp->spbase + i;
5343 
5344             /* Don't fail until after we've updated all stacks. */
5345             if (!ok)
5346                 goto out;
5347           END_CASE(JSOP_SETSP)
5348 
5349           BEGIN_CASE(JSOP_GOSUB)
5350             JS_ASSERT(cx->exception != JSVAL_HOLE);
5351             if (!cx->throwing) {
5352                 lval = JSVAL_HOLE;
5353             } else {
5354                 lval = cx->exception;
5355                 cx->throwing = JS_FALSE;
5356             }
5357             PUSH(lval);
5358             i = PTRDIFF(pc, script->main, jsbytecode) + JSOP_GOSUB_LENGTH;
5359             len = GET_JUMP_OFFSET(pc);
5360             PUSH(INT_TO_JSVAL(i));
5361           END_VARLEN_CASE
5362 
5363           BEGIN_CASE(JSOP_GOSUBX)
5364             JS_ASSERT(cx->exception != JSVAL_HOLE);
5365             if (!cx->throwing) {
5366                 lval = JSVAL_HOLE;
5367             } else {
5368                 lval = cx->exception;
5369                 cx->throwing = JS_FALSE;
5370             }
5371             PUSH(lval);
5372             i = PTRDIFF(pc, script->main, jsbytecode) + JSOP_GOSUBX_LENGTH;
5373             len = GET_JUMPX_OFFSET(pc);
5374             PUSH(INT_TO_JSVAL(i));
5375           END_VARLEN_CASE
5376 
5377           BEGIN_CASE(JSOP_RETSUB)
5378             rval = POP();
5379             JS_ASSERT(JSVAL_IS_INT(rval));
5380             lval = POP();
5381             if (lval != JSVAL_HOLE) {
5382                 /*
5383                  * Exception was pending during finally, throw it *before* we
5384                  * adjust pc, because pc indexes into script->trynotes.  This
5385                  * turns out not to be necessary, but it seems clearer.  And
5386                  * it points out a FIXME: 350509, due to Igor Bukanov.
5387                  */
5388                 cx->throwing = JS_TRUE;
5389                 cx->exception = lval;
5390                 ok = JS_FALSE;
5391                 goto out;
5392             }
5393             len = JSVAL_TO_INT(rval);
5394             pc = script->main;
5395           END_VARLEN_CASE
5396 
5397           BEGIN_CASE(JSOP_EXCEPTION)
5398             JS_ASSERT(cx->throwing);
5399             PUSH(cx->exception);
5400             cx->throwing = JS_FALSE;
5401           END_CASE(JSOP_EXCEPTION)
5402 
5403           BEGIN_CASE(JSOP_THROWING)
5404             JS_ASSERT(!cx->throwing);
5405             cx->throwing = JS_TRUE;
5406             cx->exception = POP_OPND();
5407           END_CASE(JSOP_THROWING)
5408 
5409           BEGIN_CASE(JSOP_THROW)
5410             JS_ASSERT(!cx->throwing);
5411             cx->throwing = JS_TRUE;
5412             cx->exception = POP_OPND();
5413             ok = JS_FALSE;
5414             /* let the code at out try to catch the exception. */
5415             goto out;
5416 
5417           BEGIN_CASE(JSOP_SETLOCALPOP)
5418             /*
5419              * The stack must have a block with at least one local slot below
5420              * the exception object.
5421              */
5422             JS_ASSERT(sp - fp->spbase >= 2);
5423             slot = GET_UINT16(pc);
5424             JS_ASSERT(slot + 1 < (uintN)depth);
5425             fp->spbase[slot] = POP_OPND();
5426           END_CASE(JSOP_SETLOCALPOP)
5427 
5428           BEGIN_CASE(JSOP_INSTANCEOF)
5429             SAVE_SP_AND_PC(fp);
5430             rval = FETCH_OPND(-1);
5431             if (JSVAL_IS_PRIMITIVE(rval) ||
5432                 !(obj = JSVAL_TO_OBJECT(rval))->map->ops->hasInstance) {
5433                 str = js_DecompileValueGenerator(cx, -1, rval, NULL);
5434                 if (str) {
5435                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
5436                                          JSMSG_BAD_INSTANCEOF_RHS,
5437                                          JS_GetStringBytes(str));
5438                 }
5439                 ok = JS_FALSE;
5440                 goto out;
5441             }
5442             lval = FETCH_OPND(-2);
5443             cond = JS_FALSE;
5444             ok = obj->map->ops->hasInstance(cx, obj, lval, &cond);
5445             if (!ok)
5446                 goto out;
5447             sp--;
5448             STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));
5449           END_CASE(JSOP_INSTANCEOF)
5450 
5451 #if JS_HAS_DEBUGGER_KEYWORD
5452           BEGIN_CASE(JSOP_DEBUGGER)
5453           {
5454             JSTrapHandler handler = rt->debuggerHandler;
5455             if (handler) {
5456                 SAVE_SP_AND_PC(fp);
5457                 switch (handler(cx, script, pc, &rval,
5458                                 rt->debuggerHandlerData)) {
5459                   case JSTRAP_ERROR:
5460                     ok = JS_FALSE;
5461                     goto out;
5462                   case JSTRAP_CONTINUE:
5463                     break;
5464                   case JSTRAP_RETURN:
5465                     fp->rval = rval;
5466                     goto out;
5467                   case JSTRAP_THROW:
5468                     cx->throwing = JS_TRUE;
5469                     cx->exception = rval;
5470                     ok = JS_FALSE;
5471                     goto out;
5472                   default:;
5473                 }
5474                 LOAD_INTERRUPT_HANDLER(rt);
5475             }
5476           }
5477           END_CASE(JSOP_DEBUGGER)
5478 #endif /* JS_HAS_DEBUGGER_KEYWORD */
5479 
5480 #if JS_HAS_XML_SUPPORT
5481           BEGIN_CASE(JSOP_DEFXMLNS)
5482             rval = POP();
5483             SAVE_SP_AND_PC(fp);
5484             ok = js_SetDefaultXMLNamespace(cx, rval);
5485             if (!ok)
5486                 goto out;
5487           END_CASE(JSOP_DEFXMLNS)
5488 
5489           BEGIN_CASE(JSOP_ANYNAME)
5490             SAVE_SP_AND_PC(fp);
5491             ok = js_GetAnyName(cx, &rval);
5492             if (!ok)
5493                 goto out;
5494             PUSH_OPND(rval);
5495           END_CASE(JSOP_ANYNAME)
5496 
5497           BEGIN_LITOPX_CASE(JSOP_QNAMEPART, 0)
5498             PUSH_OPND(ATOM_KEY(atom));
5499           END_LITOPX_CASE(JSOP_QNAMEPART)
5500 
5501           BEGIN_LITOPX_CASE(JSOP_QNAMECONST, 0)
5502             rval = ATOM_KEY(atom);
5503             lval = FETCH_OPND(-1);
5504             SAVE_SP_AND_PC(fp);
5505             obj = js_ConstructXMLQNameObject(cx, lval, rval);
5506             if (!obj) {
5507                 ok = JS_FALSE;
5508                 goto out;
5509             }
5510             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
5511           END_LITOPX_CASE(JSOP_QNAMECONST)
5512 
5513           BEGIN_CASE(JSOP_QNAME)
5514             rval = FETCH_OPND(-1);
5515             lval = FETCH_OPND(-2);
5516             SAVE_SP_AND_PC(fp);
5517             obj = js_ConstructXMLQNameObject(cx, lval, rval);
5518             if (!obj) {
5519                 ok = JS_FALSE;
5520                 goto out;
5521             }
5522             sp--;
5523             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
5524           END_CASE(JSOP_QNAME)
5525 
5526           BEGIN_CASE(JSOP_TOATTRNAME)
5527             rval = FETCH_OPND(-1);
5528             SAVE_SP_AND_PC(fp);
5529             ok = js_ToAttributeName(cx, &rval);
5530             if (!ok)
5531                 goto out;
5532             STORE_OPND(-1, rval);
5533           END_CASE(JSOP_TOATTRNAME)
5534 
5535           BEGIN_CASE(JSOP_TOATTRVAL)
5536             rval = FETCH_OPND(-1);
5537             JS_ASSERT(JSVAL_IS_STRING(rval));
5538             SAVE_SP_AND_PC(fp);
5539             str = js_EscapeAttributeValue(cx, JSVAL_TO_STRING(rval));
5540             if (!str) {
5541                 ok = JS_FALSE;
5542                 goto out;
5543             }
5544             STORE_OPND(-1, STRING_TO_JSVAL(str));
5545           END_CASE(JSOP_TOATTRVAL)
5546 
5547           BEGIN_CASE(JSOP_ADDATTRNAME)
5548           BEGIN_CASE(JSOP_ADDATTRVAL)
5549             rval = FETCH_OPND(-1);
5550             lval = FETCH_OPND(-2);
5551             str = JSVAL_TO_STRING(lval);
5552             str2 = JSVAL_TO_STRING(rval);
5553             SAVE_SP_AND_PC(fp);
5554             str = js_AddAttributePart(cx, op == JSOP_ADDATTRNAME, str, str2);
5555             if (!str) {
5556                 ok = JS_FALSE;
5557                 goto out;
5558             }
5559             sp--;
5560             STORE_OPND(-1, STRING_TO_JSVAL(str));
5561           END_CASE(JSOP_ADDATTRNAME)
5562 
5563           BEGIN_CASE(JSOP_BINDXMLNAME)
5564             lval = FETCH_OPND(-1);
5565             SAVE_SP_AND_PC(fp);
5566             ok = js_FindXMLProperty(cx, lval, &obj, &rval);
5567             if (!ok)
5568                 goto out;
5569             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
5570             PUSH_OPND(rval);
5571           END_CASE(JSOP_BINDXMLNAME)
5572 
5573           BEGIN_CASE(JSOP_SETXMLNAME)
5574             obj = JSVAL_TO_OBJECT(FETCH_OPND(-3));
5575             lval = FETCH_OPND(-2);
5576             rval = FETCH_OPND(-1);
5577             SAVE_SP_AND_PC(fp);
5578             ok = js_SetXMLProperty(cx, obj, lval, &rval);
5579             if (!ok)
5580                 goto out;
5581             sp -= 2;
5582             STORE_OPND(-1, rval);
5583             obj = NULL;
5584           END_CASE(JSOP_SETXMLNAME)
5585 
5586           BEGIN_CASE(JSOP_XMLNAME)
5587             lval = FETCH_OPND(-1);
5588             SAVE_SP_AND_PC(fp);
5589             ok = js_FindXMLProperty(cx, lval, &obj, &rval);
5590             if (!ok)
5591                 goto out;
5592             ok = js_GetXMLProperty(cx, obj, rval, &rval);
5593             if (!ok)
5594                 goto out;
5595             STORE_OPND(-1, rval);
5596           END_CASE(JSOP_XMLNAME)
5597 
5598           BEGIN_CASE(JSOP_DESCENDANTS)
5599           BEGIN_CASE(JSOP_DELDESC)
5600             FETCH_OBJECT(cx, -2, lval, obj);
5601             rval = FETCH_OPND(-1);
5602             SAVE_SP_AND_PC(fp);
5603             ok = js_GetXMLDescendants(cx, obj, rval, &rval);
5604             if (!ok)
5605                 goto out;
5606 
5607             if (op == JSOP_DELDESC) {
5608                 sp[-1] = rval;          /* set local root */
5609                 ok = js_DeleteXMLListElements(cx, JSVAL_TO_OBJECT(rval));
5610                 if (!ok)
5611                     goto out;
5612                 rval = JSVAL_TRUE;      /* always succeed */
5613             }
5614 
5615             sp--;
5616             STORE_OPND(-1, rval);
5617           END_CASE(JSOP_DESCENDANTS)
5618 
5619           BEGIN_CASE(JSOP_FILTER)
5620             FETCH_OBJECT(cx, -1, lval, obj);
5621             len = GET_JUMP_OFFSET(pc);
5622             SAVE_SP_AND_PC(fp);
5623             ok = js_FilterXMLList(cx, obj, pc + js_CodeSpec[op].length, &rval);
5624             if (!ok)
5625                 goto out;
5626             JS_ASSERT(fp->sp == sp);
5627             STORE_OPND(-1, rval);
5628           END_VARLEN_CASE
5629 
5630           BEGIN_CASE(JSOP_ENDFILTER)
5631             *result = POP_OPND();
5632             goto out;
5633 
5634           EMPTY_CASE(JSOP_STARTXML)
5635           EMPTY_CASE(JSOP_STARTXMLEXPR)
5636 
5637           BEGIN_CASE(JSOP_TOXML)
5638             rval = FETCH_OPND(-1);
5639             SAVE_SP_AND_PC(fp);
5640             obj = js_ValueToXMLObject(cx, rval);
5641             if (!obj) {
5642                 ok = JS_FALSE;
5643                 goto out;
5644             }
5645             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
5646           END_CASE(JSOP_TOXML)
5647 
5648           BEGIN_CASE(JSOP_TOXMLLIST)
5649             rval = FETCH_OPND(-1);
5650             SAVE_SP_AND_PC(fp);
5651             obj = js_ValueToXMLListObject(cx, rval);
5652             if (!obj) {
5653                 ok = JS_FALSE;
5654                 goto out;
5655             }
5656             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
5657           END_CASE(JSOP_TOXMLLIST)
5658 
5659           BEGIN_CASE(JSOP_XMLTAGEXPR)
5660             rval = FETCH_OPND(-1);
5661             SAVE_SP_AND_PC(fp);
5662             str = js_ValueToString(cx, rval);
5663             if (!str) {
5664                 ok = JS_FALSE;
5665                 goto out;
5666             }
5667             STORE_OPND(-1, STRING_TO_JSVAL(str));
5668           END_CASE(JSOP_XMLTAGEXPR)
5669 
5670           BEGIN_CASE(JSOP_XMLELTEXPR)
5671             rval = FETCH_OPND(-1);
5672             SAVE_SP_AND_PC(fp);
5673             if (VALUE_IS_XML(cx, rval)) {
5674                 str = js_ValueToXMLString(cx, rval);
5675             } else {
5676                 str = js_ValueToString(cx, rval);
5677                 if (str)
5678                     str = js_EscapeElementValue(cx, str);
5679             }
5680             if (!str) {
5681                 ok = JS_FALSE;
5682                 goto out;
5683             }
5684             STORE_OPND(-1, STRING_TO_JSVAL(str));
5685           END_CASE(JSOP_XMLELTEXPR)
5686 
5687           BEGIN_LITOPX_CASE(JSOP_XMLOBJECT, 0)
5688             SAVE_SP_AND_PC(fp);
5689             obj = js_CloneXMLObject(cx, ATOM_TO_OBJECT(atom));
5690             if (!obj) {
5691                 ok = JS_FALSE;
5692                 goto out;
5693             }
5694             PUSH_OPND(OBJECT_TO_JSVAL(obj));
5695             obj = NULL;
5696           END_LITOPX_CASE(JSOP_XMLOBJECT)
5697 
5698           BEGIN_LITOPX_CASE(JSOP_XMLCDATA, 0)
5699             str = ATOM_TO_STRING(atom);
5700             obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_TEXT, NULL, str);
5701             if (!obj) {
5702                 ok = JS_FALSE;
5703                 goto out;
5704             }
5705             PUSH_OPND(OBJECT_TO_JSVAL(obj));
5706           END_LITOPX_CASE(JSOP_XMLCDATA)
5707 
5708           BEGIN_LITOPX_CASE(JSOP_XMLCOMMENT, 0)
5709             str = ATOM_TO_STRING(atom);
5710             obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_COMMENT, NULL, str);
5711             if (!obj) {
5712                 ok = JS_FALSE;
5713                 goto out;
5714             }
5715             PUSH_OPND(OBJECT_TO_JSVAL(obj));
5716           END_LITOPX_CASE(JSOP_XMLCOMMENT)
5717 
5718           BEGIN_LITOPX_CASE(JSOP_XMLPI, 0)
5719             str = ATOM_TO_STRING(atom);
5720             rval = FETCH_OPND(-1);
5721             str2 = JSVAL_TO_STRING(rval);
5722             SAVE_SP_AND_PC(fp);
5723             obj = js_NewXMLSpecialObject(cx,
5724                                          JSXML_CLASS_PROCESSING_INSTRUCTION,
5725                                          str, str2);
5726             if (!obj) {
5727                 ok = JS_FALSE;
5728                 goto out;
5729             }
5730             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
5731           END_LITOPX_CASE(JSOP_XMLPI)
5732 
5733           BEGIN_LITOPX_CASE(JSOP_GETMETHOD, 0)
5734             /* Get an immediate atom naming the property. */
5735             id   = ATOM_TO_JSID(atom);
5736             lval = FETCH_OPND(-1);
5737             SAVE_SP_AND_PC(fp);
5738             if (!JSVAL_IS_PRIMITIVE(lval)) {
5739                 STORE_OPND(-1, lval);
5740                 obj = JSVAL_TO_OBJECT(lval);
5741 
5742                 /* Special-case XML object method lookup, per ECMA-357. */
5743                 if (OBJECT_IS_XML(cx, obj)) {
5744                     JSXMLObjectOps *ops;
5745 
5746                     ops = (JSXMLObjectOps *) obj->map->ops;
5747                     obj = ops->getMethod(cx, obj, id, &rval);
5748                     if (!obj)
5749                         ok = JS_FALSE;
5750                 } else {
5751                     CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval));
5752                 }
5753             } else {
5754                 if (JSVAL_IS_STRING(lval)) {
5755                     i = JSProto_String;
5756                 } else if (JSVAL_IS_NUMBER(lval)) {
5757                     i = JSProto_Number;
5758                 } else if (JSVAL_IS_BOOLEAN(lval)) {
5759                     i = JSProto_Boolean;
5760                 } else {
5761                     JS_ASSERT(JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval));
5762                     str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
5763                                                      lval, NULL);
5764                     if (str) {
5765                         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
5766                                              JSMSG_NO_PROPERTIES,
5767                                              JS_GetStringBytes(str));
5768                     }
5769                     ok = JS_FALSE;
5770                     goto out;
5771                 }
5772                 ok = js_GetClassPrototype(cx, NULL, INT_TO_JSID(i), &obj);
5773                 if (!ok)
5774                     goto out;
5775                 JS_ASSERT(obj);
5776                 STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
5777                 CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval));
5778                 obj = (JSObject *) lval; /* keep tagged as non-object */
5779             }
5780             if (!ok)
5781                 goto out;
5782             STORE_OPND(-1, rval);
5783           END_LITOPX_CASE(JSOP_GETMETHOD)
5784 
5785           BEGIN_LITOPX_CASE(JSOP_SETMETHOD, 0)
5786             /* Get an immediate atom naming the property. */
5787             id   = ATOM_TO_JSID(atom);
5788             rval = FETCH_OPND(-1);
5789             FETCH_OBJECT(cx, -2, lval, obj);
5790             SAVE_SP_AND_PC(fp);
5791 
5792             /* Special-case XML object method lookup, per ECMA-357. */
5793             if (OBJECT_IS_XML(cx, obj)) {
5794                 JSXMLObjectOps *ops;
5795 
5796                 ops = (JSXMLObjectOps *) obj->map->ops;
5797                 ok = ops->setMethod(cx, obj, id, &rval);
5798             } else {
5799                 CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval));
5800             }
5801             if (!ok)
5802                 goto out;
5803             --sp;
5804             STORE_OPND(-1, rval);
5805             obj = NULL;
5806           END_LITOPX_CASE(JSOP_SETMETHOD)
5807 
5808           BEGIN_CASE(JSOP_GETFUNNS)
5809             SAVE_SP_AND_PC(fp);
5810             ok = js_GetFunctionNamespace(cx, &rval);
5811             if (!ok)
5812                 goto out;
5813             PUSH_OPND(rval);
5814           END_CASE(JSOP_GETFUNNS)
5815 #endif /* JS_HAS_XML_SUPPORT */
5816 
5817           BEGIN_LITOPX_CASE(JSOP_ENTERBLOCK, 0)
5818             obj = ATOM_TO_OBJECT(atom);
5819             JS_ASSERT(fp->spbase + OBJ_BLOCK_DEPTH(cx, obj) == sp);
5820             vp = sp + OBJ_BLOCK_COUNT(cx, obj);
5821             JS_ASSERT(vp <= fp->spbase + depth);
5822             while (sp < vp) {
5823                 STORE_OPND(0, JSVAL_VOID);
5824                 sp++;
5825             }
5826 
5827             /*
5828              * If this frame had to reflect the compile-time block chain into
5829              * the runtime scope chain, we can't optimize block scopes out of
5830              * runtime any longer, because an outer block that parents obj has
5831              * been cloned onto the scope chain.  To avoid re-cloning such a
5832              * parent and accumulating redundant clones via js_GetScopeChain,
5833              * we must clone each block eagerly on entry, and push it on the
5834              * scope chain, until this frame pops.
5835              */
5836             if (fp->flags & JSFRAME_POP_BLOCKS) {
5837                 JS_ASSERT(!fp->blockChain);
5838 
5839                 /*
5840                  * Check whether JSOP_DEFLOCALFUN emulated JSOP_ENTERBLOCK for
5841                  * the body block in order to correctly scope the local cloned
5842                  * function object it creates.
5843                  */
5844                 parent = fp->scopeChain;
5845                 if (OBJ_GET_PROTO(cx, parent) == obj) {
5846                     JS_ASSERT(OBJ_GET_CLASS(cx, parent) == &js_BlockClass);
5847                 } else {
5848                     obj = js_CloneBlockObject(cx, obj, parent, fp);
5849                     if (!obj) {
5850                         ok = JS_FALSE;
5851                         goto out;
5852                     }
5853                     fp->scopeChain = obj;
5854                 }
5855             } else {
5856                 JS_ASSERT(!fp->blockChain ||
5857                           OBJ_GET_PARENT(cx, obj) == fp->blockChain);
5858                 fp->blockChain = obj;
5859             }
5860           END_LITOPX_CASE(JSOP_ENTERBLOCK)
5861 
5862           BEGIN_CASE(JSOP_LEAVEBLOCKEXPR)
5863           BEGIN_CASE(JSOP_LEAVEBLOCK)
5864           {
5865             JSObject **chainp;
5866 
5867             /* Grab the result of the expression. */
5868             if (op == JSOP_LEAVEBLOCKEXPR)
5869                 rval = FETCH_OPND(-1);
5870 
5871             chainp = &fp->blockChain;
5872             obj = *chainp;
5873             if (!obj) {
5874                 chainp = &fp->scopeChain;
5875                 obj = *chainp;
5876 
5877                 /*
5878                  * This block was cloned, so clear its private data and sync
5879                  * its locals to their property slots.
5880                  */
5881                 SAVE_SP_AND_PC(fp);
5882                 ok = js_PutBlockObject(cx, obj);
5883                 if (!ok)
5884                     goto out;
5885             }
5886 
5887             sp -= GET_UINT16(pc);
5888             JS_ASSERT(fp->spbase <= sp && sp <= fp->spbase + depth);
5889 
5890             /* Store the result into the topmost stack slot. */
5891             if (op == JSOP_LEAVEBLOCKEXPR)
5892                 STORE_OPND(-1, rval);
5893 
5894             JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_BlockClass);
5895             JS_ASSERT(op == JSOP_LEAVEBLOCKEXPR
5896                       ? fp->spbase + OBJ_BLOCK_DEPTH(cx, obj) == sp - 1
5897                       : fp->spbase + OBJ_BLOCK_DEPTH(cx, obj) == sp);
5898 
5899             *chainp = OBJ_GET_PARENT(cx, obj);
5900             JS_ASSERT(chainp != &fp->blockChain ||
5901                       !*chainp ||
5902                       OBJ_GET_CLASS(cx, *chainp) == &js_BlockClass);
5903           }
5904           END_CASE(JSOP_LEAVEBLOCK)
5905 
5906           BEGIN_CASE(JSOP_GETLOCAL)
5907             slot = GET_UINT16(pc);
5908             JS_ASSERT(slot < (uintN)depth);
5909             PUSH_OPND(fp->spbase[slot]);
5910             obj = NULL;
5911           END_CASE(JSOP_GETLOCAL)
5912 
5913           BEGIN_CASE(JSOP_SETLOCAL)
5914             slot = GET_UINT16(pc);
5915             JS_ASSERT(slot < (uintN)depth);
5916             vp = &fp->spbase[slot];
5917             GC_POKE(cx, *vp);
5918             *vp = FETCH_OPND(-1);
5919             obj = NULL;
5920           END_CASE(JSOP_SETLOCAL)
5921 
5922 /* NB: This macro doesn't use JS_BEGIN_MACRO/JS_END_MACRO around its body. */
5923 #define FAST_LOCAL_INCREMENT_OP(PRE,OPEQ,MINMAX)                              \
5924     slot = GET_UINT16(pc);                                                    \
5925     JS_ASSERT(slot < (uintN)depth);                                           \
5926     vp = fp->spbase + slot;                                                   \
5927     rval = *vp;                                                               \
5928     if (!JSVAL_IS_INT(rval) || rval == INT_TO_JSVAL(JSVAL_INT_##MINMAX))      \
5929         goto do_nonint_fast_incop;                                            \
5930     PRE = rval;                                                               \
5931     rval OPEQ 2;                                                              \
5932     *vp = rval;                                                               \
5933     PUSH_OPND(PRE)
5934 
5935           BEGIN_CASE(JSOP_INCLOCAL)
5936             FAST_LOCAL_INCREMENT_OP(rval, +=, MAX);
5937           END_CASE(JSOP_INCLOCAL)
5938 
5939           BEGIN_CASE(JSOP_DECLOCAL)
5940             FAST_LOCAL_INCREMENT_OP(rval, -=, MIN);
5941           END_CASE(JSOP_DECLOCAL)
5942 
5943           BEGIN_CASE(JSOP_LOCALINC)
5944             FAST_LOCAL_INCREMENT_OP(rtmp, +=, MAX);
5945           END_CASE(JSOP_LOCALINC)
5946 
5947           BEGIN_CASE(JSOP_LOCALDEC)
5948             FAST_LOCAL_INCREMENT_OP(rtmp, -=, MIN);
5949           END_CASE(JSOP_LOCALDEC)
5950 
5951 #undef FAST_LOCAL_INCREMENT_OP
5952 
5953           EMPTY_CASE(JSOP_STARTITER)
5954 
5955           BEGIN_CASE(JSOP_ENDITER)
5956             JS_ASSERT(!JSVAL_IS_PRIMITIVE(sp[-1]));
5957             iterobj = JSVAL_TO_OBJECT(sp[-1]);
5958 
5959             /*
5960              * js_CloseNativeIterator checks whether the iterator is not
5961              * native, and also detects the case of a native iterator that
5962              * has already escaped, even though a for-in loop caused it to
5963              * be created.  See jsiter.c.
5964              */
5965             SAVE_SP_AND_PC(fp);
5966             js_CloseNativeIterator(cx, iterobj);
5967             *--sp = JSVAL_NULL;
5968           END_CASE(JSOP_ENDITER)
5969 
5970 #if JS_HAS_GENERATORS
5971           BEGIN_CASE(JSOP_GENERATOR)
5972             pc += JSOP_GENERATOR_LENGTH;
5973             SAVE_SP_AND_PC(fp);
5974             obj = js_NewGenerator(cx, fp);
5975             if (!obj) {
5976                 ok = JS_FALSE;
5977             } else {
5978                 JS_ASSERT(!fp->callobj && !fp->argsobj);
5979                 fp->rval = OBJECT_TO_JSVAL(obj);
5980             }
5981             goto out;
5982 
5983           BEGIN_CASE(JSOP_YIELD)
5984             ASSERT_NOT_THROWING(cx);
5985             if (fp->flags & JSFRAME_FILTERING) {
5986                 /* FIXME: bug 309894 -- fix to eliminate this error. */
5987                 JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
5988                                        JSMSG_YIELD_FROM_FILTER);
5989                 ok = JS_FALSE;
5990                 goto out;
5991             }
5992             if (FRAME_TO_GENERATOR(fp)->state == JSGEN_CLOSING) {
5993                 str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
5994                                                  fp->argv[-2], NULL);
5995                 if (str) {
5996                     JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
5997                                            JSMSG_BAD_GENERATOR_YIELD,
5998                                            JSSTRING_CHARS(str));
5999                 }
6000                 ok = JS_FALSE;
6001                 goto out;
6002             }
6003             fp->rval = FETCH_OPND(-1);
6004             fp->flags |= JSFRAME_YIELDING;
6005             pc += JSOP_YIELD_LENGTH;
6006             SAVE_SP_AND_PC(fp);
6007             goto out;
6008 
6009           BEGIN_CASE(JSOP_ARRAYPUSH)
6010             slot = GET_UINT16(pc);
6011             JS_ASSERT(slot < (uintN)depth);
6012             lval = fp->spbase[slot];
6013             obj  = JSVAL_TO_OBJECT(lval);
6014             JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_ArrayClass);
6015             rval = FETCH_OPND(-1);
6016 
6017             /* We know that the array is created with only a 'length' slot. */
6018             i = obj->map->freeslot - (JSSLOT_FREE(&js_ArrayClass) + 1);
6019             id = INT_TO_JSID(i);
6020 
6021             SAVE_SP_AND_PC(fp);
6022             ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
6023             if (!ok)
6024                 goto out;
6025             --sp;
6026           END_CASE(JSOP_ARRAYPUSH)
6027 #endif /* JS_HAS_GENERATORS */
6028 
6029 #if !JS_HAS_GENERATORS
6030           L_JSOP_GENERATOR:
6031           L_JSOP_YIELD:
6032           L_JSOP_ARRAYPUSH:
6033 #endif
6034 
6035 #if !JS_HAS_DESTRUCTURING
6036           L_JSOP_FOREACHKEYVAL:
6037           L_JSOP_ENUMCONSTELEM:
6038 #endif
6039 
6040 #ifdef JS_THREADED_INTERP
6041           L_JSOP_BACKPATCH:
6042           L_JSOP_BACKPATCH_POP:
6043 #else
6044           default:
6045 #endif
6046           {
6047             char numBuf[12];
6048             JS_snprintf(numBuf, sizeof numBuf, "%d", op);
6049             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
6050                                  JSMSG_BAD_BYTECODE, numBuf);
6051             ok = JS_FALSE;
6052             goto out;
6053           }
6054 
6055 #ifndef JS_THREADED_INTERP
6056 
6057         } /* switch (op) */
6058 
6059     advance_pc:
6060         pc += len;
6061 
6062 #ifdef DEBUG
6063         if (tracefp) {
6064             intN ndefs, n;
6065             jsval *siter;
6066 
6067             ndefs = js_CodeSpec[op].ndefs;
6068             if (ndefs) {
6069                 SAVE_SP_AND_PC(fp);
6070                 if (op == JSOP_FORELEM && sp[-1] == JSVAL_FALSE)
6071                     --ndefs;
6072                 for (n = -ndefs; n < 0; n++) {
6073                     str = js_DecompileValueGenerator(cx, n, sp[n], NULL);
6074                     if (str) {
6075                         fprintf(tracefp, "%s %s",
6076                                 (n == -ndefs) ? "  output:" : ",",
6077                                 JS_GetStringBytes(str));
6078                     }
6079                 }
6080                 fprintf(tracefp, " @ %d\n", sp - fp->spbase);
6081             }
6082             fprintf(tracefp, "  stack: ");
6083             for (siter = fp->spbase; siter < sp; siter++) {
6084                 str = js_ValueToSource(cx, *siter);
6085                 fprintf(tracefp, "%s ",
6086                         str ? JS_GetStringBytes(str) : "<null>");
6087             }
6088             fputc('\n', tracefp);
6089         }
6090 #endif /* DEBUG */
6091     }
6092 #endif /* !JS_THREADED_INTERP */
6093 
6094 out:
6095     if (!ok) {
6096         /*
6097          * Has an exception been raised?  Also insist that we are not in an
6098          * XML filtering predicate expression, to avoid catching exceptions
6099          * within the filtering predicate, such as this example taken from
6100          * tests/e4x/Regress/regress-301596.js:
6101          *
6102          *    try {
6103          *        <xml/>.(@a == 1);
6104          *        throw 5;
6105          *    } catch (e) {
6106          *    }
6107          *
6108          * The inner interpreter activation executing the predicate bytecode
6109          * will throw "reference to undefined XML name @a" (or 5, in older
6110          * versions that followed the first edition of ECMA-357 and evaluated
6111          * unbound identifiers to undefined), and the exception must not be
6112          * caught until control unwinds to the outer interpreter activation.
6113          *
6114          * Otherwise, the wrong stack depth will be restored by JSOP_SETSP,
6115          * and the catch will move into the filtering predicate expression,
6116          * leading to double catch execution if it rethrows.
6117          *
6118          * FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=309894
6119          */
6120         if (cx->throwing && !(fp->flags & JSFRAME_FILTERING)) {
6121             /*
6122              * Call debugger throw hook if set (XXX thread safety?).
6123              */
6124             JSTrapHandler handler = rt->throwHook;
6125             if (handler) {
6126                 SAVE_SP_AND_PC(fp);
6127                 switch (handler(cx, script, pc, &rval, rt->throwHookData)) {
6128                   case JSTRAP_ERROR:
6129                     cx->throwing = JS_FALSE;
6130                     goto no_catch;
6131                   case JSTRAP_RETURN:
6132                     ok = JS_TRUE;
6133                     cx->throwing = JS_FALSE;
6134                     fp->rval = rval;
6135                     goto no_catch;
6136                   case JSTRAP_THROW:
6137                     cx->exception = rval;
6138                   case JSTRAP_CONTINUE:
6139                   default:;
6140                 }
6141                 LOAD_INTERRUPT_HANDLER(rt);
6142             }
6143 
6144             /*
6145              * Look for a try block in script that can catch this exception.
6146              */
6147 #if JS_HAS_GENERATORS
6148             if (JS_LIKELY(cx->exception != JSVAL_ARETURN)) {
6149                 SCRIPT_FIND_CATCH_START(script, pc, pc);
6150                 if (!pc)
6151                     goto no_catch;
6152             } else {
6153                 pc = js_FindFinallyHandler(script, pc);
6154                 if (!pc) {
6155                     cx->throwing = JS_FALSE;
6156                     ok = JS_TRUE;
6157                     fp->rval = JSVAL_VOID;
6158                     goto no_catch;
6159                 }
6160             }
6161 #else
6162             SCRIPT_FIND_CATCH_START(script, pc, pc);
6163             if (!pc)
6164                 goto no_catch;
6165 #endif
6166 
6167             /* Don't clear cx->throwing to save cx->exception from GC. */
6168             len = 0;
6169             ok = JS_TRUE;
6170             DO_NEXT_OP(len);
6171         }
6172 no_catch:;
6173     }
6174 
6175     /*
6176      * Check whether control fell off the end of a lightweight function, or an
6177      * exception thrown under such a function was not caught by it.  If so, go
6178      * to the inline code under JSOP_RETURN.
6179      */
6180     if (inlineCallCount)
6181         goto inline_return;
6182 
6183     /*
6184      * Reset sp before freeing stack slots, because our caller may GC soon.
6185      * Clear spbase to indicate that we've popped the 2 * depth operand slots.
6186      * Restore the previous frame's execution state.
6187      */
6188     if (JS_LIKELY(mark != NULL)) {
6189         /* If fp has blocks on its scope chain, home their locals now. */
6190         if (fp->flags & JSFRAME_POP_BLOCKS) {
6191             SAVE_SP_AND_PC(fp);
6192             ok &= PutBlockObjects(cx, fp);
6193         }
6194 
6195         fp->sp = fp->spbase;
6196         fp->spbase = NULL;
6197         js_FreeRawStack(cx, mark);
6198     } else {
6199         SAVE_SP(fp);
6200     }
6201 
6202 out2:
6203     if (cx->version == currentVersion && currentVersion != originalVersion)
6204         js_SetVersion(cx, originalVersion);
6205     cx->interpLevel--;
6206     return ok;
6207 
6208 atom_not_defined:
6209     {
6210         const char *printable = js_AtomToPrintableString(cx, atom);
6211         if (printable)
6212             js_ReportIsNotDefined(cx, printable);
6213         ok = JS_FALSE;
6214         goto out;
6215     }
6216 }
6217