Back to index

lightning-sunbird  0.9+nobinonly
jsinterp.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  * vim: set ts=8 sw=4 et tw=78:
00003  *
00004  * ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is Mozilla Communicator client code, released
00018  * March 31, 1998.
00019  *
00020  * The Initial Developer of the Original Code is
00021  * Netscape Communications Corporation.
00022  * Portions created by the Initial Developer are Copyright (C) 1998
00023  * the Initial Developer. All Rights Reserved.
00024  *
00025  * Contributor(s):
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 /*
00042  * JavaScript bytecode interpreter.
00043  */
00044 #include "jsstddef.h"
00045 #include <stdio.h>
00046 #include <string.h>
00047 #include <math.h>
00048 #include "jstypes.h"
00049 #include "jsarena.h" /* Added by JSIFY */
00050 #include "jsutil.h" /* Added by JSIFY */
00051 #include "jsprf.h"
00052 #include "jsapi.h"
00053 #include "jsarray.h"
00054 #include "jsatom.h"
00055 #include "jsbool.h"
00056 #include "jscntxt.h"
00057 #include "jsconfig.h"
00058 #include "jsdbgapi.h"
00059 #include "jsfun.h"
00060 #include "jsgc.h"
00061 #include "jsinterp.h"
00062 #include "jsiter.h"
00063 #include "jslock.h"
00064 #include "jsnum.h"
00065 #include "jsobj.h"
00066 #include "jsopcode.h"
00067 #include "jsscan.h"
00068 #include "jsscope.h"
00069 #include "jsscript.h"
00070 #include "jsstr.h"
00071 
00072 #if JS_HAS_XML_SUPPORT
00073 #include "jsxml.h"
00074 #endif
00075 
00076 #ifdef DEBUG
00077 #define ASSERT_CACHE_IS_EMPTY(cache)                                          \
00078     JS_BEGIN_MACRO                                                            \
00079         JSPropertyCacheEntry *end_, *pce_, entry_;                            \
00080         JSPropertyCache *cache_ = (cache);                                    \
00081         JS_ASSERT(cache_->empty);                                             \
00082         end_ = &cache_->table[PROPERTY_CACHE_SIZE];                           \
00083         for (pce_ = &cache_->table[0]; pce_ < end_; pce_++) {                 \
00084             PCE_LOAD(cache_, pce_, entry_);                                   \
00085             JS_ASSERT(!PCE_OBJECT(entry_));                                   \
00086             JS_ASSERT(!PCE_PROPERTY(entry_));                                 \
00087         }                                                                     \
00088     JS_END_MACRO
00089 #else
00090 #define ASSERT_CACHE_IS_EMPTY(cache) ((void)0)
00091 #endif
00092 
00093 void
00094 js_FlushPropertyCache(JSContext *cx)
00095 {
00096     JSPropertyCache *cache;
00097 
00098     cache = &cx->runtime->propertyCache;
00099     if (cache->empty) {
00100         ASSERT_CACHE_IS_EMPTY(cache);
00101         return;
00102     }
00103     memset(cache->table, 0, sizeof cache->table);
00104     cache->empty = JS_TRUE;
00105 #ifdef JS_PROPERTY_CACHE_METERING
00106     cache->flushes++;
00107 #endif
00108 }
00109 
00110 void
00111 js_DisablePropertyCache(JSContext *cx)
00112 {
00113     JS_ASSERT(!cx->runtime->propertyCache.disabled);
00114     cx->runtime->propertyCache.disabled = JS_TRUE;
00115 }
00116 
00117 void
00118 js_EnablePropertyCache(JSContext *cx)
00119 {
00120     JS_ASSERT(cx->runtime->propertyCache.disabled);
00121     ASSERT_CACHE_IS_EMPTY(&cx->runtime->propertyCache);
00122     cx->runtime->propertyCache.disabled = JS_FALSE;
00123 }
00124 
00125 /*
00126  * Stack macros and functions.  These all use a local variable, jsval *sp, to
00127  * point to the next free stack slot.  SAVE_SP must be called before any call
00128  * to a function that may invoke the interpreter.  RESTORE_SP must be called
00129  * only after return from js_Invoke, because only js_Invoke changes fp->sp.
00130  */
00131 #define PUSH(v)         (*sp++ = (v))
00132 #define POP()           (*--sp)
00133 #ifdef DEBUG
00134 #define SAVE_SP(fp)                                                           \
00135     (JS_ASSERT((fp)->script || !(fp)->spbase || (sp) == (fp)->spbase),        \
00136      (fp)->sp = sp)
00137 #else
00138 #define SAVE_SP(fp)     ((fp)->sp = sp)
00139 #endif
00140 #define RESTORE_SP(fp)  (sp = (fp)->sp)
00141 
00142 /*
00143  * SAVE_SP_AND_PC commits deferred stores of interpreter registers to their
00144  * homes in fp, when calling out of the interpreter loop or threaded code.
00145  * RESTORE_SP_AND_PC copies the other way, to update registers after a call
00146  * to a subroutine that interprets a piece of the current script.
00147  * ASSERT_SAVED_SP_AND_PC checks that SAVE_SP_AND_PC was called.
00148  */
00149 #define SAVE_SP_AND_PC(fp)      (SAVE_SP(fp), (fp)->pc = pc)
00150 #define RESTORE_SP_AND_PC(fp)   (RESTORE_SP(fp), pc = (fp)->pc)
00151 #define ASSERT_SAVED_SP_AND_PC(fp) JS_ASSERT((fp)->sp == sp && (fp)->pc == pc);
00152 
00153 /*
00154  * Push the generating bytecode's pc onto the parallel pc stack that runs
00155  * depth slots below the operands.
00156  *
00157  * NB: PUSH_OPND uses sp, depth, and pc from its lexical environment.  See
00158  * js_Interpret for these local variables' declarations and uses.
00159  */
00160 #define PUSH_OPND(v)    (sp[-depth] = (jsval)pc, PUSH(v))
00161 #define STORE_OPND(n,v) (sp[(n)-depth] = (jsval)pc, sp[n] = (v))
00162 #define POP_OPND()      POP()
00163 #define FETCH_OPND(n)   (sp[n])
00164 
00165 /*
00166  * Push the jsdouble d using sp, depth, and pc from the lexical environment.
00167  * Try to convert d to a jsint that fits in a jsval, otherwise GC-alloc space
00168  * for it and push a reference.
00169  */
00170 #define STORE_NUMBER(cx, n, d)                                                \
00171     JS_BEGIN_MACRO                                                            \
00172         jsint i_;                                                             \
00173         jsval v_;                                                             \
00174                                                                               \
00175         if (JSDOUBLE_IS_INT(d, i_) && INT_FITS_IN_JSVAL(i_)) {                \
00176             v_ = INT_TO_JSVAL(i_);                                            \
00177         } else {                                                              \
00178             SAVE_SP_AND_PC(fp);                                               \
00179             ok = js_NewDoubleValue(cx, d, &v_);                               \
00180             if (!ok)                                                          \
00181                 goto out;                                                     \
00182         }                                                                     \
00183         STORE_OPND(n, v_);                                                    \
00184     JS_END_MACRO
00185 
00186 #define STORE_INT(cx, n, i)                                                   \
00187     JS_BEGIN_MACRO                                                            \
00188         jsval v_;                                                             \
00189                                                                               \
00190         if (INT_FITS_IN_JSVAL(i)) {                                           \
00191             v_ = INT_TO_JSVAL(i);                                             \
00192         } else {                                                              \
00193             SAVE_SP_AND_PC(fp);                                               \
00194             ok = js_NewDoubleValue(cx, (jsdouble)(i), &v_);                   \
00195             if (!ok)                                                          \
00196                 goto out;                                                     \
00197         }                                                                     \
00198         STORE_OPND(n, v_);                                                    \
00199     JS_END_MACRO
00200 
00201 #define STORE_UINT(cx, n, u)                                                  \
00202     JS_BEGIN_MACRO                                                            \
00203         jsval v_;                                                             \
00204                                                                               \
00205         if ((u) <= JSVAL_INT_MAX) {                                           \
00206             v_ = INT_TO_JSVAL(u);                                             \
00207         } else {                                                              \
00208             SAVE_SP_AND_PC(fp);                                               \
00209             ok = js_NewDoubleValue(cx, (jsdouble)(u), &v_);                   \
00210             if (!ok)                                                          \
00211                 goto out;                                                     \
00212         }                                                                     \
00213         STORE_OPND(n, v_);                                                    \
00214     JS_END_MACRO
00215 
00216 #define FETCH_NUMBER(cx, n, d)                                                \
00217     JS_BEGIN_MACRO                                                            \
00218         jsval v_;                                                             \
00219                                                                               \
00220         v_ = FETCH_OPND(n);                                                   \
00221         VALUE_TO_NUMBER(cx, v_, d);                                           \
00222     JS_END_MACRO
00223 
00224 #define FETCH_INT(cx, n, i)                                                   \
00225     JS_BEGIN_MACRO                                                            \
00226         jsval v_ = FETCH_OPND(n);                                             \
00227         if (JSVAL_IS_INT(v_)) {                                               \
00228             i = JSVAL_TO_INT(v_);                                             \
00229         } else {                                                              \
00230             SAVE_SP_AND_PC(fp);                                               \
00231             ok = js_ValueToECMAInt32(cx, v_, &i);                             \
00232             if (!ok)                                                          \
00233                 goto out;                                                     \
00234         }                                                                     \
00235     JS_END_MACRO
00236 
00237 #define FETCH_UINT(cx, n, ui)                                                 \
00238     JS_BEGIN_MACRO                                                            \
00239         jsval v_ = FETCH_OPND(n);                                             \
00240         jsint i_;                                                             \
00241         if (JSVAL_IS_INT(v_) && (i_ = JSVAL_TO_INT(v_)) >= 0) {               \
00242             ui = (uint32) i_;                                                 \
00243         } else {                                                              \
00244             SAVE_SP_AND_PC(fp);                                               \
00245             ok = js_ValueToECMAUint32(cx, v_, &ui);                           \
00246             if (!ok)                                                          \
00247                 goto out;                                                     \
00248         }                                                                     \
00249     JS_END_MACRO
00250 
00251 /*
00252  * Optimized conversion macros that test for the desired type in v before
00253  * homing sp and calling a conversion function.
00254  */
00255 #define VALUE_TO_NUMBER(cx, v, d)   VALUE_TO_NUMBER_GOTO(cx, v, d, goto out)
00256 
00257 #define VALUE_TO_NUMBER_GOTO(cx, v, d, error_goto)                            \
00258     JS_BEGIN_MACRO                                                            \
00259         if (JSVAL_IS_INT(v)) {                                                \
00260             d = (jsdouble)JSVAL_TO_INT(v);                                    \
00261         } else if (JSVAL_IS_DOUBLE(v)) {                                      \
00262             d = *JSVAL_TO_DOUBLE(v);                                          \
00263         } else {                                                              \
00264             SAVE_SP_AND_PC(fp);                                               \
00265             ok = js_ValueToNumber(cx, v, &d);                                 \
00266             if (!ok)                                                          \
00267                 error_goto;                                                   \
00268         }                                                                     \
00269     JS_END_MACRO
00270 
00271 #define POP_BOOLEAN(cx, v, b)                                                 \
00272     JS_BEGIN_MACRO                                                            \
00273         v = FETCH_OPND(-1);                                                   \
00274         if (v == JSVAL_NULL) {                                                \
00275             b = JS_FALSE;                                                     \
00276         } else if (JSVAL_IS_BOOLEAN(v)) {                                     \
00277             b = JSVAL_TO_BOOLEAN(v);                                          \
00278         } else {                                                              \
00279             SAVE_SP_AND_PC(fp);                                               \
00280             ok = js_ValueToBoolean(cx, v, &b);                                \
00281             if (!ok)                                                          \
00282                 goto out;                                                     \
00283         }                                                                     \
00284         sp--;                                                                 \
00285     JS_END_MACRO
00286 
00287 /*
00288  * Convert a primitive string, number or boolean to a corresponding object.
00289  * v must not be an object, null or undefined when using this macro.
00290  */
00291 #define PRIMITIVE_TO_OBJECT(cx, v, obj)                                       \
00292     JS_BEGIN_MACRO                                                            \
00293         SAVE_SP(fp);                                                          \
00294         if (JSVAL_IS_STRING(v)) {                                             \
00295             obj = js_StringToObject(cx, JSVAL_TO_STRING(v));                  \
00296         } else if (JSVAL_IS_INT(v)) {                                         \
00297             obj = js_NumberToObject(cx, (jsdouble)JSVAL_TO_INT(v));           \
00298         } else if (JSVAL_IS_DOUBLE(v)) {                                      \
00299             obj = js_NumberToObject(cx, *JSVAL_TO_DOUBLE(v));                 \
00300         } else {                                                              \
00301             JS_ASSERT(JSVAL_IS_BOOLEAN(v));                                   \
00302             obj = js_BooleanToObject(cx, JSVAL_TO_BOOLEAN(v));                \
00303         }                                                                     \
00304     JS_END_MACRO
00305 
00306 #define VALUE_TO_OBJECT(cx, v, obj)                                           \
00307     JS_BEGIN_MACRO                                                            \
00308         if (!JSVAL_IS_PRIMITIVE(v)) {                                         \
00309             obj = JSVAL_TO_OBJECT(v);                                         \
00310         } else {                                                              \
00311             SAVE_SP_AND_PC(fp);                                               \
00312             obj = js_ValueToNonNullObject(cx, v);                             \
00313             if (!obj) {                                                       \
00314                 ok = JS_FALSE;                                                \
00315                 goto out;                                                     \
00316             }                                                                 \
00317         }                                                                     \
00318     JS_END_MACRO
00319 
00320 #define FETCH_OBJECT(cx, n, v, obj)                                           \
00321     JS_BEGIN_MACRO                                                            \
00322         v = FETCH_OPND(n);                                                    \
00323         VALUE_TO_OBJECT(cx, v, obj);                                          \
00324         STORE_OPND(n, OBJECT_TO_JSVAL(obj));                                  \
00325     JS_END_MACRO
00326 
00327 #define VALUE_TO_PRIMITIVE(cx, v, hint, vp)                                   \
00328     JS_BEGIN_MACRO                                                            \
00329         if (JSVAL_IS_PRIMITIVE(v)) {                                          \
00330             *vp = v;                                                          \
00331         } else {                                                              \
00332             SAVE_SP_AND_PC(fp);                                               \
00333             ok = OBJ_DEFAULT_VALUE(cx, JSVAL_TO_OBJECT(v), hint, vp);         \
00334             if (!ok)                                                          \
00335                 goto out;                                                     \
00336         }                                                                     \
00337     JS_END_MACRO
00338 
00339 JS_FRIEND_API(jsval *)
00340 js_AllocRawStack(JSContext *cx, uintN nslots, void **markp)
00341 {
00342     jsval *sp;
00343 
00344     if (markp)
00345         *markp = JS_ARENA_MARK(&cx->stackPool);
00346     JS_ARENA_ALLOCATE_CAST(sp, jsval *, &cx->stackPool, nslots * sizeof(jsval));
00347     if (!sp) {
00348         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_STACK_OVERFLOW,
00349                              (cx->fp && cx->fp->fun)
00350                              ? JS_GetFunctionName(cx->fp->fun)
00351                              : "script");
00352     }
00353     return sp;
00354 }
00355 
00356 JS_FRIEND_API(void)
00357 js_FreeRawStack(JSContext *cx, void *mark)
00358 {
00359     JS_ARENA_RELEASE(&cx->stackPool, mark);
00360 }
00361 
00362 JS_FRIEND_API(jsval *)
00363 js_AllocStack(JSContext *cx, uintN nslots, void **markp)
00364 {
00365     jsval *sp, *vp, *end;
00366     JSArena *a;
00367     JSStackHeader *sh;
00368     JSStackFrame *fp;
00369 
00370     /* Callers don't check for zero nslots: we do to avoid empty segments. */
00371     if (nslots == 0) {
00372         *markp = NULL;
00373         return JS_ARENA_MARK(&cx->stackPool);
00374     }
00375 
00376     /* Allocate 2 extra slots for the stack segment header we'll likely need. */
00377     sp = js_AllocRawStack(cx, 2 + nslots, markp);
00378     if (!sp)
00379         return NULL;
00380 
00381     /* Try to avoid another header if we can piggyback on the last segment. */
00382     a = cx->stackPool.current;
00383     sh = cx->stackHeaders;
00384     if (sh && JS_STACK_SEGMENT(sh) + sh->nslots == sp) {
00385         /* Extend the last stack segment, give back the 2 header slots. */
00386         sh->nslots += nslots;
00387         a->avail -= 2 * sizeof(jsval);
00388     } else {
00389         /*
00390          * Need a new stack segment, so we must initialize unused slots in the
00391          * current frame.  See js_GC, just before marking the "operand" jsvals,
00392          * where we scan from fp->spbase to fp->sp or through fp->script->depth
00393          * (whichever covers fewer slots).
00394          */
00395         fp = cx->fp;
00396         if (fp && fp->script && fp->spbase) {
00397 #ifdef DEBUG
00398             jsuword depthdiff = fp->script->depth * sizeof(jsval);
00399             JS_ASSERT(JS_UPTRDIFF(fp->sp, fp->spbase) <= depthdiff);
00400             JS_ASSERT(JS_UPTRDIFF(*markp, fp->spbase) >= depthdiff);
00401 #endif
00402             end = fp->spbase + fp->script->depth;
00403             for (vp = fp->sp; vp < end; vp++)
00404                 *vp = JSVAL_VOID;
00405         }
00406 
00407         /* Allocate and push a stack segment header from the 2 extra slots. */
00408         sh = (JSStackHeader *)sp;
00409         sh->nslots = nslots;
00410         sh->down = cx->stackHeaders;
00411         cx->stackHeaders = sh;
00412         sp += 2;
00413     }
00414 
00415     /*
00416      * Store JSVAL_NULL using memset, to let compilers optimize as they see
00417      * fit, in case a caller allocates and pushes GC-things one by one, which
00418      * could nest a last-ditch GC that will scan this segment.
00419      */
00420     memset(sp, 0, nslots * sizeof(jsval));
00421     return sp;
00422 }
00423 
00424 JS_FRIEND_API(void)
00425 js_FreeStack(JSContext *cx, void *mark)
00426 {
00427     JSStackHeader *sh;
00428     jsuword slotdiff;
00429 
00430     /* Check for zero nslots allocation special case. */
00431     if (!mark)
00432         return;
00433 
00434     /* We can assert because js_FreeStack always balances js_AllocStack. */
00435     sh = cx->stackHeaders;
00436     JS_ASSERT(sh);
00437 
00438     /* If mark is in the current segment, reduce sh->nslots, else pop sh. */
00439     slotdiff = JS_UPTRDIFF(mark, JS_STACK_SEGMENT(sh)) / sizeof(jsval);
00440     if (slotdiff < (jsuword)sh->nslots)
00441         sh->nslots = slotdiff;
00442     else
00443         cx->stackHeaders = sh->down;
00444 
00445     /* Release the stackPool space allocated since mark was set. */
00446     JS_ARENA_RELEASE(&cx->stackPool, mark);
00447 }
00448 
00449 JSBool
00450 js_GetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
00451 {
00452     return JS_TRUE;
00453 }
00454 
00455 JSBool
00456 js_SetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
00457 {
00458     return JS_TRUE;
00459 }
00460 
00461 JSBool
00462 js_GetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
00463 {
00464     return JS_TRUE;
00465 }
00466 
00467 JSBool
00468 js_SetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
00469 {
00470     return JS_TRUE;
00471 }
00472 
00473 JSObject *
00474 js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
00475 {
00476     JSObject *obj, *cursor, *clonedChild, *parent;
00477     JSTempValueRooter tvr;
00478 
00479     obj = fp->blockChain;
00480     if (!obj) {
00481         /*
00482          * Don't force a call object for a lightweight function call, but do
00483          * insist that there is a call object for a heavyweight function call.
00484          */
00485         JS_ASSERT(!fp->fun ||
00486                   !(fp->fun->flags & JSFUN_HEAVYWEIGHT) ||
00487                   fp->callobj);
00488         JS_ASSERT(fp->scopeChain);
00489         return fp->scopeChain;
00490     }
00491 
00492     /*
00493      * We have one or more lexical scopes to reflect into fp->scopeChain, so
00494      * make sure there's a call object at the current head of the scope chain,
00495      * if this frame is a call frame.
00496      */
00497     if (fp->fun && !fp->callobj) {
00498         JS_ASSERT(OBJ_GET_CLASS(cx, fp->scopeChain) != &js_BlockClass ||
00499                   JS_GetPrivate(cx, fp->scopeChain) != fp);
00500         if (!js_GetCallObject(cx, fp, fp->scopeChain))
00501             return NULL;
00502     }
00503 
00504     /*
00505      * Clone the block chain. To avoid recursive cloning we set the parent of
00506      * the cloned child after we clone the parent. In the following loop when
00507      * clonedChild is null it indicates the first iteration when no special GC
00508      * rooting is necessary. On the second and the following iterations we
00509      * have to protect cloned so far chain against the GC during cloning of
00510      * the cursor object.
00511      */
00512     cursor = obj;
00513     clonedChild = NULL;
00514     for (;;) {
00515         parent = OBJ_GET_PARENT(cx, cursor);
00516 
00517         /*
00518          * We pass fp->scopeChain and not null even if we override the parent
00519          * slot later as null triggers useless calculations of slot's value in
00520          * js_NewObject that js_CloneBlockObject calls.
00521          */
00522         cursor = js_CloneBlockObject(cx, cursor, fp->scopeChain, fp);
00523         if (!cursor) {
00524             if (clonedChild)
00525                 JS_POP_TEMP_ROOT(cx, &tvr);
00526             return NULL;
00527         }
00528         if (!clonedChild) {
00529             /*
00530              * The first iteration. Check if other follow and root obj if so
00531              * to protect the whole cloned chain against GC.
00532              */
00533             obj = cursor;
00534             if (!parent)
00535                 break;
00536             JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr);
00537         } else {
00538             /*
00539              * Avoid OBJ_SET_PARENT overhead as clonedChild cannot escape to
00540              * other threads.
00541              */
00542             clonedChild->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(cursor);
00543             if (!parent) {
00544                 JS_ASSERT(tvr.u.value == OBJECT_TO_JSVAL(obj));
00545                 JS_POP_TEMP_ROOT(cx, &tvr);
00546                 break;
00547             }
00548         }
00549         clonedChild = cursor;
00550         cursor = parent;
00551     }
00552     fp->flags |= JSFRAME_POP_BLOCKS;
00553     fp->scopeChain = obj;
00554     fp->blockChain = NULL;
00555     return obj;
00556 }
00557 
00558 /*
00559  * Walk the scope chain looking for block scopes whose locals need to be
00560  * copied from stack slots into object slots before fp goes away.
00561  */
00562 static JSBool
00563 PutBlockObjects(JSContext *cx, JSStackFrame *fp)
00564 {
00565     JSBool ok;
00566     JSObject *obj;
00567 
00568     ok = JS_TRUE;
00569     for (obj = fp->scopeChain; obj; obj = OBJ_GET_PARENT(cx, obj)) {
00570         if (OBJ_GET_CLASS(cx, obj) == &js_BlockClass) {
00571             if (JS_GetPrivate(cx, obj) != fp)
00572                 break;
00573             ok &= js_PutBlockObject(cx, obj);
00574         }
00575     }
00576     return ok;
00577 }
00578 
00579 JSObject *
00580 js_ComputeThis(JSContext *cx, JSObject *thisp, jsval *argv)
00581 {
00582     if (thisp && OBJ_GET_CLASS(cx, thisp) != &js_CallClass) {
00583         /* Some objects (e.g., With) delegate 'this' to another object. */
00584         thisp = OBJ_THIS_OBJECT(cx, thisp);
00585         if (!thisp)
00586             return NULL;
00587     } else {
00588         /*
00589          * ECMA requires "the global object", but in the presence of multiple
00590          * top-level objects (windows, frames, or certain layers in the client
00591          * object model), we prefer fun's parent.  An example that causes this
00592          * code to run:
00593          *
00594          *   // in window w1
00595          *   function f() { return this }
00596          *   function g() { return f }
00597          *
00598          *   // in window w2
00599          *   var h = w1.g()
00600          *   alert(h() == w1)
00601          *
00602          * The alert should display "true".
00603          */
00604         if (JSVAL_IS_PRIMITIVE(argv[-2]) ||
00605             !OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(argv[-2]))) {
00606             thisp = cx->globalObject;
00607         } else {
00608             jsid id;
00609             jsval v;
00610             uintN attrs;
00611 
00612             /* Walk up the parent chain. */
00613             thisp = JSVAL_TO_OBJECT(argv[-2]);
00614             id = ATOM_TO_JSID(cx->runtime->atomState.parentAtom);
00615             for (;;) {
00616                 if (!OBJ_CHECK_ACCESS(cx, thisp, id, JSACC_PARENT, &v, &attrs))
00617                     return NULL;
00618                 if (JSVAL_IS_VOID(v))
00619                     v = OBJ_GET_SLOT(cx, thisp, JSSLOT_PARENT);
00620                 if (JSVAL_IS_NULL(v))
00621                     break;
00622                 thisp = JSVAL_TO_OBJECT(v);
00623             }
00624         }
00625     }
00626     argv[-1] = OBJECT_TO_JSVAL(thisp);
00627     return thisp;
00628 }
00629 
00630 #if JS_HAS_NO_SUCH_METHOD
00631 
00632 static JSBool
00633 NoSuchMethod(JSContext *cx, JSStackFrame *fp, jsval *vp, uint32 flags,
00634              uintN argc)
00635 {
00636     JSObject *thisp, *argsobj;
00637     jsval *sp, roots[3];
00638     JSTempValueRooter tvr;
00639     jsid id;
00640     JSBool ok;
00641     jsbytecode *pc;
00642     jsatomid atomIndex;
00643 
00644     /*
00645      * We must call js_ComputeThis here to censor Call objects.  A performance
00646      * hit, since we'll call it again in the normal sequence of invoke events,
00647      * but at least it's idempotent.
00648      *
00649      * Normally, we call ComputeThis after all frame members have been set,
00650      * and in particular, after any revision of the callee value at *vp  due
00651      * to clasp->convert (see below).  This matters because ComputeThis may
00652      * access *vp via fp->argv[-2], to follow the parent chain to a global
00653      * object to use as the 'this' parameter.
00654      *
00655      * Obviously, here in the JSVAL_IS_PRIMITIVE(v) case, there can't be any
00656      * such defaulting of 'this' to callee (v, *vp) ancestor.
00657      */
00658     JS_ASSERT(JSVAL_IS_PRIMITIVE(vp[0]));
00659     RESTORE_SP(fp);
00660     if (JSVAL_IS_OBJECT(vp[1])) {
00661         thisp = JSVAL_TO_OBJECT(vp[1]);
00662     } else {
00663         PRIMITIVE_TO_OBJECT(cx, vp[1], thisp);
00664         if (!thisp)
00665             return JS_FALSE;
00666         vp[1] = OBJECT_TO_JSVAL(thisp);
00667     }
00668     thisp = js_ComputeThis(cx, thisp, vp + 2);
00669     if (!thisp)
00670         return JS_FALSE;
00671     vp[1] = OBJECT_TO_JSVAL(thisp);
00672 
00673     /* From here on, control must flow through label out: to return. */
00674     memset(roots, 0, sizeof roots);
00675     JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr);
00676 
00677     id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom);
00678 #if JS_HAS_XML_SUPPORT
00679     if (OBJECT_IS_XML(cx, thisp)) {
00680         JSXMLObjectOps *ops;
00681 
00682         ops = (JSXMLObjectOps *) thisp->map->ops;
00683         thisp = ops->getMethod(cx, thisp, id, &roots[2]);
00684         if (!thisp) {
00685             ok = JS_FALSE;
00686             goto out;
00687         }
00688         vp[1] = OBJECT_TO_JSVAL(thisp);
00689     } else
00690 #endif
00691     {
00692         ok = OBJ_GET_PROPERTY(cx, thisp, id, &roots[2]);
00693         if (!ok)
00694             goto out;
00695     }
00696     if (JSVAL_IS_PRIMITIVE(roots[2]))
00697         goto not_function;
00698 
00699     pc = (jsbytecode *) vp[-(intN)fp->script->depth];
00700     switch ((JSOp) *pc) {
00701       case JSOP_NAME:
00702       case JSOP_GETPROP:
00703 #if JS_HAS_XML_SUPPORT
00704       case JSOP_GETMETHOD:
00705 #endif
00706         atomIndex = GET_ATOM_INDEX(pc);
00707         roots[0] = ATOM_KEY(js_GetAtom(cx, &fp->script->atomMap, atomIndex));
00708         argsobj = js_NewArrayObject(cx, argc, vp + 2);
00709         if (!argsobj) {
00710             ok = JS_FALSE;
00711             goto out;
00712         }
00713         roots[1] = OBJECT_TO_JSVAL(argsobj);
00714         ok = js_InternalInvoke(cx, thisp, roots[2], flags | JSINVOKE_INTERNAL,
00715                                2, roots, &vp[0]);
00716         break;
00717 
00718       default:
00719         goto not_function;
00720     }
00721 
00722   out:
00723     JS_POP_TEMP_ROOT(cx, &tvr);
00724     return ok;
00725 
00726   not_function:
00727     js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_FUNFLAGS);
00728     ok = JS_FALSE;
00729     goto out;
00730 }
00731 
00732 #endif /* JS_HAS_NO_SUCH_METHOD */
00733 
00734 #ifdef DUMP_CALL_TABLE
00735 
00736 #include "jsclist.h"
00737 #include "jshash.h"
00738 #include "jsdtoa.h"
00739 
00740 typedef struct CallKey {
00741     jsval               callee;                 /* callee value */
00742     const char          *filename;              /* function filename or null */
00743     uintN               lineno;                 /* function lineno or 0 */
00744 } CallKey;
00745 
00746 /* Compensate for typeof null == "object" brain damage. */
00747 #define JSTYPE_NULL     JSTYPE_LIMIT
00748 #define TYPEOF(cx,v)    (JSVAL_IS_NULL(v) ? JSTYPE_NULL : JS_TypeOfValue(cx,v))
00749 #define TYPENAME(t)     (((t) == JSTYPE_NULL) ? js_null_str : js_type_str[t])
00750 #define NTYPEHIST       (JSTYPE_LIMIT + 1)
00751 
00752 typedef struct CallValue {
00753     uint32              total;                  /* total call count */
00754     uint32              recycled;               /* LRU-recycled calls lost */
00755     uint16              minargc;                /* minimum argument count */
00756     uint16              maxargc;                /* maximum argument count */
00757     struct ArgInfo {
00758         uint32          typeHist[NTYPEHIST];    /* histogram by type */
00759         JSCList         lruList;                /* top 10 values LRU list */
00760         struct ArgValCount {
00761             JSCList     lruLink;                /* LRU list linkage */
00762             jsval       value;                  /* recently passed value */
00763             uint32      count;                  /* number of times passed */
00764             char        strbuf[112];            /* string conversion buffer */
00765         } topValCounts[10];                     /* top 10 value storage */
00766     } argInfo[8];
00767 } CallValue;
00768 
00769 typedef struct CallEntry {
00770     JSHashEntry         entry;
00771     CallKey             key;
00772     CallValue           value;
00773     char                name[32];               /* function name copy */
00774 } CallEntry;
00775 
00776 static void *
00777 AllocCallTable(void *pool, size_t size)
00778 {
00779     return malloc(size);
00780 }
00781 
00782 static void
00783 FreeCallTable(void *pool, void *item)
00784 {
00785     free(item);
00786 }
00787 
00788 static JSHashEntry *
00789 AllocCallEntry(void *pool, const void *key)
00790 {
00791     return (JSHashEntry*) calloc(1, sizeof(CallEntry));
00792 }
00793 
00794 static void
00795 FreeCallEntry(void *pool, JSHashEntry *he, uintN flag)
00796 {
00797     JS_ASSERT(flag == HT_FREE_ENTRY);
00798     free(he);
00799 }
00800 
00801 static JSHashAllocOps callTableAllocOps = {
00802     AllocCallTable, FreeCallTable,
00803     AllocCallEntry, FreeCallEntry
00804 };
00805 
00806 JS_STATIC_DLL_CALLBACK(JSHashNumber)
00807 js_hash_call_key(const void *key)
00808 {
00809     CallKey *ck = (CallKey *) key;
00810     JSHashNumber hash = (jsuword)ck->callee >> 3;
00811 
00812     if (ck->filename) {
00813         hash = (hash << 4) ^ JS_HashString(ck->filename);
00814         hash = (hash << 4) ^ ck->lineno;
00815     }
00816     return hash;
00817 }
00818 
00819 JS_STATIC_DLL_CALLBACK(intN)
00820 js_compare_call_keys(const void *k1, const void *k2)
00821 {
00822     CallKey *ck1 = (CallKey *)k1, *ck2 = (CallKey *)k2;
00823 
00824     return ck1->callee == ck2->callee &&
00825            ((ck1->filename && ck2->filename)
00826             ? strcmp(ck1->filename, ck2->filename) == 0
00827             : ck1->filename == ck2->filename) &&
00828            ck1->lineno == ck2->lineno;
00829 }
00830 
00831 JSHashTable *js_CallTable;
00832 size_t      js_LogCallToSourceLimit;
00833 
00834 JS_STATIC_DLL_CALLBACK(intN)
00835 CallTableDumper(JSHashEntry *he, intN k, void *arg)
00836 {
00837     CallEntry *ce = (CallEntry *)he;
00838     FILE *fp = (FILE *)arg;
00839     uintN argc, i, n;
00840     struct ArgInfo *ai;
00841     JSType save, type;
00842     JSCList *cl;
00843     struct ArgValCount *avc;
00844     jsval argval;
00845 
00846     if (ce->key.filename) {
00847         /* We're called at the end of the mark phase, so mark our filenames. */
00848         js_MarkScriptFilename(ce->key.filename);
00849         fprintf(fp, "%s:%u ", ce->key.filename, ce->key.lineno);
00850     } else {
00851         fprintf(fp, "@%p ", (void *) ce->key.callee);
00852     }
00853 
00854     if (ce->name[0])
00855         fprintf(fp, "name %s ", ce->name);
00856     fprintf(fp, "calls %lu (%lu) argc %u/%u\n",
00857             (unsigned long) ce->value.total,
00858             (unsigned long) ce->value.recycled,
00859             ce->value.minargc, ce->value.maxargc);
00860 
00861     argc = JS_MIN(ce->value.maxargc, 8);
00862     for (i = 0; i < argc; i++) {
00863         ai = &ce->value.argInfo[i];
00864 
00865         n = 0;
00866         save = -1;
00867         for (type = JSTYPE_VOID; type <= JSTYPE_LIMIT; type++) {
00868             if (ai->typeHist[type]) {
00869                 save = type;
00870                 ++n;
00871             }
00872         }
00873         if (n == 1) {
00874             fprintf(fp, "  arg %u type %s: %lu\n",
00875                     i, TYPENAME(save), (unsigned long) ai->typeHist[save]);
00876         } else {
00877             fprintf(fp, "  arg %u type histogram:\n", i);
00878             for (type = JSTYPE_VOID; type <= JSTYPE_LIMIT; type++) {
00879                 fprintf(fp, "  %9s: %8lu ",
00880                        TYPENAME(type), (unsigned long) ai->typeHist[type]);
00881                 for (n = (uintN) JS_HOWMANY(ai->typeHist[type], 10); n > 0; --n)
00882                     fputc('*', fp);
00883                 fputc('\n', fp);
00884             }
00885         }
00886 
00887         fprintf(fp, "  arg %u top 10 values:\n", i);
00888         n = 1;
00889         for (cl = ai->lruList.prev; cl != &ai->lruList; cl = cl->prev) {
00890             avc = (struct ArgValCount *)cl;
00891             if (!avc->count)
00892                 break;
00893             argval = avc->value;
00894             fprintf(fp, "  %9u: %8lu %.*s (%#lx)\n",
00895                     n, (unsigned long) avc->count,
00896                     sizeof avc->strbuf, avc->strbuf, argval);
00897             ++n;
00898         }
00899     }
00900 
00901     return HT_ENUMERATE_NEXT;
00902 }
00903 
00904 void
00905 js_DumpCallTable(JSContext *cx)
00906 {
00907     char name[24];
00908     FILE *fp;
00909     static uintN dumpCount;
00910 
00911     if (!js_CallTable)
00912         return;
00913 
00914     JS_snprintf(name, sizeof name, "/tmp/calltable.dump.%u", dumpCount & 7);
00915     dumpCount++;
00916     fp = fopen(name, "w");
00917     if (!fp)
00918         return;
00919 
00920     JS_HashTableEnumerateEntries(js_CallTable, CallTableDumper, fp);
00921     fclose(fp);
00922 }
00923 
00924 static void
00925 LogCall(JSContext *cx, jsval callee, uintN argc, jsval *argv)
00926 {
00927     CallKey key;
00928     const char *name, *cstr;
00929     JSFunction *fun;
00930     JSHashNumber keyHash;
00931     JSHashEntry **hep, *he;
00932     CallEntry *ce;
00933     uintN i, j;
00934     jsval argval;
00935     JSType type;
00936     struct ArgInfo *ai;
00937     struct ArgValCount *avc;
00938     JSString *str;
00939 
00940     if (!js_CallTable) {
00941         js_CallTable = JS_NewHashTable(1024, js_hash_call_key,
00942                                        js_compare_call_keys, NULL,
00943                                        &callTableAllocOps, NULL);
00944         if (!js_CallTable)
00945             return;
00946     }
00947 
00948     key.callee = callee;
00949     key.filename = NULL;
00950     key.lineno = 0;
00951     name = "";
00952     if (VALUE_IS_FUNCTION(cx, callee)) {
00953         fun = (JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(callee));
00954         if (fun->atom)
00955             name = js_AtomToPrintableString(cx, fun->atom);
00956         if (FUN_INTERPRETED(fun)) {
00957             key.filename = fun->u.i.script->filename;
00958             key.lineno = fun->u.i.script->lineno;
00959         }
00960     }
00961     keyHash = js_hash_call_key(&key);
00962 
00963     hep = JS_HashTableRawLookup(js_CallTable, keyHash, &key);
00964     he = *hep;
00965     if (he) {
00966         ce = (CallEntry *) he;
00967         JS_ASSERT(strncmp(ce->name, name, sizeof ce->name) == 0);
00968     } else {
00969         he = JS_HashTableRawAdd(js_CallTable, hep, keyHash, &key, NULL);
00970         if (!he)
00971             return;
00972         ce = (CallEntry *) he;
00973         ce->entry.key = &ce->key;
00974         ce->entry.value = &ce->value;
00975         ce->key = key;
00976         for (i = 0; i < 8; i++) {
00977             ai = &ce->value.argInfo[i];
00978             JS_INIT_CLIST(&ai->lruList);
00979             for (j = 0; j < 10; j++)
00980                 JS_APPEND_LINK(&ai->topValCounts[j].lruLink, &ai->lruList);
00981         }
00982         strncpy(ce->name, name, sizeof ce->name);
00983     }
00984 
00985     ++ce->value.total;
00986     if (ce->value.minargc < argc)
00987         ce->value.minargc = argc;
00988     if (ce->value.maxargc < argc)
00989         ce->value.maxargc = argc;
00990     if (argc > 8)
00991         argc = 8;
00992     for (i = 0; i < argc; i++) {
00993         ai = &ce->value.argInfo[i];
00994         argval = argv[i];
00995         type = TYPEOF(cx, argval);
00996         ++ai->typeHist[type];
00997 
00998         for (j = 0; ; j++) {
00999             if (j == 10) {
01000                 avc = (struct ArgValCount *) ai->lruList.next;
01001                 ce->value.recycled += avc->count;
01002                 avc->value = argval;
01003                 avc->count = 1;
01004                 break;
01005             }
01006             avc = &ai->topValCounts[j];
01007             if (avc->value == argval) {
01008                 ++avc->count;
01009                 break;
01010             }
01011         }
01012 
01013         /* Move avc to the back of the LRU list. */
01014         JS_REMOVE_LINK(&avc->lruLink);
01015         JS_APPEND_LINK(&avc->lruLink, &ai->lruList);
01016 
01017         str = NULL;
01018         cstr = "";
01019         switch (TYPEOF(cx, argval)) {
01020           case JSTYPE_VOID:
01021             cstr = js_type_str[JSTYPE_VOID];
01022             break;
01023           case JSTYPE_NULL:
01024             cstr = js_null_str;
01025             break;
01026           case JSTYPE_BOOLEAN:
01027             cstr = js_boolean_str[JSVAL_TO_BOOLEAN(argval)];
01028             break;
01029           case JSTYPE_NUMBER:
01030             if (JSVAL_IS_INT(argval)) {
01031                 JS_snprintf(avc->strbuf, sizeof avc->strbuf, "%ld",
01032                             JSVAL_TO_INT(argval));
01033             } else {
01034                 JS_dtostr(avc->strbuf, sizeof avc->strbuf, DTOSTR_STANDARD, 0,
01035                           *JSVAL_TO_DOUBLE(argval));
01036             }
01037             continue;
01038           case JSTYPE_STRING:
01039             str = js_QuoteString(cx, JSVAL_TO_STRING(argval), (jschar)'"');
01040             break;
01041           case JSTYPE_FUNCTION:
01042             if (VALUE_IS_FUNCTION(cx, argval)) {
01043                 fun = (JSFunction *)JS_GetPrivate(cx, JSVAL_TO_OBJECT(argval));
01044                 if (fun && fun->atom) {
01045                     str = ATOM_TO_STRING(fun->atom);
01046                     break;
01047                 }
01048             }
01049             /* FALL THROUGH */
01050           case JSTYPE_OBJECT:
01051             js_LogCallToSourceLimit = sizeof avc->strbuf;
01052             cx->options |= JSOPTION_LOGCALL_TOSOURCE;
01053             str = js_ValueToSource(cx, argval);
01054             cx->options &= ~JSOPTION_LOGCALL_TOSOURCE;
01055             break;
01056         }
01057         if (str)
01058             cstr = JS_GetStringBytes(str);
01059         strncpy(avc->strbuf, cstr, sizeof avc->strbuf);
01060     }
01061 }
01062 
01063 #endif /* DUMP_CALL_TABLE */
01064 
01065 /*
01066  * Conditional assert to detect failure to clear a pending exception that is
01067  * suppressed (or unintentional suppression of a wanted exception).
01068  */
01069 #if defined DEBUG_brendan || defined DEBUG_mrbkap || defined DEBUG_shaver
01070 # define DEBUG_NOT_THROWING 1
01071 #endif
01072 
01073 #ifdef DEBUG_NOT_THROWING
01074 # define ASSERT_NOT_THROWING(cx) JS_ASSERT(!(cx)->throwing)
01075 #else
01076 # define ASSERT_NOT_THROWING(cx) /* nothing */
01077 #endif
01078 
01079 /*
01080  * Find a function reference and its 'this' object implicit first parameter
01081  * under argc arguments on cx's stack, and call the function.  Push missing
01082  * required arguments, allocate declared local variables, and pop everything
01083  * when done.  Then push the return value.
01084  */
01085 JS_FRIEND_API(JSBool)
01086 js_Invoke(JSContext *cx, uintN argc, uintN flags)
01087 {
01088     void *mark;
01089     JSStackFrame *fp, frame;
01090     jsval *sp, *newsp, *limit;
01091     jsval *vp, v, thisv;
01092     JSObject *funobj, *parent, *thisp;
01093     JSBool ok;
01094     JSClass *clasp;
01095     JSObjectOps *ops;
01096     JSNative native;
01097     JSFunction *fun;
01098     JSScript *script;
01099     uintN nslots, nvars, nalloc, surplus;
01100     JSInterpreterHook hook;
01101     void *hookData;
01102 
01103     /* Mark the top of stack and load frequently-used registers. */
01104     mark = JS_ARENA_MARK(&cx->stackPool);
01105     fp = cx->fp;
01106     sp = fp->sp;
01107 
01108     /*
01109      * Set vp to the callee value's stack slot (it's where rval goes).
01110      * Once vp is set, control should flow through label out2: to return.
01111      * Set frame.rval early so native class and object ops can throw and
01112      * return false, causing a goto out2 with ok set to false.
01113      */
01114     vp = sp - (2 + argc);
01115     v = *vp;
01116     frame.rval = JSVAL_VOID;
01117 
01118     /*
01119      * A callee must be an object reference, unless its 'this' parameter
01120      * implements the __noSuchMethod__ method, in which case that method will
01121      * be called like so:
01122      *
01123      *   thisp.__noSuchMethod__(id, args)
01124      *
01125      * where id is the name of the method that this invocation attempted to
01126      * call by name, and args is an Array containing this invocation's actual
01127      * parameters.
01128      */
01129     if (JSVAL_IS_PRIMITIVE(v)) {
01130 #if JS_HAS_NO_SUCH_METHOD
01131         if (fp->script && !(flags & JSINVOKE_INTERNAL)) {
01132             ok = NoSuchMethod(cx, fp, vp, flags, argc);
01133             if (ok)
01134                 frame.rval = *vp;
01135             goto out2;
01136         }
01137 #endif
01138         goto bad;
01139     }
01140 
01141     /* Load thisv after potentially calling NoSuchMethod, which may set it. */
01142     thisv = vp[1];
01143 
01144     funobj = JSVAL_TO_OBJECT(v);
01145     parent = OBJ_GET_PARENT(cx, funobj);
01146     clasp = OBJ_GET_CLASS(cx, funobj);
01147     if (clasp != &js_FunctionClass) {
01148         /* Function is inlined, all other classes use object ops. */
01149         ops = funobj->map->ops;
01150 
01151         /*
01152          * XXX this makes no sense -- why convert to function if clasp->call?
01153          * XXX better to call that hook without converting
01154          * XXX the only thing that needs fixing is liveconnect
01155          *
01156          * Try converting to function, for closure and API compatibility.
01157          * We attempt the conversion under all circumstances for 1.2, but
01158          * only if there is a call op defined otherwise.
01159          */
01160         if ((ops == &js_ObjectOps) ? clasp->call : ops->call) {
01161             ok = clasp->convert(cx, funobj, JSTYPE_FUNCTION, &v);
01162             if (!ok)
01163                 goto out2;
01164 
01165             if (VALUE_IS_FUNCTION(cx, v)) {
01166                 /* Make vp refer to funobj to keep it available as argv[-2]. */
01167                 *vp = v;
01168                 funobj = JSVAL_TO_OBJECT(v);
01169                 parent = OBJ_GET_PARENT(cx, funobj);
01170                 goto have_fun;
01171             }
01172         }
01173         fun = NULL;
01174         script = NULL;
01175         nslots = nvars = 0;
01176 
01177         /* Try a call or construct native object op. */
01178         native = (flags & JSINVOKE_CONSTRUCT) ? ops->construct : ops->call;
01179         if (!native)
01180             goto bad;
01181 
01182         if (JSVAL_IS_OBJECT(thisv)) {
01183             thisp = JSVAL_TO_OBJECT(thisv);
01184         } else {
01185             PRIMITIVE_TO_OBJECT(cx, thisv, thisp);
01186             if (!thisp)
01187                 goto out2;
01188             vp[1] = thisv = OBJECT_TO_JSVAL(thisp);
01189         }
01190     } else {
01191 have_fun:
01192         /* Get private data and set derived locals from it. */
01193         fun = (JSFunction *) JS_GetPrivate(cx, funobj);
01194         nslots = (fun->nargs > argc) ? fun->nargs - argc : 0;
01195         if (FUN_INTERPRETED(fun)) {
01196             native = NULL;
01197             script = fun->u.i.script;
01198             nvars = fun->u.i.nvars;
01199         } else {
01200             native = fun->u.n.native;
01201             script = NULL;
01202             nvars = 0;
01203             nslots += fun->u.n.extra;
01204         }
01205 
01206         if (JSFUN_BOUND_METHOD_TEST(fun->flags)) {
01207             /* Handle bound method special case. */
01208             thisp = parent;
01209         } else if (JSVAL_IS_OBJECT(thisv)) {
01210             thisp = JSVAL_TO_OBJECT(thisv);
01211         } else {
01212             uintN thispflags = JSFUN_THISP_FLAGS(fun->flags);
01213 
01214             JS_ASSERT(!(flags & JSINVOKE_CONSTRUCT));
01215             if (JSVAL_IS_STRING(thisv)) {
01216                 if (JSFUN_THISP_TEST(thispflags, JSFUN_THISP_STRING)) {
01217                     thisp = (JSObject *) thisv;
01218                     goto init_frame;
01219                 }
01220                 thisp = js_StringToObject(cx, JSVAL_TO_STRING(thisv));
01221             } else if (JSVAL_IS_INT(thisv)) {
01222                 if (JSFUN_THISP_TEST(thispflags, JSFUN_THISP_NUMBER)) {
01223                     thisp = (JSObject *) thisv;
01224                     goto init_frame;
01225                 }
01226                 thisp = js_NumberToObject(cx, (jsdouble)JSVAL_TO_INT(thisv));
01227             } else if (JSVAL_IS_DOUBLE(thisv)) {
01228                 if (JSFUN_THISP_TEST(thispflags, JSFUN_THISP_NUMBER)) {
01229                     thisp = (JSObject *) thisv;
01230                     goto init_frame;
01231                 }
01232                 thisp = js_NumberToObject(cx, *JSVAL_TO_DOUBLE(thisv));
01233             } else {
01234                 JS_ASSERT(JSVAL_IS_BOOLEAN(thisv));
01235                 if (JSFUN_THISP_TEST(thispflags, JSFUN_THISP_BOOLEAN)) {
01236                     thisp = (JSObject *) thisv;
01237                     goto init_frame;
01238                 }
01239                 thisp = js_BooleanToObject(cx, JSVAL_TO_BOOLEAN(thisv));
01240             }
01241             if (!thisp) {
01242                 ok = JS_FALSE;
01243                 goto out2;
01244             }
01245             goto init_frame;
01246         }
01247     }
01248 
01249     if (flags & JSINVOKE_CONSTRUCT) {
01250         /* Default return value for a constructor is the new object. */
01251         frame.rval = OBJECT_TO_JSVAL(thisp);
01252     } else {
01253         thisp = js_ComputeThis(cx, thisp, vp + 2);
01254         if (!thisp) {
01255             ok = JS_FALSE;
01256             goto out2;
01257         }
01258     }
01259 
01260   init_frame:
01261     /* Initialize the rest of frame, except for sp (set by SAVE_SP later). */
01262     frame.thisp = thisp;
01263     frame.varobj = NULL;
01264     frame.callobj = frame.argsobj = NULL;
01265     frame.script = script;
01266     frame.callee = funobj;
01267     frame.fun = fun;
01268     frame.argc = argc;
01269     frame.argv = sp - argc;
01270     frame.nvars = nvars;
01271     frame.vars = sp;
01272     frame.down = fp;
01273     frame.annotation = NULL;
01274     frame.scopeChain = NULL;    /* set below for real, after cx->fp is set */
01275     frame.pc = NULL;
01276     frame.spbase = NULL;
01277     frame.sharpDepth = 0;
01278     frame.sharpArray = NULL;
01279     frame.flags = flags;
01280     frame.dormantNext = NULL;
01281     frame.xmlNamespace = NULL;
01282     frame.blockChain = NULL;
01283 
01284     /* From here on, control must flow through label out: to return. */
01285     cx->fp = &frame;
01286 
01287     /* Init these now in case we goto out before first hook call. */
01288     hook = cx->runtime->callHook;
01289     hookData = NULL;
01290 
01291     /* Check for argument slots required by the function. */
01292     if (nslots) {
01293         /* All arguments must be contiguous, so we may have to copy actuals. */
01294         nalloc = nslots;
01295         limit = (jsval *) cx->stackPool.current->limit;
01296         JS_ASSERT((jsval *) cx->stackPool.current->base <= sp && sp <= limit);
01297         if (sp + nslots > limit) {
01298             /* Hit end of arena: we have to copy argv[-2..(argc+nslots-1)]. */
01299             nalloc += 2 + argc;
01300         } else {
01301             /* Take advantage of surplus slots in the caller's frame depth. */
01302             JS_ASSERT((jsval *)mark >= sp);
01303             surplus = (jsval *)mark - sp;
01304             nalloc -= surplus;
01305         }
01306 
01307         /* Check whether we have enough space in the caller's frame. */
01308         if ((intN)nalloc > 0) {
01309             /* Need space for actuals plus missing formals minus surplus. */
01310             newsp = js_AllocRawStack(cx, nalloc, NULL);
01311             if (!newsp) {
01312                 ok = JS_FALSE;
01313                 goto out;
01314             }
01315 
01316             /* If we couldn't allocate contiguous args, copy actuals now. */
01317             if (newsp != mark) {
01318                 JS_ASSERT(sp + nslots > limit);
01319                 JS_ASSERT(2 + argc + nslots == nalloc);
01320                 *newsp++ = vp[0];
01321                 *newsp++ = vp[1];
01322                 if (argc)
01323                     memcpy(newsp, frame.argv, argc * sizeof(jsval));
01324                 frame.argv = newsp;
01325                 sp = frame.vars = newsp + argc;
01326             }
01327         }
01328 
01329         /* Advance frame.vars to make room for the missing args. */
01330         frame.vars += nslots;
01331 
01332         /* Push void to initialize missing args. */
01333         do {
01334             PUSH(JSVAL_VOID);
01335         } while (--nslots != 0);
01336     }
01337     JS_ASSERT(nslots == 0);
01338 
01339     /* Now allocate stack space for local variables. */
01340     if (nvars) {
01341         JS_ASSERT((jsval *)cx->stackPool.current->avail >= frame.vars);
01342         surplus = (jsval *)cx->stackPool.current->avail - frame.vars;
01343         if (surplus < nvars) {
01344             newsp = js_AllocRawStack(cx, nvars, NULL);
01345             if (!newsp) {
01346                 ok = JS_FALSE;
01347                 goto out;
01348             }
01349             if (newsp != sp) {
01350                 /* NB: Discontinuity between argv and vars. */
01351                 sp = frame.vars = newsp;
01352             }
01353         }
01354 
01355         /* Push void to initialize local variables. */
01356         do {
01357             PUSH(JSVAL_VOID);
01358         } while (--nvars != 0);
01359     }
01360     JS_ASSERT(nvars == 0);
01361 
01362     /* Store the current sp in frame before calling fun. */
01363     SAVE_SP(&frame);
01364 
01365     /* call the hook if present */
01366     if (hook && (native || script))
01367         hookData = hook(cx, &frame, JS_TRUE, 0, cx->runtime->callHookData);
01368 
01369     /* Call the function, either a native method or an interpreted script. */
01370     if (native) {
01371 #ifdef DEBUG_NOT_THROWING
01372         JSBool alreadyThrowing = cx->throwing;
01373 #endif
01374 
01375 #if JS_HAS_LVALUE_RETURN
01376         /* Set by JS_SetCallReturnValue2, used to return reference types. */
01377         cx->rval2set = JS_FALSE;
01378 #endif
01379 
01380         /* If native, use caller varobj and scopeChain for eval. */
01381         frame.varobj = fp->varobj;
01382         frame.scopeChain = fp->scopeChain;
01383 
01384         /* But ensure that we have a scope chain. */
01385         if (!frame.scopeChain)
01386             frame.scopeChain = parent;
01387         ok = native(cx, frame.thisp, argc, frame.argv, &frame.rval);
01388         JS_RUNTIME_METER(cx->runtime, nativeCalls);
01389 #ifdef DEBUG_NOT_THROWING
01390         if (ok && !alreadyThrowing)
01391             ASSERT_NOT_THROWING(cx);
01392 #endif
01393     } else if (script) {
01394 #ifdef DUMP_CALL_TABLE
01395         LogCall(cx, *vp, argc, frame.argv);
01396 #endif
01397         /* Use parent scope so js_GetCallObject can find the right "Call". */
01398         frame.scopeChain = parent;
01399         if (JSFUN_HEAVYWEIGHT_TEST(fun->flags)) {
01400             /* Scope with a call object parented by the callee's parent. */
01401             if (!js_GetCallObject(cx, &frame, parent)) {
01402                 ok = JS_FALSE;
01403                 goto out;
01404             }
01405         }
01406         ok = js_Interpret(cx, script->code, &v);
01407     } else {
01408         /* fun might be onerror trying to report a syntax error in itself. */
01409         frame.scopeChain = NULL;
01410         ok = JS_TRUE;
01411     }
01412 
01413 out:
01414     if (hookData) {
01415         hook = cx->runtime->callHook;
01416         if (hook)
01417             hook(cx, &frame, JS_FALSE, &ok, hookData);
01418     }
01419 
01420     /* If frame has a call object, sync values and clear back-pointer. */
01421     if (frame.callobj)
01422         ok &= js_PutCallObject(cx, &frame);
01423 
01424     /* If frame has an arguments object, sync values and clear back-pointer. */
01425     if (frame.argsobj)
01426         ok &= js_PutArgsObject(cx, &frame);
01427 
01428     /* Restore cx->fp now that we're done releasing frame objects. */
01429     cx->fp = fp;
01430 
01431 out2:
01432     /* Pop everything we may have allocated off the stack. */
01433     JS_ARENA_RELEASE(&cx->stackPool, mark);
01434 
01435     /* Store the return value and restore sp just above it. */
01436     *vp = frame.rval;
01437     fp->sp = vp + 1;
01438 
01439     /*
01440      * Store the location of the JSOP_CALL or JSOP_EVAL that generated the
01441      * return value, but only if this is an external (compiled from script
01442      * source) call that has stack budget for the generating pc.
01443      */
01444     if (fp->script && !(flags & JSINVOKE_INTERNAL))
01445         vp[-(intN)fp->script->depth] = (jsval)fp->pc;
01446     return ok;
01447 
01448 bad:
01449     js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_FUNFLAGS);
01450     ok = JS_FALSE;
01451     goto out2;
01452 }
01453 
01454 JSBool
01455 js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags,
01456                   uintN argc, jsval *argv, jsval *rval)
01457 {
01458     JSStackFrame *fp, *oldfp, frame;
01459     jsval *oldsp, *sp;
01460     void *mark;
01461     uintN i;
01462     JSBool ok;
01463 
01464     fp = oldfp = cx->fp;
01465     if (!fp) {
01466         memset(&frame, 0, sizeof frame);
01467         cx->fp = fp = &frame;
01468     }
01469     oldsp = fp->sp;
01470     sp = js_AllocStack(cx, 2 + argc, &mark);
01471     if (!sp) {
01472         ok = JS_FALSE;
01473         goto out;
01474     }
01475 
01476     PUSH(fval);
01477     PUSH(OBJECT_TO_JSVAL(obj));
01478     for (i = 0; i < argc; i++)
01479         PUSH(argv[i]);
01480     SAVE_SP(fp);
01481     ok = js_Invoke(cx, argc, flags | JSINVOKE_INTERNAL);
01482     if (ok) {
01483         RESTORE_SP(fp);
01484 
01485         /*
01486          * Store *rval in the a scoped local root if a scope is open, else in
01487          * the lastInternalResult pigeon-hole GC root, solely so users of
01488          * js_InternalInvoke and its direct and indirect (js_ValueToString for
01489          * example) callers do not need to manage roots for local, temporary
01490          * references to such results.
01491          */
01492         *rval = POP_OPND();
01493         if (JSVAL_IS_GCTHING(*rval)) {
01494             if (cx->localRootStack) {
01495                 if (js_PushLocalRoot(cx, cx->localRootStack, *rval) < 0)
01496                     ok = JS_FALSE;
01497             } else {
01498                 cx->weakRoots.lastInternalResult = *rval;
01499             }
01500         }
01501     }
01502 
01503     js_FreeStack(cx, mark);
01504 out:
01505     fp->sp = oldsp;
01506     if (oldfp != fp)
01507         cx->fp = oldfp;
01508 
01509     return ok;
01510 }
01511 
01512 JSBool
01513 js_InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, jsval fval,
01514                     JSAccessMode mode, uintN argc, jsval *argv, jsval *rval)
01515 {
01516     int stackDummy;
01517 
01518     /*
01519      * js_InternalInvoke could result in another try to get or set the same id
01520      * again, see bug 355497.
01521      */
01522     if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) {
01523         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
01524                              JSMSG_OVER_RECURSED);
01525         return JS_FALSE;
01526     }
01527     /*
01528      * Check general (not object-ops/class-specific) access from the running
01529      * script to obj.id only if id has a scripted getter or setter that we're
01530      * about to invoke.  If we don't check this case, nothing else will -- no
01531      * other native code has the chance to check.
01532      *
01533      * Contrast this non-native (scripted) case with native getter and setter
01534      * accesses, where the native itself must do an access check, if security
01535      * policies requires it.  We make a checkAccess or checkObjectAccess call
01536      * back to the embedding program only in those cases where we're not going
01537      * to call an embedding-defined native function, getter, setter, or class
01538      * hook anyway.  Where we do call such a native, there's no need for the
01539      * engine to impose a separate access check callback on all embeddings --
01540      * many embeddings have no security policy at all.
01541      */
01542     JS_ASSERT(mode == JSACC_READ || mode == JSACC_WRITE);
01543     if (cx->runtime->checkObjectAccess &&
01544         VALUE_IS_FUNCTION(cx, fval) &&
01545         FUN_INTERPRETED((JSFunction *)
01546                         JS_GetPrivate(cx, JSVAL_TO_OBJECT(fval))) &&
01547         !cx->runtime->checkObjectAccess(cx, obj, ID_TO_VALUE(id), mode,
01548                                         &fval)) {
01549         return JS_FALSE;
01550     }
01551 
01552     return js_InternalCall(cx, obj, fval, argc, argv, rval);
01553 }
01554 
01555 JSBool
01556 js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
01557            JSStackFrame *down, uintN flags, jsval *result)
01558 {
01559     JSInterpreterHook hook;
01560     void *hookData, *mark;
01561     JSStackFrame *oldfp, frame;
01562     JSObject *obj, *tmp;
01563     JSBool ok;
01564 
01565     hook = cx->runtime->executeHook;
01566     hookData = mark = NULL;
01567     oldfp = cx->fp;
01568     frame.script = script;
01569     if (down) {
01570         /* Propagate arg/var state for eval and the debugger API. */
01571         frame.callobj = down->callobj;
01572         frame.argsobj = down->argsobj;
01573         frame.varobj = down->varobj;
01574         frame.callee = down->callee;
01575         frame.fun = down->fun;
01576         frame.thisp = down->thisp;
01577         frame.argc = down->argc;
01578         frame.argv = down->argv;
01579         frame.nvars = down->nvars;
01580         frame.vars = down->vars;
01581         frame.annotation = down->annotation;
01582         frame.sharpArray = down->sharpArray;
01583     } else {
01584         frame.callobj = frame.argsobj = NULL;
01585         obj = chain;
01586         if (cx->options & JSOPTION_VAROBJFIX) {
01587             while ((tmp = OBJ_GET_PARENT(cx, obj)) != NULL)
01588                 obj = tmp;
01589         }
01590         frame.varobj = obj;
01591         frame.callee = NULL;
01592         frame.fun = NULL;
01593         frame.thisp = chain;
01594         frame.argc = 0;
01595         frame.argv = NULL;
01596         frame.nvars = script->numGlobalVars;
01597         if (frame.nvars) {
01598             frame.vars = js_AllocRawStack(cx, frame.nvars, &mark);
01599             if (!frame.vars)
01600                 return JS_FALSE;
01601             memset(frame.vars, 0, frame.nvars * sizeof(jsval));
01602         } else {
01603             frame.vars = NULL;
01604         }
01605         frame.annotation = NULL;
01606         frame.sharpArray = NULL;
01607     }
01608     frame.rval = JSVAL_VOID;
01609     frame.down = down;
01610     frame.scopeChain = chain;
01611     frame.pc = NULL;
01612     frame.sp = oldfp ? oldfp->sp : NULL;
01613     frame.spbase = NULL;
01614     frame.sharpDepth = 0;
01615     frame.flags = flags;
01616     frame.dormantNext = NULL;
01617     frame.xmlNamespace = NULL;
01618     frame.blockChain = NULL;
01619 
01620     /*
01621      * Here we wrap the call to js_Interpret with code to (conditionally)
01622      * save and restore the old stack frame chain into a chain of 'dormant'
01623      * frame chains.  Since we are replacing cx->fp, we were running into
01624      * the problem that if GC was called under this frame, some of the GC
01625      * things associated with the old frame chain (available here only in
01626      * the C variable 'oldfp') were not rooted and were being collected.
01627      *
01628      * So, now we preserve the links to these 'dormant' frame chains in cx
01629      * before calling js_Interpret and cleanup afterwards.  The GC walks
01630      * these dormant chains and marks objects in the same way that it marks
01631      * objects in the primary cx->fp chain.
01632      */
01633     if (oldfp && oldfp != down) {
01634         JS_ASSERT(!oldfp->dormantNext);
01635         oldfp->dormantNext = cx->dormantFrameChain;
01636         cx->dormantFrameChain = oldfp;
01637     }
01638 
01639     cx->fp = &frame;
01640     if (hook)
01641         hookData = hook(cx, &frame, JS_TRUE, 0, cx->runtime->executeHookData);
01642 
01643     /*
01644      * Use frame.rval, not result, so the last result stays rooted across any
01645      * GC activations nested within this js_Interpret.
01646      */
01647     ok = js_Interpret(cx, script->code, &frame.rval);
01648     *result = frame.rval;
01649 
01650     if (hookData) {
01651         hook = cx->runtime->executeHook;
01652         if (hook)
01653             hook(cx, &frame, JS_FALSE, &ok, hookData);
01654     }
01655     if (mark)
01656         js_FreeRawStack(cx, mark);
01657     cx->fp = oldfp;
01658 
01659     if (oldfp && oldfp != down) {
01660         JS_ASSERT(cx->dormantFrameChain == oldfp);
01661         cx->dormantFrameChain = oldfp->dormantNext;
01662         oldfp->dormantNext = NULL;
01663     }
01664 
01665     return ok;
01666 }
01667 
01668 #if JS_HAS_EXPORT_IMPORT
01669 /*
01670  * If id is JSVAL_VOID, import all exported properties from obj.
01671  */
01672 static JSBool
01673 ImportProperty(JSContext *cx, JSObject *obj, jsid id)
01674 {
01675     JSBool ok;
01676     JSIdArray *ida;
01677     JSProperty *prop;
01678     JSObject *obj2, *target, *funobj, *closure;
01679     JSString *str;
01680     uintN attrs;
01681     jsint i;
01682     jsval value;
01683 
01684     if (JSVAL_IS_VOID(id)) {
01685         ida = JS_Enumerate(cx, obj);
01686         if (!ida)
01687             return JS_FALSE;
01688         ok = JS_TRUE;
01689         if (ida->length == 0)
01690             goto out;
01691     } else {
01692         ida = NULL;
01693         if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
01694             return JS_FALSE;
01695         if (!prop) {
01696             str = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK,
01697                                              ID_TO_VALUE(id), NULL);
01698             if (str)
01699                 js_ReportIsNotDefined(cx, JS_GetStringBytes(str));
01700             return JS_FALSE;
01701         }
01702         ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, &attrs);
01703         OBJ_DROP_PROPERTY(cx, obj2, prop);
01704         if (!ok)
01705             return JS_FALSE;
01706         if (!(attrs & JSPROP_EXPORTED)) {
01707             str = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK,
01708                                              ID_TO_VALUE(id), NULL);
01709             if (str) {
01710                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
01711                                      JSMSG_NOT_EXPORTED,
01712                                      JS_GetStringBytes(str));
01713             }
01714             return JS_FALSE;
01715         }
01716     }
01717 
01718     target = cx->fp->varobj;
01719     i = 0;
01720     do {
01721         if (ida) {
01722             id = ida->vector[i];
01723             ok = OBJ_GET_ATTRIBUTES(cx, obj, id, NULL, &attrs);
01724             if (!ok)
01725                 goto out;
01726             if (!(attrs & JSPROP_EXPORTED))
01727                 continue;
01728         }
01729         ok = OBJ_CHECK_ACCESS(cx, obj, id, JSACC_IMPORT, &value, &attrs);
01730         if (!ok)
01731             goto out;
01732         if (VALUE_IS_FUNCTION(cx, value)) {
01733             funobj = JSVAL_TO_OBJECT(value);
01734             closure = js_CloneFunctionObject(cx, funobj, obj);
01735             if (!closure) {
01736                 ok = JS_FALSE;
01737                 goto out;
01738             }
01739             value = OBJECT_TO_JSVAL(closure);
01740         }
01741 
01742         /*
01743          * Handle the case of importing a property that refers to a local
01744          * variable or formal parameter of a function activation.  These
01745          * properties are accessed by opcodes using stack slot numbers
01746          * generated by the compiler rather than runtime name-lookup.  These
01747          * local references, therefore, bypass the normal scope chain lookup.
01748          * So, instead of defining a new property in the activation object,
01749          * modify the existing value in the stack slot.
01750          */
01751         if (OBJ_GET_CLASS(cx, target) == &js_CallClass) {
01752             ok = OBJ_LOOKUP_PROPERTY(cx, target, id, &obj2, &prop);
01753             if (!ok)
01754                 goto out;
01755         } else {
01756             prop = NULL;
01757         }
01758         if (prop && target == obj2) {
01759             ok = OBJ_SET_PROPERTY(cx, target, id, &value);
01760         } else {
01761             ok = OBJ_DEFINE_PROPERTY(cx, target, id, value, NULL, NULL,
01762                                      attrs & ~(JSPROP_EXPORTED |
01763                                                JSPROP_GETTER |
01764                                                JSPROP_SETTER),
01765                                      NULL);
01766         }
01767         if (prop)
01768             OBJ_DROP_PROPERTY(cx, obj2, prop);
01769         if (!ok)
01770             goto out;
01771     } while (ida && ++i < ida->length);
01772 
01773 out:
01774     if (ida)
01775         JS_DestroyIdArray(cx, ida);
01776     return ok;
01777 }
01778 #endif /* JS_HAS_EXPORT_IMPORT */
01779 
01780 JSBool
01781 js_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs,
01782                       JSObject **objp, JSProperty **propp)
01783 {
01784     JSObject *obj2;
01785     JSProperty *prop;
01786     uintN oldAttrs, report;
01787     JSBool isFunction;
01788     jsval value;
01789     const char *type, *name;
01790 
01791     if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
01792         return JS_FALSE;
01793     if (propp) {
01794         *objp = obj2;
01795         *propp = prop;
01796     }
01797     if (!prop)
01798         return JS_TRUE;
01799 
01800     /*
01801      * Use prop as a speedup hint to OBJ_GET_ATTRIBUTES, but drop it on error.
01802      * An assertion at label bad: will insist that it is null.
01803      */
01804     if (!OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &oldAttrs)) {
01805         OBJ_DROP_PROPERTY(cx, obj2, prop);
01806 #ifdef DEBUG
01807         prop = NULL;
01808 #endif
01809         goto bad;
01810     }
01811 
01812     /*
01813      * From here, return true, or else goto bad on failure to null out params.
01814      * If our caller doesn't want prop, drop it (we don't need it any longer).
01815      */
01816     if (!propp) {
01817         OBJ_DROP_PROPERTY(cx, obj2, prop);
01818         prop = NULL;
01819     }
01820 
01821     /* If either property is readonly, we have an error. */
01822     report = ((oldAttrs | attrs) & JSPROP_READONLY)
01823              ? JSREPORT_ERROR
01824              : JSREPORT_WARNING | JSREPORT_STRICT;
01825 
01826     if (report != JSREPORT_ERROR) {
01827         /*
01828          * Allow redeclaration of variables and functions, but insist that the
01829          * new value is not a getter if the old value was, ditto for setters --
01830          * unless prop is impermanent (in which case anyone could delete it and
01831          * redefine it, willy-nilly).
01832          */
01833         if (!(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
01834             return JS_TRUE;
01835         if ((~(oldAttrs ^ attrs) & (JSPROP_GETTER | JSPROP_SETTER)) == 0)
01836             return JS_TRUE;
01837         if (!(oldAttrs & JSPROP_PERMANENT))
01838             return JS_TRUE;
01839         report = JSREPORT_ERROR;
01840     }
01841 
01842     isFunction = (oldAttrs & (JSPROP_GETTER | JSPROP_SETTER)) != 0;
01843     if (!isFunction) {
01844         if (!OBJ_GET_PROPERTY(cx, obj, id, &value))
01845             goto bad;
01846         isFunction = VALUE_IS_FUNCTION(cx, value);
01847     }
01848     type = (oldAttrs & attrs & JSPROP_GETTER)
01849            ? js_getter_str
01850            : (oldAttrs & attrs & JSPROP_SETTER)
01851            ? js_setter_str
01852            : (oldAttrs & JSPROP_READONLY)
01853            ? js_const_str
01854            : isFunction
01855            ? js_function_str
01856            : js_var_str;
01857     name = js_ValueToPrintableString(cx, ID_TO_VALUE(id));
01858     if (!name)
01859         goto bad;
01860     return JS_ReportErrorFlagsAndNumber(cx, report,
01861                                         js_GetErrorMessage, NULL,
01862                                         JSMSG_REDECLARED_VAR,
01863                                         type, name);
01864 
01865 bad:
01866     if (propp) {
01867         *objp = NULL;
01868         *propp = NULL;
01869     }
01870     JS_ASSERT(!prop);
01871     return JS_FALSE;
01872 }
01873 
01874 JSBool
01875 js_StrictlyEqual(jsval lval, jsval rval)
01876 {
01877     jsval ltag = JSVAL_TAG(lval), rtag = JSVAL_TAG(rval);
01878     jsdouble ld, rd;
01879 
01880     if (ltag == rtag) {
01881         if (ltag == JSVAL_STRING) {
01882             JSString *lstr = JSVAL_TO_STRING(lval),
01883                      *rstr = JSVAL_TO_STRING(rval);
01884             return js_EqualStrings(lstr, rstr);
01885         }
01886         if (ltag == JSVAL_DOUBLE) {
01887             ld = *JSVAL_TO_DOUBLE(lval);
01888             rd = *JSVAL_TO_DOUBLE(rval);
01889             return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
01890         }
01891         return lval == rval;
01892     }
01893     if (ltag == JSVAL_DOUBLE && JSVAL_IS_INT(rval)) {
01894         ld = *JSVAL_TO_DOUBLE(lval);
01895         rd = JSVAL_TO_INT(rval);
01896         return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
01897     }
01898     if (JSVAL_IS_INT(lval) && rtag == JSVAL_DOUBLE) {
01899         ld = JSVAL_TO_INT(lval);
01900         rd = *JSVAL_TO_DOUBLE(rval);
01901         return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
01902     }
01903     return lval == rval;
01904 }
01905 
01906 JSBool
01907 js_InvokeConstructor(JSContext *cx, jsval *vp, uintN argc)
01908 {
01909     JSFunction *fun;
01910     JSObject *obj, *obj2, *proto, *parent;
01911     jsval lval, rval;
01912     JSClass *clasp, *funclasp;
01913 
01914     fun = NULL;
01915     obj2 = NULL;
01916     lval = *vp;
01917     if (!JSVAL_IS_OBJECT(lval) ||
01918         (obj2 = JSVAL_TO_OBJECT(lval)) == NULL ||
01919         /* XXX clean up to avoid special cases above ObjectOps layer */
01920         OBJ_GET_CLASS(cx, obj2) == &js_FunctionClass ||
01921         !obj2->map->ops->construct)
01922     {
01923         fun = js_ValueToFunction(cx, vp, JSV2F_CONSTRUCT);
01924         if (!fun)
01925             return JS_FALSE;
01926     }
01927 
01928     clasp = &js_ObjectClass;
01929     if (!obj2) {
01930         proto = parent = NULL;
01931         fun = NULL;
01932     } else {
01933         /*
01934          * Get the constructor prototype object for this function.
01935          * Use the nominal 'this' parameter slot, vp[1], as a local
01936          * root to protect this prototype, in case it has no other
01937          * strong refs.
01938          */
01939         if (!OBJ_GET_PROPERTY(cx, obj2,
01940                               ATOM_TO_JSID(cx->runtime->atomState
01941                                            .classPrototypeAtom),
01942                               &vp[1])) {
01943             return JS_FALSE;
01944         }
01945         rval = vp[1];
01946         proto = JSVAL_IS_OBJECT(rval) ? JSVAL_TO_OBJECT(rval) : NULL;
01947         parent = OBJ_GET_PARENT(cx, obj2);
01948 
01949         if (OBJ_GET_CLASS(cx, obj2) == &js_FunctionClass) {
01950             funclasp = ((JSFunction *)JS_GetPrivate(cx, obj2))->clasp;
01951             if (funclasp)
01952                 clasp = funclasp;
01953         }
01954     }
01955     obj = js_NewObject(cx, clasp, proto, parent);
01956     if (!obj)
01957         return JS_FALSE;
01958 
01959     /* Now we have an object with a constructor method; call it. */
01960     vp[1] = OBJECT_TO_JSVAL(obj);
01961     if (!js_Invoke(cx, argc, JSINVOKE_CONSTRUCT)) {
01962         cx->weakRoots.newborn[GCX_OBJECT] = NULL;
01963         return JS_FALSE;
01964     }
01965 
01966     /* Check the return value and if it's primitive, force it to be obj. */
01967     rval = *vp;
01968     if (JSVAL_IS_PRIMITIVE(rval)) {
01969         if (!fun) {
01970             /* native [[Construct]] returning primitive is error */
01971             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
01972                                  JSMSG_BAD_NEW_RESULT,
01973                                  js_ValueToPrintableString(cx, rval));
01974             return JS_FALSE;
01975         }
01976         *vp = OBJECT_TO_JSVAL(obj);
01977     }
01978 
01979     JS_RUNTIME_METER(cx->runtime, constructs);
01980     return JS_TRUE;
01981 }
01982 
01983 static JSBool
01984 InternStringElementId(JSContext *cx, jsval idval, jsid *idp)
01985 {
01986     JSAtom *atom;
01987 
01988     atom = js_ValueToStringAtom(cx, idval);
01989     if (!atom)
01990         return JS_FALSE;
01991     *idp = ATOM_TO_JSID(atom);
01992     return JS_TRUE;
01993 }
01994 
01995 static JSBool
01996 InternNonIntElementId(JSContext *cx, jsval idval, jsid *idp)
01997 {
01998     JS_ASSERT(!JSVAL_IS_INT(idval));
01999 
02000 #if JS_HAS_XML_SUPPORT
02001     if (JSVAL_IS_OBJECT(idval)) {
02002         *idp = OBJECT_JSVAL_TO_JSID(idval);
02003         return JS_TRUE;
02004     }
02005 #endif
02006 
02007     return InternStringElementId(cx, idval, idp);
02008 }
02009 
02010 #if JS_HAS_XML_SUPPORT
02011 #define CHECK_ELEMENT_ID(obj, id)                                             \
02012     JS_BEGIN_MACRO                                                            \
02013         if (JSID_IS_OBJECT(id) && !OBJECT_IS_XML(cx, obj)) {                  \
02014             SAVE_SP_AND_PC(fp);                                               \
02015             ok = InternStringElementId(cx, OBJECT_JSID_TO_JSVAL(id), &id);    \
02016             if (!ok)                                                          \
02017                 goto out;                                                     \
02018         }                                                                     \
02019     JS_END_MACRO
02020 
02021 #else
02022 #define CHECK_ELEMENT_ID(obj, id)       JS_ASSERT(!JSID_IS_OBJECT(id))
02023 #endif
02024 
02025 #ifndef MAX_INTERP_LEVEL
02026 #if defined(XP_OS2)
02027 #define MAX_INTERP_LEVEL 250
02028 #else
02029 #define MAX_INTERP_LEVEL 1000
02030 #endif
02031 #endif
02032 
02033 #define MAX_INLINE_CALL_COUNT 1000
02034 
02035 /*
02036  * Threaded interpretation via computed goto appears to be well-supported by
02037  * GCC 3 and higher.  IBM's C compiler when run with the right options (e.g.,
02038  * -qlanglvl=extended) also supports threading.  Ditto the SunPro C compiler.
02039  * Currently it's broken for JS_VERSION < 160, though this isn't worth fixing.
02040  * Add your compiler support macros here.
02041  */
02042 #if JS_VERSION >= 160 && (                                                    \
02043     __GNUC__ >= 3 ||                                                          \
02044     (__IBMC__ >= 700 && defined __IBM_COMPUTED_GOTO) ||                       \
02045     __SUNPRO_C >= 0x570)
02046 # define JS_THREADED_INTERP 1
02047 #else
02048 # undef JS_THREADED_INTERP
02049 #endif
02050 
02051 JSBool
02052 js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
02053 {
02054     JSRuntime *rt;
02055     JSStackFrame *fp;
02056     JSScript *script;
02057     uintN inlineCallCount;
02058     JSObject *obj, *obj2, *parent;
02059     JSVersion currentVersion, originalVersion;
02060     JSBranchCallback onbranch;
02061     JSBool ok, cond;
02062     JSTrapHandler interruptHandler;
02063     jsint depth, len;
02064     jsval *sp, *newsp;
02065     void *mark;
02066     jsbytecode *endpc, *pc2;
02067     JSOp op, op2;
02068     jsatomid atomIndex;
02069     JSAtom *atom;
02070     uintN argc, attrs, flags, slot;
02071     jsval *vp, lval, rval, ltmp, rtmp;
02072     jsid id;
02073     JSObject *withobj, *iterobj;
02074     JSProperty *prop;
02075     JSScopeProperty *sprop;
02076     JSString *str, *str2;
02077     jsint i, j;
02078     jsdouble d, d2;
02079     JSClass *clasp;
02080     JSFunction *fun;
02081     JSType type;
02082 #if !defined JS_THREADED_INTERP && defined DEBUG
02083     FILE *tracefp = NULL;
02084 #endif
02085 #if JS_HAS_EXPORT_IMPORT
02086     JSIdArray *ida;
02087 #endif
02088     jsint low, high, off, npairs;
02089     JSBool match;
02090 #if JS_HAS_GETTER_SETTER
02091     JSPropertyOp getter, setter;
02092 #endif
02093     int stackDummy;
02094 
02095 #ifdef __GNUC__
02096 # define JS_EXTENSION __extension__
02097 # define JS_EXTENSION_(s) __extension__ ({ s; })
02098 #else
02099 # define JS_EXTENSION
02100 # define JS_EXTENSION_(s) s
02101 #endif
02102 
02103 #ifdef JS_THREADED_INTERP
02104     static void *normalJumpTable[] = {
02105 # define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
02106         JS_EXTENSION &&L_##op,
02107 # include "jsopcode.tbl"
02108 # undef OPDEF
02109     };
02110 
02111     static void *interruptJumpTable[] = {
02112 # define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format)              \
02113         ((op != JSOP_PUSHOBJ)                                                 \
02114          ? JS_EXTENSION &&interrupt                                           \
02115          : JS_EXTENSION &&L_JSOP_PUSHOBJ),
02116 # include "jsopcode.tbl"
02117 # undef OPDEF
02118     };
02119 
02120     register void **jumpTable = normalJumpTable;
02121 
02122 # define DO_OP()            JS_EXTENSION_(goto *jumpTable[op])
02123 # define DO_NEXT_OP(n)      do { op = *(pc += (n)); DO_OP(); } while (0)
02124 # define BEGIN_CASE(OP)     L_##OP:
02125 # define END_CASE(OP)       DO_NEXT_OP(OP##_LENGTH);
02126 # define END_VARLEN_CASE    DO_NEXT_OP(len);
02127 # define EMPTY_CASE(OP)     BEGIN_CASE(OP) op = *++pc; DO_OP();
02128 #else
02129 # define DO_OP()            goto do_op
02130 # define DO_NEXT_OP(n)      goto advance_pc
02131 # define BEGIN_CASE(OP)     case OP:
02132 # define END_CASE(OP)       break;
02133 # define END_VARLEN_CASE    break;
02134 # define EMPTY_CASE(OP)     BEGIN_CASE(OP) END_CASE(OP)
02135 #endif
02136 
02137     *result = JSVAL_VOID;
02138     rt = cx->runtime;
02139 
02140     /* Set registerized frame pointer and derived script pointer. */
02141     fp = cx->fp;
02142     script = fp->script;
02143     JS_ASSERT(script->length != 0);
02144 
02145     /* Count of JS function calls that nest in this C js_Interpret frame. */
02146     inlineCallCount = 0;
02147 
02148     /*
02149      * Optimized Get and SetVersion for proper script language versioning.
02150      *
02151      * If any native method or JSClass/JSObjectOps hook calls js_SetVersion
02152      * and changes cx->version, the effect will "stick" and we will stop
02153      * maintaining currentVersion.  This is relied upon by testsuites, for
02154      * the most part -- web browsers select version before compiling and not
02155      * at run-time.
02156      */
02157     currentVersion = script->version;
02158     originalVersion = cx->version;
02159     if (currentVersion != originalVersion)
02160         js_SetVersion(cx, currentVersion);
02161 
02162 #ifdef __GNUC__
02163     flags = 0;  /* suppress gcc warnings */
02164     id = 0;
02165 #endif
02166 
02167     /*
02168      * Prepare to call a user-supplied branch handler, and abort the script
02169      * if it returns false.  We reload onbranch after calling out to native
02170      * functions (but not to getters, setters, or other native hooks).
02171      */
02172 #define LOAD_BRANCH_CALLBACK(cx)    (onbranch = (cx)->branchCallback)
02173 
02174     LOAD_BRANCH_CALLBACK(cx);
02175 #define CHECK_BRANCH(len)                                                     \
02176     JS_BEGIN_MACRO                                                            \
02177         if (len <= 0 && onbranch) {                                           \
02178             SAVE_SP_AND_PC(fp);                                               \
02179             if (!(ok = (*onbranch)(cx, script)))                              \
02180                 goto out;                                                     \
02181         }                                                                     \
02182     JS_END_MACRO
02183 
02184     /*
02185      * Load the debugger's interrupt hook here and after calling out to native
02186      * functions (but not to getters, setters, or other native hooks), so we do
02187      * not have to reload it each time through the interpreter loop -- we hope
02188      * the compiler can keep it in a register when it is non-null.
02189      */
02190 #ifdef JS_THREADED_INTERP
02191 # define LOAD_JUMP_TABLE()                                                    \
02192     (jumpTable = interruptHandler ? interruptJumpTable : normalJumpTable)
02193 #else
02194 # define LOAD_JUMP_TABLE()      /* nothing */
02195 #endif
02196 
02197 #define LOAD_INTERRUPT_HANDLER(rt)                                            \
02198     JS_BEGIN_MACRO                                                            \
02199         interruptHandler = (rt)->interruptHandler;                            \
02200         LOAD_JUMP_TABLE();                                                    \
02201     JS_END_MACRO
02202 
02203     LOAD_INTERRUPT_HANDLER(rt);
02204 
02205     /* Check for too much js_Interpret nesting, or too deep a C stack. */
02206     if (++cx->interpLevel == MAX_INTERP_LEVEL ||
02207         !JS_CHECK_STACK_SIZE(cx, stackDummy)) {
02208         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED);
02209         ok = JS_FALSE;
02210         goto out2;
02211     }
02212 
02213     /*
02214      * Allocate operand and pc stack slots for the script's worst-case depth,
02215      * unless we're called to interpret a part of an already active script, a
02216      * filtering predicate expression for example.
02217      */
02218     depth = (jsint) script->depth;
02219     if (JS_LIKELY(!fp->spbase)) {
02220         newsp = js_AllocRawStack(cx, (uintN)(2 * depth), &mark);
02221         if (!newsp) {
02222             ok = JS_FALSE;
02223             goto out2;
02224         }
02225         sp = newsp + depth;
02226         fp->spbase = sp;
02227         SAVE_SP(fp);
02228     } else {
02229         sp = fp->sp;
02230         JS_ASSERT(JS_UPTRDIFF(sp, fp->spbase) <= depth * sizeof(jsval));
02231         newsp = fp->spbase - depth;
02232         mark = NULL;
02233     }
02234 
02235     /*
02236      * To support generator_throw and to catch ignored exceptions, fail right
02237      * away if cx->throwing is set.  If no exception is pending, null obj in
02238      * case a callable object is being sent into a yield expression, and the
02239      * yield's result is invoked.
02240      */
02241     ok = !cx->throwing;
02242     if (!ok) {
02243 #ifdef DEBUG_NOT_THROWING
02244         printf("JS INTERPRETER CALLED WITH PENDING EXCEPTION %lx\n",
02245                (unsigned long) cx->exception);
02246 #endif
02247         goto out;
02248     }
02249     obj = NULL;
02250 
02251 #ifdef JS_THREADED_INTERP
02252 
02253     /*
02254      * This is a loop, but it does not look like a loop.  The loop-closing
02255      * jump is distributed throughout interruptJumpTable, and comes back to
02256      * the interrupt label.  The dispatch on op is through normalJumpTable.
02257      * The trick is LOAD_INTERRUPT_HANDLER setting jumpTable appropriately.
02258      *
02259      * It is important that "op" be initialized before the interrupt label
02260      * because it is possible for "op" to be specially assigned during the
02261      * normally processing of an opcode while looping (in particular, this
02262      * happens in JSOP_TRAP while debugging).  We rely on DO_NEXT_OP to
02263      * correctly manage "op" in all other cases.
02264      */
02265     op = (JSOp) *pc;
02266     if (interruptHandler) {
02267 interrupt:
02268         SAVE_SP_AND_PC(fp);
02269         switch (interruptHandler(cx, script, pc, &rval,
02270                                  rt->interruptHandlerData)) {
02271           case JSTRAP_ERROR:
02272             ok = JS_FALSE;
02273             goto out;
02274           case JSTRAP_CONTINUE:
02275             break;
02276           case JSTRAP_RETURN:
02277             fp->rval = rval;
02278             goto out;
02279           case JSTRAP_THROW:
02280             cx->throwing = JS_TRUE;
02281             cx->exception = rval;
02282             ok = JS_FALSE;
02283             goto out;
02284           default:;
02285         }
02286         LOAD_INTERRUPT_HANDLER(rt);
02287     }
02288 
02289     JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT);
02290     JS_EXTENSION_(goto *normalJumpTable[op]);
02291 
02292 #else  /* !JS_THREADED_INTERP */
02293 
02294     for (;;) {
02295         op = (JSOp) *pc;
02296       do_op:
02297         len = js_CodeSpec[op].length;
02298 
02299 #ifdef DEBUG
02300         tracefp = (FILE *) cx->tracefp;
02301         if (tracefp) {
02302             intN nuses, n;
02303 
02304             fprintf(tracefp, "%4u: ", js_PCToLineNumber(cx, script, pc));
02305             js_Disassemble1(cx, script, pc,
02306                             PTRDIFF(pc, script->code, jsbytecode), JS_FALSE,
02307                             tracefp);
02308             nuses = js_CodeSpec[op].nuses;
02309             if (nuses) {
02310                 SAVE_SP_AND_PC(fp);
02311                 for (n = -nuses; n < 0; n++) {
02312                     str = js_DecompileValueGenerator(cx, n, sp[n], NULL);
02313                     if (str) {
02314                         fprintf(tracefp, "%s %s",
02315                                 (n == -nuses) ? "  inputs:" : ",",
02316                                 JS_GetStringBytes(str));
02317                     }
02318                 }
02319                 fprintf(tracefp, " @ %d\n", sp - fp->spbase);
02320             }
02321         }
02322 #endif /* DEBUG */
02323 
02324         if (interruptHandler && op != JSOP_PUSHOBJ) {
02325             SAVE_SP_AND_PC(fp);
02326             switch (interruptHandler(cx, script, pc, &rval,
02327                                      rt->interruptHandlerData)) {
02328               case JSTRAP_ERROR:
02329                 ok = JS_FALSE;
02330                 goto out;
02331               case JSTRAP_CONTINUE:
02332                 break;
02333               case JSTRAP_RETURN:
02334                 fp->rval = rval;
02335                 goto out;
02336               case JSTRAP_THROW:
02337                 cx->throwing = JS_TRUE;
02338                 cx->exception = rval;
02339                 ok = JS_FALSE;
02340                 goto out;
02341               default:;
02342             }
02343             LOAD_INTERRUPT_HANDLER(rt);
02344         }
02345 
02346         switch (op) {
02347 
02348 #endif /* !JS_THREADED_INTERP */
02349 
02350           BEGIN_CASE(JSOP_STOP)
02351             goto out;
02352 
02353           EMPTY_CASE(JSOP_NOP)
02354 
02355           BEGIN_CASE(JSOP_GROUP)
02356             obj = NULL;
02357           END_CASE(JSOP_GROUP)
02358 
02359           BEGIN_CASE(JSOP_PUSH)
02360             PUSH_OPND(JSVAL_VOID);
02361           END_CASE(JSOP_PUSH)
02362 
02363           BEGIN_CASE(JSOP_POP)
02364             sp--;
02365           END_CASE(JSOP_POP)
02366 
02367           BEGIN_CASE(JSOP_POP2)
02368             sp -= 2;
02369           END_CASE(JSOP_POP2)
02370 
02371           BEGIN_CASE(JSOP_SWAP)
02372             vp = sp - depth;    /* swap generating pc's for the decompiler */
02373             ltmp = vp[-1];
02374             vp[-1] = vp[-2];
02375             sp[-2] = ltmp;
02376             rtmp = sp[-1];
02377             sp[-1] = sp[-2];
02378             sp[-2] = rtmp;
02379           END_CASE(JSOP_SWAP)
02380 
02381           BEGIN_CASE(JSOP_POPV)
02382             *result = POP_OPND();
02383           END_CASE(JSOP_POPV)
02384 
02385           BEGIN_CASE(JSOP_ENTERWITH)
02386             FETCH_OBJECT(cx, -1, rval, obj);
02387             SAVE_SP_AND_PC(fp);
02388             OBJ_TO_INNER_OBJECT(cx, obj);
02389             if (!obj || !(obj2 = js_GetScopeChain(cx, fp))) {
02390                 ok = JS_FALSE;
02391                 goto out;
02392             }
02393             withobj = js_NewWithObject(cx, obj, obj2, sp - fp->spbase - 1);
02394             if (!withobj) {
02395                 ok = JS_FALSE;
02396                 goto out;
02397             }
02398             fp->scopeChain = withobj;
02399             STORE_OPND(-1, OBJECT_TO_JSVAL(withobj));
02400           END_CASE(JSOP_ENTERWITH)
02401 
02402           BEGIN_CASE(JSOP_LEAVEWITH)
02403             rval = POP_OPND();
02404             JS_ASSERT(JSVAL_IS_OBJECT(rval));
02405             withobj = JSVAL_TO_OBJECT(rval);
02406             JS_ASSERT(OBJ_GET_CLASS(cx, withobj) == &js_WithClass);
02407             fp->scopeChain = OBJ_GET_PARENT(cx, withobj);
02408             JS_SetPrivate(cx, withobj, NULL);
02409           END_CASE(JSOP_LEAVEWITH)
02410 
02411           BEGIN_CASE(JSOP_SETRVAL)
02412             ASSERT_NOT_THROWING(cx);
02413             fp->rval = POP_OPND();
02414           END_CASE(JSOP_SETRVAL)
02415 
02416           BEGIN_CASE(JSOP_RETURN)
02417             CHECK_BRANCH(-1);
02418             fp->rval = POP_OPND();
02419             /* FALL THROUGH */
02420 
02421           BEGIN_CASE(JSOP_RETRVAL)    /* fp->rval already set */
02422             ASSERT_NOT_THROWING(cx);
02423             if (inlineCallCount)
02424           inline_return:
02425             {
02426                 JSInlineFrame *ifp = (JSInlineFrame *) fp;
02427                 void *hookData = ifp->hookData;
02428 
02429                 /*
02430                  * If fp has blocks on its scope chain, home their locals now,
02431                  * before calling any debugger hook, and before freeing stack.
02432                  * This matches the order of block putting and hook calling in
02433                  * the "out-of-line" return code at the bottom of js_Interpret
02434                  * and in js_Invoke.
02435                  */
02436                 if (fp->flags & JSFRAME_POP_BLOCKS) {
02437                     SAVE_SP_AND_PC(fp);
02438                     ok &= PutBlockObjects(cx, fp);
02439                 }
02440 
02441                 if (hookData) {
02442                     JSInterpreterHook hook = rt->callHook;
02443                     if (hook) {
02444                         SAVE_SP_AND_PC(fp);
02445                         hook(cx, fp, JS_FALSE, &ok, hookData);
02446                         LOAD_INTERRUPT_HANDLER(rt);
02447                     }
02448                 }
02449 
02450                 /*
02451                  * If fp has a call object, sync values and clear the back-
02452                  * pointer. This can happen for a lightweight function if it
02453                  * calls eval unexpectedly (in a way that is hidden from the
02454                  * compiler). See bug 325540.
02455                  */
02456                 if (fp->callobj) {
02457                     SAVE_SP_AND_PC(fp);
02458                     ok &= js_PutCallObject(cx, fp);
02459                 }
02460 
02461                 if (fp->argsobj) {
02462                     SAVE_SP_AND_PC(fp);
02463                     ok &= js_PutArgsObject(cx, fp);
02464                 }
02465 
02466                 /* Restore context version only if callee hasn't set version. */
02467                 if (JS_LIKELY(cx->version == currentVersion)) {
02468                     currentVersion = ifp->callerVersion;
02469                     if (currentVersion != cx->version)
02470                         js_SetVersion(cx, currentVersion);
02471                 }
02472 
02473                 /* Store the return value in the caller's operand frame. */
02474                 vp = ifp->rvp;
02475                 *vp = fp->rval;
02476 
02477                 /* Restore cx->fp and release the inline frame's space. */
02478                 cx->fp = fp = fp->down;
02479                 JS_ARENA_RELEASE(&cx->stackPool, ifp->mark);
02480 
02481                 /* Restore sp to point just above the return value. */
02482                 fp->sp = vp + 1;
02483                 RESTORE_SP(fp);
02484 
02485                 /* Restore the calling script's interpreter registers. */
02486                 obj = NULL;
02487                 script = fp->script;
02488                 depth = (jsint) script->depth;
02489                 pc = fp->pc;
02490 #ifndef JS_THREADED_INTERP
02491                 endpc = script->code + script->length;
02492 #endif
02493 
02494                 /* Store the generating pc for the return value. */
02495                 vp[-depth] = (jsval)pc;
02496 
02497                 /* Resume execution in the calling frame. */
02498                 inlineCallCount--;
02499                 if (JS_LIKELY(ok)) {
02500                     JS_ASSERT(js_CodeSpec[*pc].length == JSOP_CALL_LENGTH);
02501                     len = JSOP_CALL_LENGTH;
02502                     DO_NEXT_OP(len);
02503                 }
02504             }
02505             goto out;
02506 
02507           BEGIN_CASE(JSOP_DEFAULT)
02508             (void) POP();
02509             /* FALL THROUGH */
02510           BEGIN_CASE(JSOP_GOTO)
02511             len = GET_JUMP_OFFSET(pc);
02512             CHECK_BRANCH(len);
02513           END_VARLEN_CASE
02514 
02515           BEGIN_CASE(JSOP_IFEQ)
02516             POP_BOOLEAN(cx, rval, cond);
02517             if (cond == JS_FALSE) {
02518                 len = GET_JUMP_OFFSET(pc);
02519                 CHECK_BRANCH(len);
02520                 DO_NEXT_OP(len);
02521             }
02522           END_CASE(JSOP_IFEQ)
02523 
02524           BEGIN_CASE(JSOP_IFNE)
02525             POP_BOOLEAN(cx, rval, cond);
02526             if (cond != JS_FALSE) {
02527                 len = GET_JUMP_OFFSET(pc);
02528                 CHECK_BRANCH(len);
02529                 DO_NEXT_OP(len);
02530             }
02531           END_CASE(JSOP_IFNE)
02532 
02533           BEGIN_CASE(JSOP_OR)
02534             POP_BOOLEAN(cx, rval, cond);
02535             if (cond == JS_TRUE) {
02536                 len = GET_JUMP_OFFSET(pc);
02537                 PUSH_OPND(rval);
02538                 DO_NEXT_OP(len);
02539             }
02540           END_CASE(JSOP_OR)
02541 
02542           BEGIN_CASE(JSOP_AND)
02543             POP_BOOLEAN(cx, rval, cond);
02544             if (cond == JS_FALSE) {
02545                 len = GET_JUMP_OFFSET(pc);
02546                 PUSH_OPND(rval);
02547                 DO_NEXT_OP(len);
02548             }
02549           END_CASE(JSOP_AND)
02550 
02551           BEGIN_CASE(JSOP_DEFAULTX)
02552             (void) POP();
02553             /* FALL THROUGH */
02554           BEGIN_CASE(JSOP_GOTOX)
02555             len = GET_JUMPX_OFFSET(pc);
02556             CHECK_BRANCH(len);
02557           END_VARLEN_CASE
02558 
02559           BEGIN_CASE(JSOP_IFEQX)
02560             POP_BOOLEAN(cx, rval, cond);
02561             if (cond == JS_FALSE) {
02562                 len = GET_JUMPX_OFFSET(pc);
02563                 CHECK_BRANCH(len);
02564                 DO_NEXT_OP(len);
02565             }
02566           END_CASE(JSOP_IFEQX)
02567 
02568           BEGIN_CASE(JSOP_IFNEX)
02569             POP_BOOLEAN(cx, rval, cond);
02570             if (cond != JS_FALSE) {
02571                 len = GET_JUMPX_OFFSET(pc);
02572                 CHECK_BRANCH(len);
02573                 DO_NEXT_OP(len);
02574             }
02575           END_CASE(JSOP_IFNEX)
02576 
02577           BEGIN_CASE(JSOP_ORX)
02578             POP_BOOLEAN(cx, rval, cond);
02579             if (cond == JS_TRUE) {
02580                 len = GET_JUMPX_OFFSET(pc);
02581                 PUSH_OPND(rval);
02582                 DO_NEXT_OP(len);
02583             }
02584           END_CASE(JSOP_ORX)
02585 
02586           BEGIN_CASE(JSOP_ANDX)
02587             POP_BOOLEAN(cx, rval, cond);
02588             if (cond == JS_FALSE) {
02589                 len = GET_JUMPX_OFFSET(pc);
02590                 PUSH_OPND(rval);
02591                 DO_NEXT_OP(len);
02592             }
02593           END_CASE(JSOP_ANDX)
02594 
02595 /*
02596  * If the index value at sp[n] is not an int that fits in a jsval, it could
02597  * be an object (an XML QName, AttributeName, or AnyName), but only if we are
02598  * compiling with JS_HAS_XML_SUPPORT.  Otherwise convert the index value to a
02599  * string atom id.
02600  */
02601 #define FETCH_ELEMENT_ID(n, id)                                               \
02602     JS_BEGIN_MACRO                                                            \
02603         jsval idval_ = FETCH_OPND(n);                                         \
02604         if (JSVAL_IS_INT(idval_)) {                                           \
02605             id = INT_JSVAL_TO_JSID(idval_);                                   \
02606         } else {                                                              \
02607             SAVE_SP_AND_PC(fp);                                               \
02608             ok = InternNonIntElementId(cx, idval_, &id);                      \
02609             if (!ok)                                                          \
02610                 goto out;                                                     \
02611         }                                                                     \
02612     JS_END_MACRO
02613 
02614           BEGIN_CASE(JSOP_IN)
02615             SAVE_SP_AND_PC(fp);
02616             rval = FETCH_OPND(-1);
02617             if (JSVAL_IS_PRIMITIVE(rval)) {
02618                 str = js_DecompileValueGenerator(cx, -1, rval, NULL);
02619                 if (str) {
02620                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
02621                                          JSMSG_IN_NOT_OBJECT,
02622                                          JS_GetStringBytes(str));
02623                 }
02624                 ok = JS_FALSE;
02625                 goto out;
02626             }
02627             obj = JSVAL_TO_OBJECT(rval);
02628             FETCH_ELEMENT_ID(-2, id);
02629             CHECK_ELEMENT_ID(obj, id);
02630             ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
02631             if (!ok)
02632                 goto out;
02633             sp--;
02634             STORE_OPND(-1, BOOLEAN_TO_JSVAL(prop != NULL));
02635             if (prop)
02636                 OBJ_DROP_PROPERTY(cx, obj2, prop);
02637           END_CASE(JSOP_IN)
02638 
02639           BEGIN_CASE(JSOP_FOREACH)
02640             flags = JSITER_ENUMERATE | JSITER_FOREACH;
02641             goto value_to_iter;
02642 
02643 #if JS_HAS_DESTRUCTURING
02644           BEGIN_CASE(JSOP_FOREACHKEYVAL)
02645             flags = JSITER_ENUMERATE | JSITER_FOREACH | JSITER_KEYVALUE;
02646             goto value_to_iter;
02647 #endif
02648 
02649           BEGIN_CASE(JSOP_FORIN)
02650             /*
02651              * Set JSITER_ENUMERATE to indicate that for-in loop should use
02652              * the enumeration protocol's iterator for compatibility if an
02653              * explicit iterator is not given via the optional __iterator__
02654              * method.
02655              */
02656             flags = JSITER_ENUMERATE;
02657 
02658           value_to_iter:
02659             JS_ASSERT(sp > fp->spbase);
02660             SAVE_SP_AND_PC(fp);
02661             ok = js_ValueToIterator(cx, flags, &sp[-1]);
02662             if (!ok)
02663                 goto out;
02664             JS_ASSERT(!JSVAL_IS_PRIMITIVE(sp[-1]));
02665             JS_ASSERT(JSOP_FORIN_LENGTH == js_CodeSpec[op].length);
02666           END_CASE(JSOP_FORIN)
02667 
02668           BEGIN_CASE(JSOP_FORPROP)
02669             /*
02670              * Handle JSOP_FORPROP first, so the cost of the goto do_forinloop
02671              * is not paid for the more common cases.
02672              */
02673             lval = FETCH_OPND(-1);
02674             atom = GET_ATOM(cx, script, pc);
02675             id   = ATOM_TO_JSID(atom);
02676             i = -2;
02677             goto do_forinloop;
02678 
02679           BEGIN_CASE(JSOP_FORNAME)
02680             atom = GET_ATOM(cx, script, pc);
02681             id   = ATOM_TO_JSID(atom);
02682 
02683             /*
02684              * ECMA 12.6.3 says to eval the LHS after looking for properties
02685              * to enumerate, and bail without LHS eval if there are no props.
02686              * We do Find here to share the most code at label do_forinloop.
02687              * If looking for enumerable properties could have side effects,
02688              * then we'd have to move this into the common code and condition
02689              * it on op == JSOP_FORNAME.
02690              */
02691             SAVE_SP_AND_PC(fp);
02692             ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
02693             if (!ok)
02694                 goto out;
02695             if (prop)
02696                 OBJ_DROP_PROPERTY(cx, obj2, prop);
02697             lval = OBJECT_TO_JSVAL(obj);
02698             /* FALL THROUGH */
02699 
02700           BEGIN_CASE(JSOP_FORARG)
02701           BEGIN_CASE(JSOP_FORVAR)
02702           BEGIN_CASE(JSOP_FORCONST)
02703           BEGIN_CASE(JSOP_FORLOCAL)
02704             /*
02705              * JSOP_FORARG and JSOP_FORVAR don't require any lval computation
02706              * here, because they address slots on the stack (in fp->args and
02707              * fp->vars, respectively).  Same applies to JSOP_FORLOCAL, which
02708              * addresses fp->spbase.
02709              */
02710             /* FALL THROUGH */
02711 
02712           BEGIN_CASE(JSOP_FORELEM)
02713             /*
02714              * JSOP_FORELEM simply initializes or updates the iteration state
02715              * and leaves the index expression evaluation and assignment to the
02716              * enumerator until after the next property has been acquired, via
02717              * a JSOP_ENUMELEM bytecode.
02718              */
02719             i = -1;
02720 
02721           do_forinloop:
02722             /*
02723              * Reach under the top of stack to find our property iterator, a
02724              * JSObject that contains the iteration state.
02725              */
02726             JS_ASSERT(!JSVAL_IS_PRIMITIVE(sp[i]));
02727             iterobj = JSVAL_TO_OBJECT(sp[i]);
02728 
02729             SAVE_SP_AND_PC(fp);
02730             ok = js_CallIteratorNext(cx, iterobj, &rval);
02731             if (!ok)
02732                 goto out;
02733             if (rval == JSVAL_HOLE) {
02734                 rval = JSVAL_FALSE;
02735                 goto end_forinloop;
02736             }
02737 
02738             switch (op) {
02739               case JSOP_FORARG:
02740                 slot = GET_ARGNO(pc);
02741                 JS_ASSERT(slot < fp->fun->nargs);
02742                 fp->argv[slot] = rval;
02743                 break;
02744 
02745               case JSOP_FORVAR:
02746                 slot = GET_VARNO(pc);
02747                 JS_ASSERT(slot < fp->fun->u.i.nvars);
02748                 fp->vars[slot] = rval;
02749                 break;
02750 
02751               case JSOP_FORCONST:
02752                 /* Don't update the const slot. */
02753                 break;
02754 
02755               case JSOP_FORLOCAL:
02756                 slot = GET_UINT16(pc);
02757                 JS_ASSERT(slot < (uintN)depth);
02758                 vp = &fp->spbase[slot];
02759                 GC_POKE(cx, *vp);
02760                 *vp = rval;
02761                 break;
02762 
02763               case JSOP_FORELEM:
02764                 /* FORELEM is not a SET operation, it's more like BINDNAME. */
02765                 PUSH_OPND(rval);
02766                 break;
02767 
02768               default:
02769                 JS_ASSERT(op == JSOP_FORPROP || op == JSOP_FORNAME);
02770 
02771                 /* Convert lval to a non-null object containing id. */
02772                 VALUE_TO_OBJECT(cx, lval, obj);
02773                 if (op == JSOP_FORPROP)
02774                     STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
02775 
02776                 /* Set the variable obj[id] to refer to rval. */
02777                 fp->flags |= JSFRAME_ASSIGNING;
02778                 ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
02779                 fp->flags &= ~JSFRAME_ASSIGNING;
02780                 if (!ok)
02781                     goto out;
02782                 break;
02783             }
02784 
02785             /* Push true to keep looping through properties. */
02786             rval = JSVAL_TRUE;
02787 
02788           end_forinloop:
02789             sp += i + 1;
02790             PUSH_OPND(rval);
02791             len = js_CodeSpec[op].length;
02792             DO_NEXT_OP(len);
02793 
02794           BEGIN_CASE(JSOP_DUP)
02795             JS_ASSERT(sp > fp->spbase);
02796             vp = sp - 1;                /* address top of stack */
02797             rval = *vp;
02798             vp -= depth;                /* address generating pc */
02799             vp[1] = *vp;
02800             PUSH(rval);
02801           END_CASE(JSOP_DUP)
02802 
02803           BEGIN_CASE(JSOP_DUP2)
02804             JS_ASSERT(sp - 2 >= fp->spbase);
02805             vp = sp - 1;                /* address top of stack */
02806             lval = vp[-1];
02807             rval = *vp;
02808             vp -= depth;                /* address generating pc */
02809             vp[1] = vp[2] = *vp;
02810             PUSH(lval);
02811             PUSH(rval);
02812           END_CASE(JSOP_DUP2)
02813 
02814 #define PROPERTY_OP(n, call)                                                  \
02815     JS_BEGIN_MACRO                                                            \
02816         /* Fetch the left part and resolve it to a non-null object. */        \
02817         FETCH_OBJECT(cx, n, lval, obj);                                       \
02818                                                                               \
02819         /* Get or set the property, set ok false if error, true if success. */\
02820         SAVE_SP_AND_PC(fp);                                                   \
02821         call;                                                                 \
02822         if (!ok)                                                              \
02823             goto out;                                                         \
02824     JS_END_MACRO
02825 
02826 #define ELEMENT_OP(n, call)                                                   \
02827     JS_BEGIN_MACRO                                                            \
02828         /* Fetch the right part and resolve it to an internal id. */          \
02829         FETCH_ELEMENT_ID(n, id);                                              \
02830                                                                               \
02831         /* Fetch the left part and resolve it to a non-null object. */        \
02832         FETCH_OBJECT(cx, n - 1, lval, obj);                                   \
02833                                                                               \
02834         /* Ensure that id has a type suitable for use with obj. */            \
02835         CHECK_ELEMENT_ID(obj, id);                                            \
02836                                                                               \
02837         /* Get or set the element, set ok false if error, true if success. */ \
02838         SAVE_SP_AND_PC(fp);                                                   \
02839         call;                                                                 \
02840         if (!ok)                                                              \
02841             goto out;                                                         \
02842     JS_END_MACRO
02843 
02844 #define NATIVE_GET(cx,obj,pobj,sprop,vp)                                      \
02845     JS_BEGIN_MACRO                                                            \
02846         if (SPROP_HAS_STUB_GETTER(sprop)) {                                   \
02847             /* Fast path for Object instance properties. */                   \
02848             JS_ASSERT((sprop)->slot != SPROP_INVALID_SLOT ||                  \
02849                       !SPROP_HAS_STUB_SETTER(sprop));                         \
02850             *vp = ((sprop)->slot != SPROP_INVALID_SLOT)                       \
02851                   ? LOCKED_OBJ_GET_SLOT(pobj, (sprop)->slot)                  \
02852                   : JSVAL_VOID;                                               \
02853         } else {                                                              \
02854             SAVE_SP_AND_PC(fp);                                               \
02855             ok = js_NativeGet(cx, obj, pobj, sprop, vp);                      \
02856             if (!ok)                                                          \
02857                 goto out;                                                     \
02858         }                                                                     \
02859     JS_END_MACRO
02860 
02861 #define NATIVE_SET(cx,obj,sprop,vp)                                           \
02862     JS_BEGIN_MACRO                                                            \
02863         if (SPROP_HAS_STUB_SETTER(sprop) &&                                   \
02864             (sprop)->slot != SPROP_INVALID_SLOT) {                            \
02865             /* Fast path for Object instance properties. */                   \
02866             LOCKED_OBJ_SET_SLOT(obj, (sprop)->slot, *vp);                     \
02867         } else {                                                              \
02868             SAVE_SP_AND_PC(fp);                                               \
02869             ok = js_NativeSet(cx, obj, sprop, vp);                            \
02870             if (!ok)                                                          \
02871                 goto out;                                                     \
02872         }                                                                     \
02873     JS_END_MACRO
02874 
02875 /*
02876  * CACHED_GET and CACHED_SET use cx, obj, id, and rval from their callers'
02877  * environments.
02878  */
02879 #define CACHED_GET(call)                                                      \
02880     JS_BEGIN_MACRO                                                            \
02881         if (!OBJ_IS_NATIVE(obj)) {                                            \
02882             ok = call;                                                        \
02883         } else {                                                              \
02884             JS_LOCK_OBJ(cx, obj);                                             \
02885             PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, sprop);          \
02886             if (sprop) {                                                      \
02887                 NATIVE_GET(cx, obj, obj, sprop, &rval);                       \
02888                 JS_UNLOCK_OBJ(cx, obj);                                       \
02889             } else {                                                          \
02890                 JS_UNLOCK_OBJ(cx, obj);                                       \
02891                 ok = call;                                                    \
02892                 /* No fill here: js_GetProperty fills the cache. */           \
02893             }                                                                 \
02894         }                                                                     \
02895     JS_END_MACRO
02896 
02897 #define CACHED_SET(call)                                                      \
02898     JS_BEGIN_MACRO                                                            \
02899         if (!OBJ_IS_NATIVE(obj)) {                                            \
02900             ok = call;                                                        \
02901         } else {                                                              \
02902             JSScope *scope_;                                                  \
02903             JS_LOCK_OBJ(cx, obj);                                             \
02904             PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, sprop);          \
02905             if (sprop &&                                                      \
02906                 !(sprop->attrs & JSPROP_READONLY) &&                          \
02907                 (scope_ = OBJ_SCOPE(obj), !SCOPE_IS_SEALED(scope_))) {        \
02908                 NATIVE_SET(cx, obj, sprop, &rval);                            \
02909                 JS_UNLOCK_SCOPE(cx, scope_);                                  \
02910             } else {                                                          \
02911                 JS_UNLOCK_OBJ(cx, obj);                                       \
02912                 ok = call;                                                    \
02913                 /* No fill here: js_SetProperty writes through the cache. */  \
02914             }                                                                 \
02915         }                                                                     \
02916     JS_END_MACRO
02917 
02918 #define BEGIN_LITOPX_CASE(OP,PCOFF)                                           \
02919           BEGIN_CASE(OP)                                                      \
02920             pc2 = pc;                                                         \
02921             atomIndex = GET_ATOM_INDEX(pc + PCOFF);                           \
02922           do_##OP:                                                            \
02923             atom = js_GetAtom(cx, &script->atomMap, atomIndex);
02924 
02925 #define END_LITOPX_CASE(OP)                                                   \
02926           END_CASE(OP)
02927 
02928           BEGIN_LITOPX_CASE(JSOP_SETCONST, 0)
02929             obj = fp->varobj;
02930             rval = FETCH_OPND(-1);
02931             SAVE_SP_AND_PC(fp);
02932             ok = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval,
02933                                      NULL, NULL,
02934                                      JSPROP_ENUMERATE | JSPROP_PERMANENT |
02935                                      JSPROP_READONLY,
02936                                      NULL);
02937             if (!ok)
02938                 goto out;
02939             STORE_OPND(-1, rval);
02940           END_LITOPX_CASE(JSOP_SETCONST)
02941 
02942 #if JS_HAS_DESTRUCTURING
02943           BEGIN_CASE(JSOP_ENUMCONSTELEM)
02944             FETCH_ELEMENT_ID(-1, id);
02945             FETCH_OBJECT(cx, -2, lval, obj);
02946             CHECK_ELEMENT_ID(obj, id);
02947             rval = FETCH_OPND(-3);
02948             SAVE_SP_AND_PC(fp);
02949             ok = OBJ_DEFINE_PROPERTY(cx, obj, id, rval, NULL, NULL,
02950                                      JSPROP_ENUMERATE | JSPROP_PERMANENT |
02951                                      JSPROP_READONLY,
02952                                      NULL);
02953             if (!ok)
02954                 goto out;
02955             sp -= 3;
02956           END_CASE(JSOP_ENUMCONSTELEM)
02957 #endif
02958 
02959           BEGIN_LITOPX_CASE(JSOP_BINDNAME, 0)
02960             SAVE_SP_AND_PC(fp);
02961             obj = js_FindIdentifierBase(cx, ATOM_TO_JSID(atom));
02962             if (!obj) {
02963                 ok = JS_FALSE;
02964                 goto out;
02965             }
02966             PUSH_OPND(OBJECT_TO_JSVAL(obj));
02967           END_LITOPX_CASE(JSOP_BINDNAME)
02968 
02969           BEGIN_CASE(JSOP_SETNAME)
02970             atom = GET_ATOM(cx, script, pc);
02971             id   = ATOM_TO_JSID(atom);
02972             rval = FETCH_OPND(-1);
02973             lval = FETCH_OPND(-2);
02974             JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval));
02975             obj  = JSVAL_TO_OBJECT(lval);
02976             SAVE_SP_AND_PC(fp);
02977             CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval));
02978             if (!ok)
02979                 goto out;
02980             sp--;
02981             STORE_OPND(-1, rval);
02982             obj = NULL;
02983           END_CASE(JSOP_SETNAME)
02984 
02985 #define INTEGER_OP(OP, EXTRA_CODE)                                            \
02986     JS_BEGIN_MACRO                                                            \
02987         FETCH_INT(cx, -1, j);                                                 \
02988         FETCH_INT(cx, -2, i);                                                 \
02989         EXTRA_CODE                                                            \
02990         i = i OP j;                                                           \
02991         sp--;                                                                 \
02992         STORE_INT(cx, -1, i);                                                 \
02993     JS_END_MACRO
02994 
02995 #define BITWISE_OP(OP)          INTEGER_OP(OP, (void) 0;)
02996 #define SIGNED_SHIFT_OP(OP)     INTEGER_OP(OP, j &= 31;)
02997 
02998           BEGIN_CASE(JSOP_BITOR)
02999             BITWISE_OP(|);
03000           END_CASE(JSOP_BITOR)
03001 
03002           BEGIN_CASE(JSOP_BITXOR)
03003             BITWISE_OP(^);
03004           END_CASE(JSOP_BITXOR)
03005 
03006           BEGIN_CASE(JSOP_BITAND)
03007             BITWISE_OP(&);
03008           END_CASE(JSOP_BITAND)
03009 
03010 #define RELATIONAL_OP(OP)                                                     \
03011     JS_BEGIN_MACRO                                                            \
03012         rval = FETCH_OPND(-1);                                                \
03013         lval = FETCH_OPND(-2);                                                \
03014         /* Optimize for two int-tagged operands (typical loop control). */    \
03015         if ((lval & rval) & JSVAL_INT) {                                      \
03016             ltmp = lval ^ JSVAL_VOID;                                         \
03017             rtmp = rval ^ JSVAL_VOID;                                         \
03018             if (ltmp && rtmp) {                                               \
03019                 cond = JSVAL_TO_INT(lval) OP JSVAL_TO_INT(rval);              \
03020             } else {                                                          \
03021                 d  = ltmp ? JSVAL_TO_INT(lval) : *rt->jsNaN;                  \
03022                 d2 = rtmp ? JSVAL_TO_INT(rval) : *rt->jsNaN;                  \
03023                 cond = JSDOUBLE_COMPARE(d, OP, d2, JS_FALSE);                 \
03024             }                                                                 \
03025         } else {                                                              \
03026             VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_NUMBER, &lval);               \
03027             sp[-2] = lval;                                                    \
03028             VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_NUMBER, &rval);               \
03029             if (JSVAL_IS_STRING(lval) && JSVAL_IS_STRING(rval)) {             \
03030                 str  = JSVAL_TO_STRING(lval);                                 \
03031                 str2 = JSVAL_TO_STRING(rval);                                 \
03032                 cond = js_CompareStrings(str, str2) OP 0;                     \
03033             } else {                                                          \
03034                 VALUE_TO_NUMBER(cx, lval, d);                                 \
03035                 VALUE_TO_NUMBER(cx, rval, d2);                                \
03036                 cond = JSDOUBLE_COMPARE(d, OP, d2, JS_FALSE);                 \
03037             }                                                                 \
03038         }                                                                     \
03039         sp--;                                                                 \
03040         STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));                               \
03041     JS_END_MACRO
03042 
03043 /*
03044  * NB: These macros can't use JS_BEGIN_MACRO/JS_END_MACRO around their bodies
03045  * because they begin if/else chains, so callers must not put semicolons after
03046  * the call expressions!
03047  */
03048 #if JS_HAS_XML_SUPPORT
03049 #define XML_EQUALITY_OP(OP)                                                   \
03050     if ((ltmp == JSVAL_OBJECT &&                                              \
03051          (obj2 = JSVAL_TO_OBJECT(lval)) &&                                    \
03052          OBJECT_IS_XML(cx, obj2)) ||                                          \
03053         (rtmp == JSVAL_OBJECT &&                                              \
03054          (obj2 = JSVAL_TO_OBJECT(rval)) &&                                    \
03055          OBJECT_IS_XML(cx, obj2))) {                                          \
03056         JSXMLObjectOps *ops;                                                  \
03057                                                                               \
03058         ops = (JSXMLObjectOps *) obj2->map->ops;                              \
03059         if (obj2 == JSVAL_TO_OBJECT(rval))                                    \
03060             rval = lval;                                                      \
03061         SAVE_SP_AND_PC(fp);                                                   \
03062         ok = ops->equality(cx, obj2, rval, &cond);                            \
03063         if (!ok)                                                              \
03064             goto out;                                                         \
03065         cond = cond OP JS_TRUE;                                               \
03066     } else
03067 
03068 #define EXTENDED_EQUALITY_OP(OP)                                              \
03069     if (ltmp == JSVAL_OBJECT &&                                               \
03070         (obj2 = JSVAL_TO_OBJECT(lval)) &&                                     \
03071         ((clasp = OBJ_GET_CLASS(cx, obj2))->flags & JSCLASS_IS_EXTENDED)) {   \
03072         JSExtendedClass *xclasp;                                              \
03073                                                                               \
03074         xclasp = (JSExtendedClass *) clasp;                                   \
03075         SAVE_SP_AND_PC(fp);                                                   \
03076         ok = xclasp->equality(cx, obj2, rval, &cond);                         \
03077         if (!ok)                                                              \
03078             goto out;                                                         \
03079         cond = cond OP JS_TRUE;                                               \
03080     } else
03081 #else
03082 #define XML_EQUALITY_OP(OP)             /* nothing */
03083 #define EXTENDED_EQUALITY_OP(OP)        /* nothing */
03084 #endif
03085 
03086 #define EQUALITY_OP(OP, IFNAN)                                                \
03087     JS_BEGIN_MACRO                                                            \
03088         rval = FETCH_OPND(-1);                                                \
03089         lval = FETCH_OPND(-2);                                                \
03090         ltmp = JSVAL_TAG(lval);                                               \
03091         rtmp = JSVAL_TAG(rval);                                               \
03092         XML_EQUALITY_OP(OP)                                                   \
03093         if (ltmp == rtmp) {                                                   \
03094             if (ltmp == JSVAL_STRING) {                                       \
03095                 str  = JSVAL_TO_STRING(lval);                                 \
03096                 str2 = JSVAL_TO_STRING(rval);                                 \
03097                 cond = js_EqualStrings(str, str2) OP JS_TRUE;                 \
03098             } else if (ltmp == JSVAL_DOUBLE) {                                \
03099                 d  = *JSVAL_TO_DOUBLE(lval);                                  \
03100                 d2 = *JSVAL_TO_DOUBLE(rval);                                  \
03101                 cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN);                    \
03102             } else {                                                          \
03103                 EXTENDED_EQUALITY_OP(OP)                                      \
03104                 /* Handle all undefined (=>NaN) and int combinations. */      \
03105                 cond = lval OP rval;                                          \
03106             }                                                                 \
03107         } else {                                                              \
03108             if (JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval)) {                 \
03109                 cond = (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) OP 1;     \
03110             } else if (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) {          \
03111                 cond = 1 OP 0;                                                \
03112             } else {                                                          \
03113                 if (ltmp == JSVAL_OBJECT) {                                   \
03114                     VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_VOID, &sp[-2]);       \
03115                     lval = sp[-2];                                            \
03116                     ltmp = JSVAL_TAG(lval);                                   \
03117                 } else if (rtmp == JSVAL_OBJECT) {                            \
03118                     VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_VOID, &sp[-1]);       \
03119                     rval = sp[-1];                                            \
03120                     rtmp = JSVAL_TAG(rval);                                   \
03121                 }                                                             \
03122                 if (ltmp == JSVAL_STRING && rtmp == JSVAL_STRING) {           \
03123                     str  = JSVAL_TO_STRING(lval);                             \
03124                     str2 = JSVAL_TO_STRING(rval);                             \
03125                     cond = js_EqualStrings(str, str2) OP JS_TRUE;             \
03126                 } else {                                                      \
03127                     VALUE_TO_NUMBER(cx, lval, d);                             \
03128                     VALUE_TO_NUMBER(cx, rval, d2);                            \
03129                     cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN);                \
03130                 }                                                             \
03131             }                                                                 \
03132         }                                                                     \
03133         sp--;                                                                 \
03134         STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));                               \
03135     JS_END_MACRO
03136 
03137           BEGIN_CASE(JSOP_EQ)
03138             EQUALITY_OP(==, JS_FALSE);
03139           END_CASE(JSOP_EQ)
03140 
03141           BEGIN_CASE(JSOP_NE)
03142             EQUALITY_OP(!=, JS_TRUE);
03143           END_CASE(JSOP_NE)
03144 
03145 #define NEW_EQUALITY_OP(OP)                                                   \
03146     JS_BEGIN_MACRO                                                            \
03147         rval = FETCH_OPND(-1);                                                \
03148         lval = FETCH_OPND(-2);                                                \
03149         cond = js_StrictlyEqual(lval, rval) OP JS_TRUE;                       \
03150         sp--;                                                                 \
03151         STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));                               \
03152     JS_END_MACRO
03153 
03154           BEGIN_CASE(JSOP_NEW_EQ)
03155             NEW_EQUALITY_OP(==);
03156           END_CASE(JSOP_NEW_EQ)
03157 
03158           BEGIN_CASE(JSOP_NEW_NE)
03159             NEW_EQUALITY_OP(!=);
03160           END_CASE(JSOP_NEW_NE)
03161 
03162           BEGIN_CASE(JSOP_CASE)
03163             pc2 = (jsbytecode *) sp[-2-depth];
03164             NEW_EQUALITY_OP(==);
03165             (void) POP();
03166             if (cond) {
03167                 len = GET_JUMP_OFFSET(pc);
03168                 CHECK_BRANCH(len);
03169                 DO_NEXT_OP(len);
03170             }
03171             sp[-depth] = (jsval)pc2;
03172             PUSH(lval);
03173           END_CASE(JSOP_CASE)
03174 
03175           BEGIN_CASE(JSOP_CASEX)
03176             pc2 = (jsbytecode *) sp[-2-depth];
03177             NEW_EQUALITY_OP(==);
03178             (void) POP();
03179             if (cond) {
03180                 len = GET_JUMPX_OFFSET(pc);
03181                 CHECK_BRANCH(len);
03182                 DO_NEXT_OP(len);
03183             }
03184             sp[-depth] = (jsval)pc2;
03185             PUSH(lval);
03186           END_CASE(JSOP_CASEX)
03187 
03188           BEGIN_CASE(JSOP_LT)
03189             RELATIONAL_OP(<);
03190           END_CASE(JSOP_LT)
03191 
03192           BEGIN_CASE(JSOP_LE)
03193             RELATIONAL_OP(<=);
03194           END_CASE(JSOP_LE)
03195 
03196           BEGIN_CASE(JSOP_GT)
03197             RELATIONAL_OP(>);
03198           END_CASE(JSOP_GT)
03199 
03200           BEGIN_CASE(JSOP_GE)
03201             RELATIONAL_OP(>=);
03202           END_CASE(JSOP_GE)
03203 
03204 #undef EQUALITY_OP
03205 #undef RELATIONAL_OP
03206 
03207           BEGIN_CASE(JSOP_LSH)
03208             SIGNED_SHIFT_OP(<<);
03209           END_CASE(JSOP_LSH)
03210 
03211           BEGIN_CASE(JSOP_RSH)
03212             SIGNED_SHIFT_OP(>>);
03213           END_CASE(JSOP_RSH)
03214 
03215           BEGIN_CASE(JSOP_URSH)
03216           {
03217             uint32 u;
03218 
03219             FETCH_INT(cx, -1, j);
03220             FETCH_UINT(cx, -2, u);
03221             u >>= j & 31;
03222             sp--;
03223             STORE_UINT(cx, -1, u);
03224           }
03225           END_CASE(JSOP_URSH)
03226 
03227 #undef INTEGER_OP
03228 #undef BITWISE_OP
03229 #undef SIGNED_SHIFT_OP
03230 
03231           BEGIN_CASE(JSOP_ADD)
03232             rval = FETCH_OPND(-1);
03233             lval = FETCH_OPND(-2);
03234 #if JS_HAS_XML_SUPPORT
03235             if (!JSVAL_IS_PRIMITIVE(lval) &&
03236                 (obj2 = JSVAL_TO_OBJECT(lval), OBJECT_IS_XML(cx, obj2)) &&
03237                 VALUE_IS_XML(cx, rval)) {
03238                 JSXMLObjectOps *ops;
03239 
03240                 ops = (JSXMLObjectOps *) obj2->map->ops;
03241                 SAVE_SP_AND_PC(fp);
03242                 ok = ops->concatenate(cx, obj2, rval, &rval);
03243                 if (!ok)
03244                     goto out;
03245                 sp--;
03246                 STORE_OPND(-1, rval);
03247             } else
03248 #endif
03249             {
03250                 VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_VOID, &sp[-2]);
03251                 lval = sp[-2];
03252                 VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_VOID, &sp[-1]);
03253                 rval = sp[-1];
03254                 if ((cond = JSVAL_IS_STRING(lval)) || JSVAL_IS_STRING(rval)) {
03255                     SAVE_SP_AND_PC(fp);
03256                     if (cond) {
03257                         str = JSVAL_TO_STRING(lval);
03258                         ok = (str2 = js_ValueToString(cx, rval)) != NULL;
03259                         if (!ok)
03260                             goto out;
03261                         sp[-1] = STRING_TO_JSVAL(str2);
03262                     } else {
03263                         str2 = JSVAL_TO_STRING(rval);
03264                         ok = (str = js_ValueToString(cx, lval)) != NULL;
03265                         if (!ok)
03266                             goto out;
03267                         sp[-2] = STRING_TO_JSVAL(str);
03268                     }
03269                     str = js_ConcatStrings(cx, str, str2);
03270                     if (!str) {
03271                         ok = JS_FALSE;
03272                         goto out;
03273                     }
03274                     sp--;
03275                     STORE_OPND(-1, STRING_TO_JSVAL(str));
03276                 } else {
03277                     VALUE_TO_NUMBER(cx, lval, d);
03278                     VALUE_TO_NUMBER(cx, rval, d2);
03279                     d += d2;
03280                     sp--;
03281                     STORE_NUMBER(cx, -1, d);
03282                 }
03283             }
03284           END_CASE(JSOP_ADD)
03285 
03286 #define BINARY_OP(OP)                                                         \
03287     JS_BEGIN_MACRO                                                            \
03288         FETCH_NUMBER(cx, -1, d2);                                             \
03289         FETCH_NUMBER(cx, -2, d);                                              \
03290         d = d OP d2;                                                          \
03291         sp--;                                                                 \
03292         STORE_NUMBER(cx, -1, d);                                              \
03293     JS_END_MACRO
03294 
03295           BEGIN_CASE(JSOP_SUB)
03296             BINARY_OP(-);
03297           END_CASE(JSOP_SUB)
03298 
03299           BEGIN_CASE(JSOP_MUL)
03300             BINARY_OP(*);
03301           END_CASE(JSOP_MUL)
03302 
03303           BEGIN_CASE(JSOP_DIV)
03304             FETCH_NUMBER(cx, -1, d2);
03305             FETCH_NUMBER(cx, -2, d);
03306             sp--;
03307             if (d2 == 0) {
03308 #ifdef XP_WIN
03309                 /* XXX MSVC miscompiles such that (NaN == 0) */
03310                 if (JSDOUBLE_IS_NaN(d2))
03311                     rval = DOUBLE_TO_JSVAL(rt->jsNaN);
03312                 else
03313 #endif
03314                 if (d == 0 || JSDOUBLE_IS_NaN(d))
03315                     rval = DOUBLE_TO_JSVAL(rt->jsNaN);
03316                 else if ((JSDOUBLE_HI32(d) ^ JSDOUBLE_HI32(d2)) >> 31)
03317                     rval = DOUBLE_TO_JSVAL(rt->jsNegativeInfinity);
03318                 else
03319                     rval = DOUBLE_TO_JSVAL(rt->jsPositiveInfinity);
03320                 STORE_OPND(-1, rval);
03321             } else {
03322                 d /= d2;
03323                 STORE_NUMBER(cx, -1, d);
03324             }
03325           END_CASE(JSOP_DIV)
03326 
03327           BEGIN_CASE(JSOP_MOD)
03328             FETCH_NUMBER(cx, -1, d2);
03329             FETCH_NUMBER(cx, -2, d);
03330             sp--;
03331             if (d2 == 0) {
03332                 STORE_OPND(-1, DOUBLE_TO_JSVAL(rt->jsNaN));
03333             } else {
03334 #ifdef XP_WIN
03335               /* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
03336               if (!(JSDOUBLE_IS_FINITE(d) && JSDOUBLE_IS_INFINITE(d2)))
03337 #endif
03338                 d = fmod(d, d2);
03339                 STORE_NUMBER(cx, -1, d);
03340             }
03341           END_CASE(JSOP_MOD)
03342 
03343           BEGIN_CASE(JSOP_NOT)
03344             POP_BOOLEAN(cx, rval, cond);
03345             PUSH_OPND(BOOLEAN_TO_JSVAL(!cond));
03346           END_CASE(JSOP_NOT)
03347 
03348           BEGIN_CASE(JSOP_BITNOT)
03349             FETCH_INT(cx, -1, i);
03350             i = ~i;
03351             STORE_INT(cx, -1, i);
03352           END_CASE(JSOP_BITNOT)
03353 
03354           BEGIN_CASE(JSOP_NEG)
03355             /*
03356              * Optimize the case of an int-tagged operand by noting that
03357              * INT_FITS_IN_JSVAL(i) => INT_FITS_IN_JSVAL(-i) unless i is 0
03358              * when -i is the negative zero which is jsdouble.
03359              */
03360             rval = FETCH_OPND(-1);
03361             if (JSVAL_IS_INT(rval) && (i = JSVAL_TO_INT(rval)) != 0) {
03362                 i = -i;
03363                 JS_ASSERT(INT_FITS_IN_JSVAL(i));
03364                 rval = INT_TO_JSVAL(i);
03365             } else {
03366                 SAVE_SP_AND_PC(fp);
03367                 if (JSVAL_IS_DOUBLE(rval)) {
03368                     d = *JSVAL_TO_DOUBLE(rval);
03369                 } else {
03370                     ok = js_ValueToNumber(cx, rval, &d);
03371                     if (!ok)
03372                         goto out;
03373                 }
03374 #ifdef HPUX
03375                 /*
03376                  * Negation of a zero doesn't produce a negative
03377                  * zero on HPUX. Perform the operation by bit
03378                  * twiddling.
03379                  */
03380                 JSDOUBLE_HI32(d) ^= JSDOUBLE_HI32_SIGNBIT;
03381 #else
03382                 d = -d;
03383 #endif
03384                 ok = js_NewNumberValue(cx, d, &rval);
03385                 if (!ok)
03386                     goto out;
03387             }
03388             STORE_OPND(-1, rval);
03389           END_CASE(JSOP_NEG)
03390 
03391           BEGIN_CASE(JSOP_POS)
03392             rval = FETCH_OPND(-1);
03393             if (!JSVAL_IS_NUMBER(rval)) {
03394                 SAVE_SP_AND_PC(fp);
03395                 ok = js_ValueToNumber(cx, rval, &d);
03396                 if (!ok)
03397                     goto out;
03398                 ok = js_NewNumberValue(cx, d, &rval);
03399                 if (!ok)
03400                     goto out;
03401                 sp[-1] = rval;
03402             }
03403             sp[-1-depth] = (jsval)pc;
03404           END_CASE(JSOP_POS)
03405 
03406           BEGIN_CASE(JSOP_NEW)
03407             /* Get immediate argc and find the constructor function. */
03408             argc = GET_ARGC(pc);
03409 
03410           do_new:
03411             SAVE_SP_AND_PC(fp);
03412             vp = sp - (2 + argc);
03413             JS_ASSERT(vp >= fp->spbase);
03414 
03415             ok = js_InvokeConstructor(cx, vp, argc);
03416             if (!ok)
03417                 goto out;
03418             RESTORE_SP(fp);
03419             LOAD_BRANCH_CALLBACK(cx);
03420             LOAD_INTERRUPT_HANDLER(rt);
03421             obj = JSVAL_TO_OBJECT(*vp);
03422             len = js_CodeSpec[op].length;
03423             DO_NEXT_OP(len);
03424 
03425           BEGIN_CASE(JSOP_DELNAME)
03426             atom = GET_ATOM(cx, script, pc);
03427             id   = ATOM_TO_JSID(atom);
03428 
03429             SAVE_SP_AND_PC(fp);
03430             ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
03431             if (!ok)
03432                 goto out;
03433 
03434             /* ECMA says to return true if name is undefined or inherited. */
03435             rval = JSVAL_TRUE;
03436             if (prop) {
03437                 OBJ_DROP_PROPERTY(cx, obj2, prop);
03438                 ok = OBJ_DELETE_PROPERTY(cx, obj, id, &rval);
03439                 if (!ok)
03440                     goto out;
03441             }
03442             PUSH_OPND(rval);
03443           END_CASE(JSOP_DELNAME)
03444 
03445           BEGIN_CASE(JSOP_DELPROP)
03446             atom = GET_ATOM(cx, script, pc);
03447             id   = ATOM_TO_JSID(atom);
03448             PROPERTY_OP(-1, ok = OBJ_DELETE_PROPERTY(cx, obj, id, &rval));
03449             STORE_OPND(-1, rval);
03450           END_CASE(JSOP_DELPROP)
03451 
03452           BEGIN_CASE(JSOP_DELELEM)
03453             ELEMENT_OP(-1, ok = OBJ_DELETE_PROPERTY(cx, obj, id, &rval));
03454             sp--;
03455             STORE_OPND(-1, rval);
03456           END_CASE(JSOP_DELELEM)
03457 
03458           BEGIN_CASE(JSOP_TYPEOFEXPR)
03459           BEGIN_CASE(JSOP_TYPEOF)
03460             rval = FETCH_OPND(-1);
03461             SAVE_SP_AND_PC(fp);
03462             type = JS_TypeOfValue(cx, rval);
03463             atom = rt->atomState.typeAtoms[type];
03464             STORE_OPND(-1, ATOM_KEY(atom));
03465           END_CASE(JSOP_TYPEOF)
03466 
03467           BEGIN_CASE(JSOP_VOID)
03468             (void) POP_OPND();
03469             PUSH_OPND(JSVAL_VOID);
03470           END_CASE(JSOP_VOID)
03471 
03472           BEGIN_CASE(JSOP_INCNAME)
03473           BEGIN_CASE(JSOP_DECNAME)
03474           BEGIN_CASE(JSOP_NAMEINC)
03475           BEGIN_CASE(JSOP_NAMEDEC)
03476             atom = GET_ATOM(cx, script, pc);
03477             id   = ATOM_TO_JSID(atom);
03478 
03479             SAVE_SP_AND_PC(fp);
03480             ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
03481             if (!ok)
03482                 goto out;
03483             if (!prop)
03484                 goto atom_not_defined;
03485 
03486             OBJ_DROP_PROPERTY(cx, obj2, prop);
03487             lval = OBJECT_TO_JSVAL(obj);
03488             i = 0;
03489             goto do_incop;
03490 
03491           BEGIN_CASE(JSOP_INCPROP)
03492           BEGIN_CASE(JSOP_DECPROP)
03493           BEGIN_CASE(JSOP_PROPINC)
03494           BEGIN_CASE(JSOP_PROPDEC)
03495             atom = GET_ATOM(cx, script, pc);
03496             id   = ATOM_TO_JSID(atom);
03497             lval = FETCH_OPND(-1);
03498             i = -1;
03499             goto do_incop;
03500 
03501           BEGIN_CASE(JSOP_INCELEM)
03502           BEGIN_CASE(JSOP_DECELEM)
03503           BEGIN_CASE(JSOP_ELEMINC)
03504           BEGIN_CASE(JSOP_ELEMDEC)
03505             FETCH_ELEMENT_ID(-1, id);
03506             lval = FETCH_OPND(-2);
03507             i = -2;
03508 
03509           do_incop:
03510           {
03511             const JSCodeSpec *cs;
03512 
03513             VALUE_TO_OBJECT(cx, lval, obj);
03514             if (i < 0)
03515                 STORE_OPND(i, OBJECT_TO_JSVAL(obj));
03516             CHECK_ELEMENT_ID(obj, id);
03517 
03518             /* Preload for use in the if/else immediately below. */
03519             cs = &js_CodeSpec[op];
03520 
03521             SAVE_SP_AND_PC(fp);
03522             if (cs->format & JOF_ELEM)
03523                 JS_KEEP_ATOMS(rt);
03524 
03525             /* From this point the control must flow through finish_incop:. */
03526             CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval));
03527             if (!ok)
03528                 goto finish_incop;
03529 
03530             /* The expression result goes in rtmp, the updated value in rval. */
03531             if (JSVAL_IS_INT(rval) &&
03532                 rval != INT_TO_JSVAL(JSVAL_INT_MIN) &&
03533                 rval != INT_TO_JSVAL(JSVAL_INT_MAX)) {
03534                 if (cs->format & JOF_POST) {
03535                     rtmp = rval;
03536                     (cs->format & JOF_INC) ? (rval += 2) : (rval -= 2);
03537                 } else {
03538                     (cs->format & JOF_INC) ? (rval += 2) : (rval -= 2);
03539                     rtmp = rval;
03540                 }
03541             } else {
03542 /*
03543  * Initially, rval contains the value to increment or decrement, which is not
03544  * yet converted.  As above, the expression result goes in rtmp, the updated
03545  * value goes in rval.  Our caller must set vp to point at a GC-rooted jsval
03546  * in which we home rtmp, to protect it from GC in case the unconverted rval
03547  * is not a number.
03548  */
03549 #define NONINT_INCREMENT_OP_MIDDLE(error_goto)                                \
03550     JS_BEGIN_MACRO                                                            \
03551         VALUE_TO_NUMBER_GOTO(cx, rval, d, error_goto);                        \
03552         if (cs->format & JOF_POST) {                                          \
03553             rtmp = rval;                                                      \
03554             if (!JSVAL_IS_NUMBER(rtmp)) {                                     \
03555                 ok = js_NewNumberValue(cx, d, &rtmp);                         \
03556                 if (!ok)                                                      \
03557                     error_goto;                                               \
03558             }                                                                 \
03559             *vp = rtmp;                                                       \
03560             (cs->format & JOF_INC) ? d++ : d--;                               \
03561             ok = js_NewNumberValue(cx, d, &rval);                             \
03562         } else {                                                              \
03563             (cs->format & JOF_INC) ? ++d : --d;                               \
03564             ok = js_NewNumberValue(cx, d, &rval);                             \
03565             rtmp = rval;                                                      \
03566             *vp = rtmp;                                                       \
03567         }                                                                     \
03568         if (!ok)                                                              \
03569             error_goto;                                                       \
03570     JS_END_MACRO
03571 
03572                 /*
03573                  * We must push early to protect the increment or decrement
03574                  * result, if converted to a jsdouble from a non-number value,
03575                  * from GC nesting in the setter.
03576                  */
03577                 vp = sp;
03578                 PUSH(JSVAL_VOID);
03579                 SAVE_SP(fp);
03580                 --i;
03581                 NONINT_INCREMENT_OP_MIDDLE(goto finish_incop);
03582             }
03583             fp->flags |= JSFRAME_ASSIGNING;
03584             CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval));
03585             fp->flags &= ~JSFRAME_ASSIGNING;
03586 
03587           finish_incop:
03588             if (cs->format & JOF_ELEM)
03589                 JS_UNKEEP_ATOMS(rt);
03590             if (!ok)
03591                 goto out;
03592             sp += i;
03593             PUSH_OPND(rtmp);
03594             len = cs->length;
03595             DO_NEXT_OP(len);
03596           }
03597 
03598 /* NB: This macro doesn't use JS_BEGIN_MACRO/JS_END_MACRO around its body. */
03599 #define FAST_INCREMENT_OP(SLOT,COUNT,BASE,PRE,OPEQ,MINMAX)                    \
03600     slot = SLOT;                                                              \
03601     JS_ASSERT(slot < fp->fun->COUNT);                                         \
03602     vp = fp->BASE + slot;                                                     \
03603     rval = *vp;                                                               \
03604     if (!JSVAL_IS_INT(rval) || rval == INT_TO_JSVAL(JSVAL_INT_##MINMAX))      \
03605         goto do_nonint_fast_incop;                                            \
03606     PRE = rval;                                                               \
03607     rval OPEQ 2;                                                              \
03608     *vp = rval;                                                               \
03609     PUSH_OPND(PRE);                                                           \
03610     goto end_nonint_fast_incop
03611 
03612           BEGIN_CASE(JSOP_INCARG)
03613             FAST_INCREMENT_OP(GET_ARGNO(pc), nargs, argv, rval, +=, MAX);
03614           BEGIN_CASE(JSOP_DECARG)
03615             FAST_INCREMENT_OP(GET_ARGNO(pc), nargs, argv, rval, -=, MIN);
03616           BEGIN_CASE(JSOP_ARGINC)
03617             FAST_INCREMENT_OP(GET_ARGNO(pc), nargs, argv, rtmp, +=, MAX);
03618           BEGIN_CASE(JSOP_ARGDEC)
03619             FAST_INCREMENT_OP(GET_ARGNO(pc), nargs, argv, rtmp, -=, MIN);
03620 
03621           BEGIN_CASE(JSOP_INCVAR)
03622             FAST_INCREMENT_OP(GET_VARNO(pc), u.i.nvars, vars, rval, +=, MAX);
03623           BEGIN_CASE(JSOP_DECVAR)
03624             FAST_INCREMENT_OP(GET_VARNO(pc), u.i.nvars, vars, rval, -=, MIN);
03625           BEGIN_CASE(JSOP_VARINC)
03626             FAST_INCREMENT_OP(GET_VARNO(pc), u.i.nvars, vars, rtmp, +=, MAX);
03627           BEGIN_CASE(JSOP_VARDEC)
03628             FAST_INCREMENT_OP(GET_VARNO(pc), u.i.nvars, vars, rtmp, -=, MIN);
03629 
03630           end_nonint_fast_incop:
03631             len = JSOP_INCARG_LENGTH;   /* all fast incops are same length */
03632             DO_NEXT_OP(len);
03633 
03634 #undef FAST_INCREMENT_OP
03635 
03636           do_nonint_fast_incop:
03637           {
03638             const JSCodeSpec *cs = &js_CodeSpec[op];
03639 
03640             NONINT_INCREMENT_OP_MIDDLE(goto out);
03641             *vp = rval;
03642             PUSH_OPND(rtmp);
03643             len = cs->length;
03644             DO_NEXT_OP(len);
03645           }
03646 
03647 /* NB: This macro doesn't use JS_BEGIN_MACRO/JS_END_MACRO around its body. */
03648 #define FAST_GLOBAL_INCREMENT_OP(SLOWOP,PRE,OPEQ,MINMAX)                      \
03649     slot = GET_VARNO(pc);                                                     \
03650     JS_ASSERT(slot < fp->nvars);                                              \
03651     lval = fp->vars[slot];                                                    \
03652     if (JSVAL_IS_NULL(lval)) {                                                \
03653         op = SLOWOP;                                                          \
03654         DO_OP();                                                              \
03655     }                                                                         \
03656     slot = JSVAL_TO_INT(lval);                                                \
03657     obj = fp->varobj;                                                         \
03658     rval = OBJ_GET_SLOT(cx, obj, slot);                                       \
03659     if (!JSVAL_IS_INT(rval) || rval == INT_TO_JSVAL(JSVAL_INT_##MINMAX))      \
03660         goto do_nonint_fast_global_incop;                                     \
03661     PRE = rval;                                                               \
03662     rval OPEQ 2;                                                              \
03663     OBJ_SET_SLOT(cx, obj, slot, rval);                                        \
03664     PUSH_OPND(PRE);                                                           \
03665     goto end_nonint_fast_global_incop
03666 
03667           BEGIN_CASE(JSOP_INCGVAR)
03668             FAST_GLOBAL_INCREMENT_OP(JSOP_INCNAME, rval, +=, MAX);
03669           BEGIN_CASE(JSOP_DECGVAR)
03670             FAST_GLOBAL_INCREMENT_OP(JSOP_DECNAME, rval, -=, MIN);
03671           BEGIN_CASE(JSOP_GVARINC)
03672             FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEINC, rtmp, +=, MAX);
03673           BEGIN_CASE(JSOP_GVARDEC)
03674             FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEDEC, rtmp, -=, MIN);
03675 
03676           end_nonint_fast_global_incop:
03677             len = JSOP_INCGVAR_LENGTH;  /* all gvar incops are same length */
03678             JS_ASSERT(len == js_CodeSpec[op].length);
03679             DO_NEXT_OP(len);
03680 
03681 #undef FAST_GLOBAL_INCREMENT_OP
03682 
03683           do_nonint_fast_global_incop:
03684           {
03685             const JSCodeSpec *cs = &js_CodeSpec[op];
03686 
03687             vp = sp++;
03688             SAVE_SP(fp);
03689             NONINT_INCREMENT_OP_MIDDLE(goto out);
03690             OBJ_SET_SLOT(cx, obj, slot, rval);
03691             STORE_OPND(-1, rtmp);
03692             len = cs->length;
03693             DO_NEXT_OP(len);
03694           }
03695 
03696           BEGIN_CASE(JSOP_GETPROP)
03697           BEGIN_CASE(JSOP_GETXPROP)
03698             /* Get an immediate atom naming the property. */
03699             atom = GET_ATOM(cx, script, pc);
03700             lval = FETCH_OPND(-1);
03701             if (JSVAL_IS_STRING(lval) &&
03702                 atom == cx->runtime->atomState.lengthAtom) {
03703                 rval = INT_TO_JSVAL(JSSTRING_LENGTH(JSVAL_TO_STRING(lval)));
03704                 obj = NULL;
03705             } else {
03706                 id = ATOM_TO_JSID(atom);
03707                 VALUE_TO_OBJECT(cx, lval, obj);
03708                 STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
03709                 SAVE_SP_AND_PC(fp);
03710                 CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval));
03711                 if (!ok)
03712                     goto out;
03713             }
03714             STORE_OPND(-1, rval);
03715           END_CASE(JSOP_GETPROP)
03716 
03717           BEGIN_CASE(JSOP_SETPROP)
03718             /* Pop the right-hand side into rval for OBJ_SET_PROPERTY. */
03719             rval = FETCH_OPND(-1);
03720 
03721             /* Get an immediate atom naming the property. */
03722             atom = GET_ATOM(cx, script, pc);
03723             id   = ATOM_TO_JSID(atom);
03724             PROPERTY_OP(-2, CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval)));
03725             sp--;
03726             STORE_OPND(-1, rval);
03727             obj = NULL;
03728           END_CASE(JSOP_SETPROP)
03729 
03730           BEGIN_CASE(JSOP_GETELEM)
03731           BEGIN_CASE(JSOP_GETXELEM)
03732             ELEMENT_OP(-1, CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval)));
03733             sp--;
03734             STORE_OPND(-1, rval);
03735           END_CASE(JSOP_GETELEM)
03736 
03737           BEGIN_CASE(JSOP_SETELEM)
03738             rval = FETCH_OPND(-1);
03739             ELEMENT_OP(-2, CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval)));
03740             sp -= 2;
03741             STORE_OPND(-1, rval);
03742             obj = NULL;
03743           END_CASE(JSOP_SETELEM)
03744 
03745           BEGIN_CASE(JSOP_ENUMELEM)
03746             /* Funky: the value to set is under the [obj, id] pair. */
03747             FETCH_ELEMENT_ID(-1, id);
03748             FETCH_OBJECT(cx, -2, lval, obj);
03749             CHECK_ELEMENT_ID(obj, id);
03750             rval = FETCH_OPND(-3);
03751             SAVE_SP_AND_PC(fp);
03752             ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
03753             if (!ok)
03754                 goto out;
03755             sp -= 3;
03756           END_CASE(JSOP_ENUMELEM)
03757 
03758 /*
03759  * LAZY_ARGS_THISP allows the JSOP_ARGSUB bytecode to defer creation of the
03760  * arguments object until it is truly needed.  JSOP_ARGSUB optimizes away
03761  * arguments objects when the only uses of the 'arguments' parameter are to
03762  * fetch individual actual parameters.  But if such a use were then invoked,
03763  * e.g., arguments[i](), the 'this' parameter would and must bind to the
03764  * caller's arguments object.  So JSOP_ARGSUB sets obj to LAZY_ARGS_THISP.
03765  */
03766 #define LAZY_ARGS_THISP ((JSObject *) JSVAL_VOID)
03767 
03768           BEGIN_CASE(JSOP_PUSHOBJ)
03769             if (obj == LAZY_ARGS_THISP && !(obj = js_GetArgsObject(cx, fp))) {
03770                 ok = JS_FALSE;
03771                 goto out;
03772             }
03773             PUSH_OPND(OBJECT_TO_JSVAL(obj));
03774           END_CASE(JSOP_PUSHOBJ)
03775 
03776           BEGIN_CASE(JSOP_CALL)
03777           BEGIN_CASE(JSOP_EVAL)
03778             argc = GET_ARGC(pc);
03779             vp = sp - (argc + 2);
03780             lval = *vp;
03781             SAVE_SP_AND_PC(fp);
03782             if (VALUE_IS_FUNCTION(cx, lval) &&
03783                 (obj = JSVAL_TO_OBJECT(lval),
03784                  fun = (JSFunction *) JS_GetPrivate(cx, obj),
03785                  FUN_INTERPRETED(fun)))
03786           /* inline_call: */
03787             {
03788                 uintN nframeslots, nvars, nslots, missing;
03789                 JSArena *a;
03790                 jsuword avail, nbytes;
03791                 JSBool overflow;
03792                 void *newmark;
03793                 jsval *rvp;
03794                 JSInlineFrame *newifp;
03795                 JSInterpreterHook hook;
03796 
03797                 /* Restrict recursion of lightweight functions. */
03798                 if (inlineCallCount == MAX_INLINE_CALL_COUNT) {
03799                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
03800                                          JSMSG_OVER_RECURSED);
03801                     ok = JS_FALSE;
03802                     goto out;
03803                 }
03804 
03805                 /* Compute the total number of stack slots needed for fun. */
03806                 nframeslots = JS_HOWMANY(sizeof(JSInlineFrame), sizeof(jsval));
03807                 nvars = fun->u.i.nvars;
03808                 script = fun->u.i.script;
03809                 depth = (jsint) script->depth;
03810                 nslots = nframeslots + nvars + 2 * depth;
03811 
03812                 /* Allocate missing expected args adjacent to actual args. */
03813                 missing = (fun->nargs > argc) ? fun->nargs - argc : 0;
03814                 a = cx->stackPool.current;
03815                 avail = a->avail;
03816                 newmark = (void *) avail;
03817                 if (missing) {
03818                     newsp = sp + missing;
03819                     overflow = (jsuword) newsp > a->limit;
03820                     if (overflow)
03821                         nslots += 2 + argc + missing;
03822                     else if ((jsuword) newsp > avail)
03823                         avail = a->avail = (jsuword) newsp;
03824                 }
03825 #ifdef __GNUC__
03826                 else overflow = JS_FALSE;   /* suppress bogus gcc warnings */
03827 #endif
03828 
03829                 /* Allocate the inline frame with its vars and operand slots. */
03830                 newsp = (jsval *) avail;
03831                 nbytes = nslots * sizeof(jsval);
03832                 avail += nbytes;
03833                 if (avail <= a->limit) {
03834                     a->avail = avail;
03835                 } else {
03836                     JS_ARENA_ALLOCATE_CAST(newsp, jsval *, &cx->stackPool,
03837                                            nbytes);
03838                     if (!newsp) {
03839                         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
03840                                              JSMSG_STACK_OVERFLOW,
03841                                              (fp && fp->fun)
03842                                              ? JS_GetFunctionName(fp->fun)
03843                                              : "script");
03844                         goto bad_inline_call;
03845                     }
03846                 }
03847 
03848                 /* Move args if missing overflow arena a, push missing args. */
03849                 rvp = vp;
03850                 if (missing) {
03851                     if (overflow) {
03852                         memcpy(newsp, vp, (2 + argc) * sizeof(jsval));
03853                         vp = newsp;
03854                         sp = vp + 2 + argc;
03855                         newsp = sp + missing;
03856                     }
03857                     do {
03858                         PUSH(JSVAL_VOID);
03859                     } while (--missing != 0);
03860                 }
03861 
03862                 /* Claim space for the stack frame and initialize it. */
03863                 newifp = (JSInlineFrame *) newsp;
03864                 newsp += nframeslots;
03865                 newifp->frame.callobj = NULL;
03866                 newifp->frame.argsobj = NULL;
03867                 newifp->frame.varobj = NULL;
03868                 newifp->frame.callee = obj;
03869                 newifp->frame.script = script;
03870                 newifp->frame.fun = fun;
03871                 newifp->frame.argc = argc;
03872                 newifp->frame.argv = vp + 2;
03873                 newifp->frame.rval = JSVAL_VOID;
03874                 newifp->frame.nvars = nvars;
03875                 newifp->frame.vars = newsp;
03876                 newifp->frame.down = fp;
03877                 newifp->frame.annotation = NULL;
03878                 newifp->frame.scopeChain = parent = OBJ_GET_PARENT(cx, obj);
03879                 newifp->frame.sharpDepth = 0;
03880                 newifp->frame.sharpArray = NULL;
03881                 newifp->frame.flags = 0;
03882                 newifp->frame.dormantNext = NULL;
03883                 newifp->frame.xmlNamespace = NULL;
03884                 newifp->frame.blockChain = NULL;
03885                 newifp->rvp = rvp;
03886                 newifp->mark = newmark;
03887 
03888                 /* Compute the 'this' parameter now that argv is set. */
03889                 if (!JSVAL_IS_OBJECT(vp[1])) {
03890                     PRIMITIVE_TO_OBJECT(cx, vp[1], obj2);
03891                     if (!obj2)
03892                         goto bad_inline_call;
03893                     vp[1] = OBJECT_TO_JSVAL(obj2);
03894                 }
03895                 newifp->frame.thisp =
03896                     js_ComputeThis(cx,
03897                                    JSFUN_BOUND_METHOD_TEST(fun->flags)
03898                                    ? parent
03899                                    : JSVAL_TO_OBJECT(vp[1]),
03900                                    newifp->frame.argv);
03901                 if (!newifp->frame.thisp)
03902                     goto bad_inline_call;
03903 #ifdef DUMP_CALL_TABLE
03904                 LogCall(cx, *vp, argc, vp + 2);
03905 #endif
03906 
03907                 /* Push void to initialize local variables. */
03908                 sp = newsp;
03909                 while (nvars--)
03910                     PUSH(JSVAL_VOID);
03911                 sp += depth;
03912                 newifp->frame.spbase = sp;
03913                 SAVE_SP(&newifp->frame);
03914 
03915                 /* Call the debugger hook if present. */
03916                 hook = rt->callHook;
03917                 if (hook) {
03918                     newifp->frame.pc = NULL;
03919                     newifp->hookData = hook(cx, &newifp->frame, JS_TRUE, 0,
03920                                             rt->callHookData);
03921                     LOAD_INTERRUPT_HANDLER(rt);
03922                 } else {
03923                     newifp->hookData = NULL;
03924                 }
03925 
03926                 /* Scope with a call object parented by the callee's parent. */
03927                 if (JSFUN_HEAVYWEIGHT_TEST(fun->flags) &&
03928                     !js_GetCallObject(cx, &newifp->frame, parent)) {
03929                     goto bad_inline_call;
03930                 }
03931 
03932                 /* Switch to new version if currentVersion wasn't overridden. */
03933                 newifp->callerVersion = cx->version;
03934                 if (JS_LIKELY(cx->version == currentVersion)) {
03935                     currentVersion = script->version;
03936                     if (currentVersion != cx->version)
03937                         js_SetVersion(cx, currentVersion);
03938                 }
03939 
03940                 /* Push the frame and set interpreter registers. */
03941                 cx->fp = fp = &newifp->frame;
03942                 pc = script->code;
03943 #ifndef JS_THREADED_INTERP
03944                 endpc = pc + script->length;
03945 #endif
03946                 obj = NULL;
03947                 inlineCallCount++;
03948                 JS_RUNTIME_METER(rt, inlineCalls);
03949 
03950                 /* Load first opcode and dispatch it (safe since JSOP_STOP). */
03951                 op = *pc;
03952                 DO_OP();
03953 
03954               bad_inline_call:
03955                 RESTORE_SP(fp);
03956                 JS_ASSERT(fp->pc == pc);
03957                 script = fp->script;
03958                 depth = (jsint) script->depth;
03959                 js_FreeRawStack(cx, newmark);
03960                 ok = JS_FALSE;
03961                 goto out;
03962             }
03963 
03964             ok = js_Invoke(cx, argc, 0);
03965             RESTORE_SP(fp);
03966             LOAD_BRANCH_CALLBACK(cx);
03967             LOAD_INTERRUPT_HANDLER(rt);
03968             if (!ok)
03969                 goto out;
03970             JS_RUNTIME_METER(rt, nonInlineCalls);
03971 #if JS_HAS_LVALUE_RETURN
03972             if (cx->rval2set) {
03973                 /*
03974                  * Use the stack depth we didn't claim in our budget, but that
03975                  * we know is there on account of [fun, this] already having
03976                  * been pushed, at a minimum (if no args).  Those two slots
03977                  * have been popped and [rval] has been pushed, which leaves
03978                  * one more slot for rval2 before we might overflow.
03979                  *
03980                  * NB: rval2 must be the property identifier, and rval the
03981                  * object from which to get the property.  The pair form an
03982                  * ECMA "reference type", which can be used on the right- or
03983                  * left-hand side of assignment ops.  Note well: only native
03984                  * methods can return reference types.  See JSOP_SETCALL just
03985                  * below for the left-hand-side case.
03986                  */
03987                 PUSH_OPND(cx->rval2);
03988                 ELEMENT_OP(-1, ok = OBJ_GET_PROPERTY(cx, obj, id, &rval));
03989 
03990                 sp--;
03991                 STORE_OPND(-1, rval);
03992                 cx->rval2set = JS_FALSE;
03993             }
03994 #endif /* JS_HAS_LVALUE_RETURN */
03995             obj = NULL;
03996           END_CASE(JSOP_CALL)
03997 
03998 #if JS_HAS_LVALUE_RETURN
03999           BEGIN_CASE(JSOP_SETCALL)
04000             argc = GET_ARGC(pc);
04001             SAVE_SP_AND_PC(fp);
04002             ok = js_Invoke(cx, argc, 0);
04003             RESTORE_SP(fp);
04004             LOAD_BRANCH_CALLBACK(cx);
04005             LOAD_INTERRUPT_HANDLER(rt);
04006             if (!ok)
04007                 goto out;
04008             if (!cx->rval2set) {
04009                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
04010                                      JSMSG_BAD_LEFTSIDE_OF_ASS);
04011                 ok = JS_FALSE;
04012                 goto out;
04013             }
04014             PUSH_OPND(cx->rval2);
04015             cx->rval2set = JS_FALSE;
04016             obj = NULL;
04017           END_CASE(JSOP_SETCALL)
04018 #endif
04019 
04020           BEGIN_CASE(JSOP_NAME)
04021             atom = GET_ATOM(cx, script, pc);
04022             id   = ATOM_TO_JSID(atom);
04023 
04024             SAVE_SP_AND_PC(fp);
04025             ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
04026             if (!ok)
04027                 goto out;
04028             if (!prop) {
04029                 /* Kludge to allow (typeof foo == "undefined") tests. */
04030                 len = JSOP_NAME_LENGTH;
04031                 endpc = script->code + script->length;
04032                 for (pc2 = pc + len; pc2 < endpc; pc2++) {
04033                     op2 = (JSOp)*pc2;
04034                     if (op2 == JSOP_TYPEOF) {
04035                         PUSH_OPND(JSVAL_VOID);
04036                         DO_NEXT_OP(len);
04037                     }
04038                     if (op2 != JSOP_GROUP)
04039                         break;
04040                 }
04041                 goto atom_not_defined;
04042             }
04043 
04044             /* Take the slow path if prop was not found in a native object. */
04045             if (!OBJ_IS_NATIVE(obj) || !OBJ_IS_NATIVE(obj2)) {
04046                 OBJ_DROP_PROPERTY(cx, obj2, prop);
04047                 ok = OBJ_GET_PROPERTY(cx, obj, id, &rval);
04048                 if (!ok)
04049                     goto out;
04050             } else {
04051                 sprop = (JSScopeProperty *)prop;
04052                 NATIVE_GET(cx, obj, obj2, sprop, &rval);
04053                 OBJ_DROP_PROPERTY(cx, obj2, prop);
04054             }
04055             PUSH_OPND(rval);
04056           END_CASE(JSOP_NAME)
04057 
04058           BEGIN_CASE(JSOP_UINT16)
04059             i = (jsint) GET_ATOM_INDEX(pc);
04060             rval = INT_TO_JSVAL(i);
04061             PUSH_OPND(rval);
04062             obj = NULL;
04063           END_CASE(JSOP_UINT16)
04064 
04065           BEGIN_CASE(JSOP_UINT24)
04066             i = (jsint) GET_LITERAL_INDEX(pc);
04067             rval = INT_TO_JSVAL(i);
04068             PUSH_OPND(rval);
04069           END_CASE(JSOP_UINT24)
04070 
04071           BEGIN_CASE(JSOP_LITERAL)
04072             atomIndex = GET_LITERAL_INDEX(pc);
04073             atom = js_GetAtom(cx, &script->atomMap, atomIndex);
04074             PUSH_OPND(ATOM_KEY(atom));
04075             obj = NULL;
04076           END_CASE(JSOP_LITERAL)
04077 
04078           BEGIN_CASE(JSOP_FINDNAME)
04079             atomIndex = GET_LITERAL_INDEX(pc);
04080             atom = js_GetAtom(cx, &script->atomMap, atomIndex);
04081             SAVE_SP_AND_PC(fp);
04082             obj = js_FindIdentifierBase(cx, ATOM_TO_JSID(atom));
04083             if (!obj) {
04084                 ok = JS_FALSE;
04085                 goto out;
04086             }
04087             PUSH_OPND(OBJECT_TO_JSVAL(obj));
04088             PUSH_OPND(ATOM_KEY(atom));
04089           END_CASE(JSOP_FINDNAME)
04090 
04091           BEGIN_CASE(JSOP_LITOPX)
04092             /*
04093              * Load atomIndex, which is used by code at each do_JSOP_* label.
04094              *
04095              * Also set pc2 to point at the bytecode extended by this prefix
04096              * to have a leading 24 bit atomIndex, instead of the unextended
04097              * 16-bit atomIndex that normally comes after op.  This enables
04098              * JOF_INDEXCONST format ops (which have multiple immediates) to
04099              * collect their other immediate via GET_VARNO(pc2) or similar.
04100              *
04101              * Finally, load op and, if threading, adjust pc so that it will
04102              * be advanced properly at the end of op's case by DO_NEXT_OP.
04103              */
04104             atomIndex = GET_LITERAL_INDEX(pc);
04105             pc2 = pc + 1 + LITERAL_INDEX_LEN;
04106             op = *pc2;
04107             pc += JSOP_LITOPX_LENGTH - (1 + ATOM_INDEX_LEN);
04108 #ifndef JS_THREADED_INTERP
04109             len = js_CodeSpec[op].length;
04110 #endif
04111             switch (op) {
04112               case JSOP_ANONFUNOBJ:   goto do_JSOP_ANONFUNOBJ;
04113               case JSOP_BINDNAME:     goto do_JSOP_BINDNAME;
04114               case JSOP_CLOSURE:      goto do_JSOP_CLOSURE;
04115               case JSOP_DEFCONST:     goto do_JSOP_DEFCONST;
04116               case JSOP_DEFFUN:       goto do_JSOP_DEFFUN;
04117               case JSOP_DEFLOCALFUN:  goto do_JSOP_DEFLOCALFUN;
04118               case JSOP_DEFVAR:       goto do_JSOP_DEFVAR;
04119 #if JS_HAS_EXPORT_IMPORT
04120               case JSOP_EXPORTNAME:   goto do_JSOP_EXPORTNAME;
04121 #endif
04122 #if JS_HAS_XML_SUPPORT
04123               case JSOP_GETMETHOD:    goto do_JSOP_GETMETHOD;
04124               case JSOP_SETMETHOD:    goto do_JSOP_SETMETHOD;
04125 #endif
04126               case JSOP_NAMEDFUNOBJ:  goto do_JSOP_NAMEDFUNOBJ;
04127               case JSOP_NUMBER:       goto do_JSOP_NUMBER;
04128               case JSOP_OBJECT:       goto do_JSOP_OBJECT;
04129 #if JS_HAS_XML_SUPPORT
04130               case JSOP_QNAMECONST:   goto do_JSOP_QNAMECONST;
04131               case JSOP_QNAMEPART:    goto do_JSOP_QNAMEPART;
04132 #endif
04133               case JSOP_REGEXP:       goto do_JSOP_REGEXP;
04134               case JSOP_SETCONST:     goto do_JSOP_SETCONST;
04135               case JSOP_STRING:       goto do_JSOP_STRING;
04136 #if JS_HAS_XML_SUPPORT
04137               case JSOP_XMLCDATA:     goto do_JSOP_XMLCDATA;
04138               case JSOP_XMLCOMMENT:   goto do_JSOP_XMLCOMMENT;
04139               case JSOP_XMLOBJECT:    goto do_JSOP_XMLOBJECT;
04140               case JSOP_XMLPI:        goto do_JSOP_XMLPI;
04141 #endif
04142               case JSOP_ENTERBLOCK:   goto do_JSOP_ENTERBLOCK;
04143               default:                JS_ASSERT(0);
04144             }
04145             /* NOTREACHED */
04146 
04147           BEGIN_CASE(JSOP_NUMBER)
04148           BEGIN_CASE(JSOP_STRING)
04149           BEGIN_CASE(JSOP_OBJECT)
04150             atomIndex = GET_ATOM_INDEX(pc);
04151 
04152           do_JSOP_NUMBER:
04153           do_JSOP_STRING:
04154           do_JSOP_OBJECT:
04155             atom = js_GetAtom(cx, &script->atomMap, atomIndex);
04156             PUSH_OPND(ATOM_KEY(atom));
04157             obj = NULL;
04158           END_CASE(JSOP_NUMBER)
04159 
04160           BEGIN_LITOPX_CASE(JSOP_REGEXP, 0)
04161           {
04162             JSRegExp *re;
04163             JSObject *funobj;
04164 
04165             /*
04166              * Push a regexp object for the atom mapped by the bytecode at pc,
04167              * cloning the literal's regexp object if necessary, to simulate in
04168              * the pre-compile/execute-later case what ECMA specifies for the
04169              * compile-and-go case: that scanning each regexp literal creates
04170              * a single corresponding RegExp object.
04171              *
04172              * To support pre-compilation transparently, we must handle the
04173              * case where a regexp object literal is used in a different global
04174              * at execution time from the global with which it was scanned at
04175              * compile time.  We do this by re-wrapping the JSRegExp private
04176              * data struct with a cloned object having the right prototype and
04177              * parent, and having its own lastIndex property value storage.
04178              *
04179              * Unlike JSOP_DEFFUN and other prolog bytecodes that may clone
04180              * literal objects, we don't want to pay a script prolog execution
04181              * price for all regexp literals in a script (many may not be used
04182              * by a particular execution of that script, depending on control
04183              * flow), so we initialize lazily here.
04184              *
04185              * XXX This code is specific to regular expression objects.  If we
04186              * need a similar op for other kinds of object literals, we should
04187              * push cloning down under JSObjectOps and reuse code here.
04188              */
04189             JS_ASSERT(ATOM_IS_OBJECT(atom));
04190             obj = ATOM_TO_OBJECT(atom);
04191             JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass);
04192 
04193             re = (JSRegExp *) JS_GetPrivate(cx, obj);
04194             slot = re->cloneIndex;
04195             if (fp->fun) {
04196                 /*
04197                  * We're in function code, not global or eval code (in eval
04198                  * code, JSOP_REGEXP is never emitted).  The code generator
04199                  * recorded in fp->fun->nregexps the number of re->cloneIndex
04200                  * slots that it reserved in the cloned funobj.
04201                  */
04202                 funobj = JSVAL_TO_OBJECT(fp->argv[-2]);
04203                 slot += JSCLASS_RESERVED_SLOTS(&js_FunctionClass);
04204                 if (!JS_GetReservedSlot(cx, funobj, slot, &rval))
04205                     return JS_FALSE;
04206                 if (JSVAL_IS_VOID(rval))
04207                     rval = JSVAL_NULL;
04208             } else {
04209                 /*
04210                  * We're in global code.  The code generator already arranged
04211                  * via script->numGlobalVars to reserve a global variable slot
04212                  * at cloneIndex.  All global variable slots are initialized
04213                  * to null, not void, for faster testing in JSOP_*GVAR cases.
04214                  */
04215                 rval = fp->vars[slot];
04216 #ifdef __GNUC__
04217                 funobj = NULL;  /* suppress bogus gcc warnings */
04218 #endif
04219             }
04220 
04221             if (JSVAL_IS_NULL(rval)) {
04222                 /* Compute the current global object in obj2. */
04223                 obj2 = fp->scopeChain;
04224                 while ((parent = OBJ_GET_PARENT(cx, obj2)) != NULL)
04225                     obj2 = parent;
04226 
04227                 /*
04228                  * We must home sp here, because either js_CloneRegExpObject
04229                  * or JS_SetReservedSlot could nest a last-ditch GC.  We home
04230                  * pc as well, in case js_CloneRegExpObject has to lookup the
04231                  * "RegExp" class in the global object, which could entail a
04232                  * JSNewResolveOp call.
04233                  */
04234                 SAVE_SP_AND_PC(fp);
04235 
04236                 /*
04237                  * If obj's parent is not obj2, we must clone obj so that it
04238                  * has the right parent, and therefore, the right prototype.
04239                  *
04240                  * Yes, this means we assume that the correct RegExp.prototype
04241                  * to which regexp instances (including literals) delegate can
04242                  * be distinguished solely by the instance's parent, which was
04243                  * set to the parent of the RegExp constructor function object
04244                  * when the instance was created.  In other words,
04245                  *
04246                  *   (/x/.__parent__ == RegExp.__parent__) implies
04247                  *   (/x/.__proto__ == RegExp.prototype)
04248                  *
04249                  * (unless you assign a different object to RegExp.prototype
04250                  * at runtime, in which case, ECMA doesn't specify operation,
04251                  * and you get what you deserve).
04252                  *
04253                  * This same coupling between instance parent and constructor
04254                  * parent turns up everywhere (see jsobj.c's FindClassObject,
04255                  * js_ConstructObject, and js_NewObject).  It's fundamental to
04256                  * the design of the language when you consider multiple global
04257                  * objects and separate compilation and execution, even though
04258                  * it is not specified fully in ECMA.
04259                  */
04260                 if (OBJ_GET_PARENT(cx, obj) != obj2) {
04261                     obj = js_CloneRegExpObject(cx, obj, obj2);
04262                     if (!obj) {
04263                         ok = JS_FALSE;
04264                         goto out;
04265                     }
04266                 }
04267                 rval = OBJECT_TO_JSVAL(obj);
04268 
04269                 /* Store the regexp object value in its cloneIndex slot. */
04270                 if (fp->fun) {
04271                     if (!JS_SetReservedSlot(cx, funobj, slot, rval))
04272                         return JS_FALSE;
04273                 } else {
04274                     fp->vars[slot] = rval;
04275                 }
04276             }
04277 
04278             PUSH_OPND(rval);
04279             obj = NULL;
04280           }
04281           END_LITOPX_CASE(JSOP_REGEXP)
04282 
04283           BEGIN_CASE(JSOP_ZERO)
04284             PUSH_OPND(JSVAL_ZERO);
04285             obj = NULL;
04286           END_CASE(JSOP_ZERO)
04287 
04288           BEGIN_CASE(JSOP_ONE)
04289             PUSH_OPND(JSVAL_ONE);
04290             obj = NULL;
04291           END_CASE(JSOP_ONE)
04292 
04293           BEGIN_CASE(JSOP_NULL)
04294             PUSH_OPND(JSVAL_NULL);
04295             obj = NULL;
04296           END_CASE(JSOP_NULL)
04297 
04298           BEGIN_CASE(JSOP_THIS)
04299             obj = fp->thisp;
04300             clasp = OBJ_GET_CLASS(cx, obj);
04301             if (clasp->flags & JSCLASS_IS_EXTENDED) {
04302                 JSExtendedClass *xclasp;
04303 
04304                 xclasp = (JSExtendedClass *) clasp;
04305                 if (xclasp->outerObject) {
04306                     obj = xclasp->outerObject(cx, obj);
04307                     if (!obj) {
04308                         ok = JS_FALSE;
04309                         goto out;
04310                     }
04311                 }
04312             }
04313 
04314             PUSH_OPND(OBJECT_TO_JSVAL(obj));
04315             obj = NULL;
04316           END_CASE(JSOP_THIS)
04317 
04318           BEGIN_CASE(JSOP_FALSE)
04319             PUSH_OPND(JSVAL_FALSE);
04320             obj = NULL;
04321           END_CASE(JSOP_FALSE)
04322 
04323           BEGIN_CASE(JSOP_TRUE)
04324             PUSH_OPND(JSVAL_TRUE);
04325             obj = NULL;
04326           END_CASE(JSOP_TRUE)
04327 
04328           BEGIN_CASE(JSOP_TABLESWITCH)
04329             pc2 = pc;
04330             len = GET_JUMP_OFFSET(pc2);
04331 
04332             /*
04333              * ECMAv2+ forbids conversion of discriminant, so we will skip to
04334              * the default case if the discriminant isn't already an int jsval.
04335              * (This opcode is emitted only for dense jsint-domain switches.)
04336              */
04337             rval = POP_OPND();
04338             if (!JSVAL_IS_INT(rval))
04339                 DO_NEXT_OP(len);
04340             i = JSVAL_TO_INT(rval);
04341 
04342             pc2 += JUMP_OFFSET_LEN;
04343             low = GET_JUMP_OFFSET(pc2);
04344             pc2 += JUMP_OFFSET_LEN;
04345             high = GET_JUMP_OFFSET(pc2);
04346 
04347             i -= low;
04348             if ((jsuint)i < (jsuint)(high - low + 1)) {
04349                 pc2 += JUMP_OFFSET_LEN + JUMP_OFFSET_LEN * i;
04350                 off = (jsint) GET_JUMP_OFFSET(pc2);
04351                 if (off)
04352                     len = off;
04353             }
04354           END_VARLEN_CASE
04355 
04356           BEGIN_CASE(JSOP_LOOKUPSWITCH)
04357             lval = POP_OPND();
04358             pc2 = pc;
04359             len = GET_JUMP_OFFSET(pc2);
04360 
04361             if (!JSVAL_IS_NUMBER(lval) &&
04362                 !JSVAL_IS_STRING(lval) &&
04363                 !JSVAL_IS_BOOLEAN(lval)) {
04364                 DO_NEXT_OP(len);
04365             }
04366 
04367             pc2 += JUMP_OFFSET_LEN;
04368             npairs = (jsint) GET_ATOM_INDEX(pc2);
04369             pc2 += ATOM_INDEX_LEN;
04370 
04371 #define SEARCH_PAIRS(MATCH_CODE)                                              \
04372     while (npairs) {                                                          \
04373         atom = GET_ATOM(cx, script, pc2);                                     \
04374         rval = ATOM_KEY(atom);                                                \
04375         MATCH_CODE                                                            \
04376         if (match) {                                                          \
04377             pc2 += ATOM_INDEX_LEN;                                            \
04378             len = GET_JUMP_OFFSET(pc2);                                       \
04379             DO_NEXT_OP(len);                                                  \
04380         }                                                                     \
04381         pc2 += ATOM_INDEX_LEN + JUMP_OFFSET_LEN;                              \
04382         npairs--;                                                             \
04383     }
04384             if (JSVAL_IS_STRING(lval)) {
04385                 str  = JSVAL_TO_STRING(lval);
04386                 SEARCH_PAIRS(
04387                     match = (JSVAL_IS_STRING(rval) &&
04388                              ((str2 = JSVAL_TO_STRING(rval)) == str ||
04389                               js_EqualStrings(str2, str)));
04390                 )
04391             } else if (JSVAL_IS_DOUBLE(lval)) {
04392                 d = *JSVAL_TO_DOUBLE(lval);
04393                 SEARCH_PAIRS(
04394                     match = (JSVAL_IS_DOUBLE(rval) &&
04395                              *JSVAL_TO_DOUBLE(rval) == d);
04396                 )
04397             } else {
04398                 SEARCH_PAIRS(
04399                     match = (lval == rval);
04400                 )
04401             }
04402 #undef SEARCH_PAIRS
04403           END_VARLEN_CASE
04404 
04405           BEGIN_CASE(JSOP_TABLESWITCHX)
04406             pc2 = pc;
04407             len = GET_JUMPX_OFFSET(pc2);
04408 
04409             /*
04410              * ECMAv2+ forbids conversion of discriminant, so we will skip to
04411              * the default case if the discriminant isn't already an int jsval.
04412              * (This opcode is emitted only for dense jsint-domain switches.)
04413              */
04414             rval = POP_OPND();
04415             if (!JSVAL_IS_INT(rval))
04416                 DO_NEXT_OP(len);
04417             i = JSVAL_TO_INT(rval);
04418 
04419             pc2 += JUMPX_OFFSET_LEN;
04420             low = GET_JUMP_OFFSET(pc2);
04421             pc2 += JUMP_OFFSET_LEN;
04422             high = GET_JUMP_OFFSET(pc2);
04423 
04424             i -= low;
04425             if ((jsuint)i < (jsuint)(high - low + 1)) {
04426                 pc2 += JUMP_OFFSET_LEN + JUMPX_OFFSET_LEN * i;
04427                 off = (jsint) GET_JUMPX_OFFSET(pc2);
04428                 if (off)
04429                     len = off;
04430             }
04431           END_VARLEN_CASE
04432 
04433           BEGIN_CASE(JSOP_LOOKUPSWITCHX)
04434             lval = POP_OPND();
04435             pc2 = pc;
04436             len = GET_JUMPX_OFFSET(pc2);
04437 
04438             if (!JSVAL_IS_NUMBER(lval) &&
04439                 !JSVAL_IS_STRING(lval) &&
04440                 !JSVAL_IS_BOOLEAN(lval)) {
04441                 DO_NEXT_OP(len);
04442             }
04443 
04444             pc2 += JUMPX_OFFSET_LEN;
04445             npairs = (jsint) GET_ATOM_INDEX(pc2);
04446             pc2 += ATOM_INDEX_LEN;
04447 
04448 #define SEARCH_EXTENDED_PAIRS(MATCH_CODE)                                     \
04449     while (npairs) {                                                          \
04450         atom = GET_ATOM(cx, script, pc2);                                     \
04451         rval = ATOM_KEY(atom);                                                \
04452         MATCH_CODE                                                            \
04453         if (match) {                                                          \
04454             pc2 += ATOM_INDEX_LEN;                                            \
04455             len = GET_JUMPX_OFFSET(pc2);                                      \
04456             DO_NEXT_OP(len);                                                  \
04457         }                                                                     \
04458         pc2 += ATOM_INDEX_LEN + JUMPX_OFFSET_LEN;                             \
04459         npairs--;                                                             \
04460     }
04461             if (JSVAL_IS_STRING(lval)) {
04462                 str  = JSVAL_TO_STRING(lval);
04463                 SEARCH_EXTENDED_PAIRS(
04464                     match = (JSVAL_IS_STRING(rval) &&
04465                              ((str2 = JSVAL_TO_STRING(rval)) == str ||
04466                               js_EqualStrings(str2, str)));
04467                 )
04468             } else if (JSVAL_IS_DOUBLE(lval)) {
04469                 d = *JSVAL_TO_DOUBLE(lval);
04470                 SEARCH_EXTENDED_PAIRS(
04471                     match = (JSVAL_IS_DOUBLE(rval) &&
04472                              *JSVAL_TO_DOUBLE(rval) == d);
04473                 )
04474             } else {
04475                 SEARCH_EXTENDED_PAIRS(
04476                     match = (lval == rval);
04477                 )
04478             }
04479 #undef SEARCH_EXTENDED_PAIRS
04480           END_VARLEN_CASE
04481 
04482           EMPTY_CASE(JSOP_CONDSWITCH)
04483 
04484 #if JS_HAS_EXPORT_IMPORT
04485           BEGIN_CASE(JSOP_EXPORTALL)
04486             obj = fp->varobj;
04487             SAVE_SP_AND_PC(fp);
04488             ida = JS_Enumerate(cx, obj);
04489             if (!ida) {
04490                 ok = JS_FALSE;
04491             } else {
04492                 for (i = 0, j = ida->length; i < j; i++) {
04493                     id = ida->vector[i];
04494                     ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
04495                     if (!ok)
04496                         break;
04497                     if (!prop)
04498                         continue;
04499                     ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, &attrs);
04500                     if (ok) {
04501                         attrs |= JSPROP_EXPORTED;
04502                         ok = OBJ_SET_ATTRIBUTES(cx, obj, id, prop, &attrs);
04503                     }
04504                     OBJ_DROP_PROPERTY(cx, obj2, prop);
04505                     if (!ok)
04506                         break;
04507                 }
04508                 JS_DestroyIdArray(cx, ida);
04509             }
04510           END_CASE(JSOP_EXPORTALL)
04511 
04512           BEGIN_LITOPX_CASE(JSOP_EXPORTNAME, 0)
04513             id   = ATOM_TO_JSID(atom);
04514             obj  = fp->varobj;
04515             SAVE_SP_AND_PC(fp);
04516             ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
04517             if (!ok)
04518                 goto out;
04519             if (!prop) {
04520                 ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, NULL, NULL,
04521                                          JSPROP_EXPORTED, NULL);
04522             } else {
04523                 ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, &attrs);
04524                 if (ok) {
04525                     attrs |= JSPROP_EXPORTED;
04526                     ok = OBJ_SET_ATTRIBUTES(cx, obj, id, prop, &attrs);
04527                 }
04528                 OBJ_DROP_PROPERTY(cx, obj2, prop);
04529             }
04530             if (!ok)
04531                 goto out;
04532           END_LITOPX_CASE(JSOP_EXPORTNAME)
04533 
04534           BEGIN_CASE(JSOP_IMPORTALL)
04535             id = (jsid) JSVAL_VOID;
04536             PROPERTY_OP(-1, ok = ImportProperty(cx, obj, id));
04537             sp--;
04538           END_CASE(JSOP_IMPORTALL)
04539 
04540           BEGIN_CASE(JSOP_IMPORTPROP)
04541             /* Get an immediate atom naming the property. */
04542             atom = GET_ATOM(cx, script, pc);
04543             id   = ATOM_TO_JSID(atom);
04544             PROPERTY_OP(-1, ok = ImportProperty(cx, obj, id));
04545             sp--;
04546           END_CASE(JSOP_IMPORTPROP)
04547 
04548           BEGIN_CASE(JSOP_IMPORTELEM)
04549             ELEMENT_OP(-1, ok = ImportProperty(cx, obj, id));
04550             sp -= 2;
04551           END_CASE(JSOP_IMPORTELEM)
04552 #endif /* JS_HAS_EXPORT_IMPORT */
04553 
04554           BEGIN_CASE(JSOP_TRAP)
04555             SAVE_SP_AND_PC(fp);
04556             switch (JS_HandleTrap(cx, script, pc, &rval)) {
04557               case JSTRAP_ERROR:
04558                 ok = JS_FALSE;
04559                 goto out;
04560               case JSTRAP_CONTINUE:
04561                 JS_ASSERT(JSVAL_IS_INT(rval));
04562                 op = (JSOp) JSVAL_TO_INT(rval);
04563                 JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT);
04564                 LOAD_INTERRUPT_HANDLER(rt);
04565                 DO_OP();
04566               case JSTRAP_RETURN:
04567                 fp->rval = rval;
04568                 goto out;
04569               case JSTRAP_THROW:
04570                 cx->throwing = JS_TRUE;
04571                 cx->exception = rval;
04572                 ok = JS_FALSE;
04573                 goto out;
04574               default:;
04575             }
04576             LOAD_INTERRUPT_HANDLER(rt);
04577           END_CASE(JSOP_TRAP)
04578 
04579           BEGIN_CASE(JSOP_ARGUMENTS)
04580             SAVE_SP_AND_PC(fp);
04581             ok = js_GetArgsValue(cx, fp, &rval);
04582             if (!ok)
04583                 goto out;
04584             PUSH_OPND(rval);
04585             obj = NULL;
04586           END_CASE(JSOP_ARGUMENTS)
04587 
04588           BEGIN_CASE(JSOP_ARGSUB)
04589             id = INT_TO_JSID(GET_ARGNO(pc));
04590             SAVE_SP_AND_PC(fp);
04591             ok = js_GetArgsProperty(cx, fp, id, &obj, &rval);
04592             if (!ok)
04593                 goto out;
04594             if (!obj) {
04595                 /*
04596                  * If arguments was not overridden by eval('arguments = ...'),
04597                  * set obj to the magic cookie respected by JSOP_PUSHOBJ, just
04598                  * in case this bytecode is part of an 'arguments[i](j, k)' or
04599                  * similar such invocation sequence, where the function that
04600                  * is invoked expects its 'this' parameter to be the caller's
04601                  * arguments object.
04602                  */
04603                 obj = LAZY_ARGS_THISP;
04604             }
04605             PUSH_OPND(rval);
04606           END_CASE(JSOP_ARGSUB)
04607 
04608 #undef LAZY_ARGS_THISP
04609 
04610           BEGIN_CASE(JSOP_ARGCNT)
04611             id = ATOM_TO_JSID(rt->atomState.lengthAtom);
04612             SAVE_SP_AND_PC(fp);
04613             ok = js_GetArgsProperty(cx, fp, id, &obj, &rval);
04614             if (!ok)
04615                 goto out;
04616             PUSH_OPND(rval);
04617           END_CASE(JSOP_ARGCNT)
04618 
04619           BEGIN_CASE(JSOP_GETARG)
04620             slot = GET_ARGNO(pc);
04621             JS_ASSERT(slot < fp->fun->nargs);
04622             PUSH_OPND(fp->argv[slot]);
04623             obj = NULL;
04624           END_CASE(JSOP_GETARG)
04625 
04626           BEGIN_CASE(JSOP_SETARG)
04627             slot = GET_ARGNO(pc);
04628             JS_ASSERT(slot < fp->fun->nargs);
04629             vp = &fp->argv[slot];
04630             GC_POKE(cx, *vp);
04631             *vp = FETCH_OPND(-1);
04632             obj = NULL;
04633           END_CASE(JSOP_SETARG)
04634 
04635           BEGIN_CASE(JSOP_GETVAR)
04636             slot = GET_VARNO(pc);
04637             JS_ASSERT(slot < fp->fun->u.i.nvars);
04638             PUSH_OPND(fp->vars[slot]);
04639             obj = NULL;
04640           END_CASE(JSOP_GETVAR)
04641 
04642           BEGIN_CASE(JSOP_SETVAR)
04643             slot = GET_VARNO(pc);
04644             JS_ASSERT(slot < fp->fun->u.i.nvars);
04645             vp = &fp->vars[slot];
04646             GC_POKE(cx, *vp);
04647             *vp = FETCH_OPND(-1);
04648             obj = NULL;
04649           END_CASE(JSOP_SETVAR)
04650 
04651           BEGIN_CASE(JSOP_GETGVAR)
04652             slot = GET_VARNO(pc);
04653             JS_ASSERT(slot < fp->nvars);
04654             lval = fp->vars[slot];
04655             if (JSVAL_IS_NULL(lval)) {
04656                 op = JSOP_NAME;
04657                 DO_OP();
04658             }
04659             slot = JSVAL_TO_INT(lval);
04660             obj = fp->varobj;
04661             rval = OBJ_GET_SLOT(cx, obj, slot);
04662             PUSH_OPND(rval);
04663           END_CASE(JSOP_GETGVAR)
04664 
04665           BEGIN_CASE(JSOP_SETGVAR)
04666             slot = GET_VARNO(pc);
04667             JS_ASSERT(slot < fp->nvars);
04668             rval = FETCH_OPND(-1);
04669             lval = fp->vars[slot];
04670             obj = fp->varobj;
04671             if (JSVAL_IS_NULL(lval)) {
04672                 /*
04673                  * Inline-clone and specialize JSOP_SETNAME code here because
04674                  * JSOP_SETGVAR has arity 1: [rval], not arity 2: [obj, rval]
04675                  * as JSOP_SETNAME does, where [obj] is due to JSOP_BINDNAME.
04676                  */
04677                 atom = GET_ATOM(cx, script, pc);
04678                 id = ATOM_TO_JSID(atom);
04679                 SAVE_SP_AND_PC(fp);
04680                 CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval));
04681                 if (!ok)
04682                     goto out;
04683                 STORE_OPND(-1, rval);
04684             } else {
04685                 slot = JSVAL_TO_INT(lval);
04686                 GC_POKE(cx, obj->slots[slot]);
04687                 OBJ_SET_SLOT(cx, obj, slot, rval);
04688             }
04689             obj = NULL;
04690           END_CASE(JSOP_SETGVAR)
04691 
04692           BEGIN_CASE(JSOP_DEFCONST)
04693           BEGIN_CASE(JSOP_DEFVAR)
04694             atomIndex = GET_ATOM_INDEX(pc);
04695 
04696           do_JSOP_DEFCONST:
04697           do_JSOP_DEFVAR:
04698             atom = js_GetAtom(cx, &script->atomMap, atomIndex);
04699             obj = fp->varobj;
04700             attrs = JSPROP_ENUMERATE;
04701             if (!(fp->flags & JSFRAME_EVAL))
04702                 attrs |= JSPROP_PERMANENT;
04703             if (op == JSOP_DEFCONST)
04704                 attrs |= JSPROP_READONLY;
04705 
04706             /* Lookup id in order to check for redeclaration problems. */
04707             id = ATOM_TO_JSID(atom);
04708             SAVE_SP_AND_PC(fp);
04709             ok = js_CheckRedeclaration(cx, obj, id, attrs, &obj2, &prop);
04710             if (!ok)
04711                 goto out;
04712 
04713             /* Bind a variable only if it's not yet defined. */
04714             if (!prop) {
04715                 ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, NULL, NULL,
04716                                          attrs, &prop);
04717                 if (!ok)
04718                     goto out;
04719                 JS_ASSERT(prop);
04720                 obj2 = obj;
04721             }
04722 
04723             /*
04724              * Try to optimize a property we either just created, or found
04725              * directly in the global object, that is permanent, has a slot,
04726              * and has stub getter and setter, into a "fast global" accessed
04727              * by the JSOP_*GVAR opcodes.
04728              */
04729             if (atomIndex < script->numGlobalVars &&
04730                 (attrs & JSPROP_PERMANENT) &&
04731                 obj2 == obj &&
04732                 OBJ_IS_NATIVE(obj)) {
04733                 sprop = (JSScopeProperty *) prop;
04734                 if (SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj)) &&
04735                     SPROP_HAS_STUB_GETTER(sprop) &&
04736                     SPROP_HAS_STUB_SETTER(sprop)) {
04737                     /*
04738                      * Fast globals use fp->vars to map the global name's
04739                      * atomIndex to the permanent fp->varobj slot number,
04740                      * tagged as a jsval.  The atomIndex for the global's
04741                      * name literal is identical to its fp->vars index.
04742                      */
04743                     fp->vars[atomIndex] = INT_TO_JSVAL(sprop->slot);
04744                 }
04745             }
04746 
04747             OBJ_DROP_PROPERTY(cx, obj2, prop);
04748           END_CASE(JSOP_DEFVAR)
04749 
04750           BEGIN_LITOPX_CASE(JSOP_DEFFUN, 0)
04751             obj = ATOM_TO_OBJECT(atom);
04752             fun = (JSFunction *) JS_GetPrivate(cx, obj);
04753             id = ATOM_TO_JSID(fun->atom);
04754 
04755             /*
04756              * We must be at top-level (either outermost block that forms a
04757              * function's body, or a global) scope, not inside an expression
04758              * (JSOP_{ANON,NAMED}FUNOBJ) or compound statement (JSOP_CLOSURE)
04759              * in the same compilation unit (ECMA Program).
04760              *
04761              * However, we could be in a Program being eval'd from inside a
04762              * with statement, so we need to distinguish scope chain head from
04763              * variables object.  Hence the obj2 vs. parent distinction below.
04764              * First we make sure the function object we're defining has the
04765              * right scope chain.  Then we define its name in fp->varobj.
04766              *
04767              * If static link is not current scope, clone fun's object to link
04768              * to the current scope via parent.  This clause exists to enable
04769              * sharing of compiled functions among multiple equivalent scopes,
04770              * splitting the cost of compilation evenly among the scopes and
04771              * amortizing it over a number of executions.  Examples include XUL
04772              * scripts and event handlers shared among Mozilla chrome windows,
04773              * and server-side JS user-defined functions shared among requests.
04774              *
04775              * NB: The Script object exposes compile and exec in the language,
04776              * such that this clause introduces an incompatible change from old
04777              * JS versions that supported Script.  Such a JS version supported
04778              * executing a script that defined and called functions scoped by
04779              * the compile-time static link, not by the exec-time scope chain.
04780              *
04781              * We sacrifice compatibility, breaking such scripts, in order to
04782              * promote compile-cost sharing and amortizing, and because Script
04783              * is not and will not be standardized.
04784              */
04785             JS_ASSERT(!fp->blockChain);
04786             obj2 = fp->scopeChain;
04787             if (OBJ_GET_PARENT(cx, obj) != obj2) {
04788                 obj = js_CloneFunctionObject(cx, obj, obj2);
04789                 if (!obj) {
04790                     ok = JS_FALSE;
04791                     goto out;
04792                 }
04793             }
04794 
04795             /*
04796              * Protect obj from any GC hiding below OBJ_DEFINE_PROPERTY.  All
04797              * paths from here must flow through the "Restore fp->scopeChain"
04798              * code below the OBJ_DEFINE_PROPERTY call.
04799              */
04800             fp->scopeChain = obj;
04801             rval = OBJECT_TO_JSVAL(obj);
04802 
04803             /*
04804              * ECMA requires functions defined when entering Global code to be
04805              * permanent, and functions defined when entering Eval code to be
04806              * impermanent.
04807              */
04808             attrs = JSPROP_ENUMERATE;
04809             if (!(fp->flags & JSFRAME_EVAL))
04810                 attrs |= JSPROP_PERMANENT;
04811 
04812             /*
04813              * Load function flags that are also property attributes.  Getters
04814              * and setters do not need a slot, their value is stored elsewhere
04815              * in the property itself, not in obj->slots.
04816              */
04817             flags = JSFUN_GSFLAG2ATTR(fun->flags);
04818             if (flags) {
04819                 attrs |= flags | JSPROP_SHARED;
04820                 rval = JSVAL_VOID;
04821             }
04822 
04823             /*
04824              * Check for a const property of the same name -- or any kind
04825              * of property if executing with the strict option.  We check
04826              * here at runtime as well as at compile-time, to handle eval
04827              * as well as multiple HTML script tags.
04828              */
04829             parent = fp->varobj;
04830             SAVE_SP_AND_PC(fp);
04831             ok = js_CheckRedeclaration(cx, parent, id, attrs, NULL, NULL);
04832             if (ok) {
04833                 ok = OBJ_DEFINE_PROPERTY(cx, parent, id, rval,
04834                                          (flags & JSPROP_GETTER)
04835                                          ? JS_EXTENSION (JSPropertyOp) obj
04836                                          : NULL,
04837                                          (flags & JSPROP_SETTER)
04838                                          ? JS_EXTENSION (JSPropertyOp) obj
04839                                          : NULL,
04840                                          attrs,
04841                                          &prop);
04842             }
04843 
04844             /* Restore fp->scopeChain now that obj is defined in fp->varobj. */
04845             fp->scopeChain = obj2;
04846             if (!ok)
04847                 goto out;
04848 
04849 #if 0
04850             if (attrs == (JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
04851                 script->numGlobalVars) {
04852                 /*
04853                  * As with JSOP_DEFVAR and JSOP_DEFCONST (above), fast globals
04854                  * use fp->vars to map the global function name's atomIndex to
04855                  * its permanent fp->varobj slot number, tagged as a jsval.
04856                  */
04857                 sprop = (JSScopeProperty *) prop;
04858                 fp->vars[atomIndex] = INT_TO_JSVAL(sprop->slot);
04859             }
04860 #endif
04861             OBJ_DROP_PROPERTY(cx, parent, prop);
04862           END_LITOPX_CASE(JSOP_DEFFUN)
04863 
04864           BEGIN_LITOPX_CASE(JSOP_DEFLOCALFUN, VARNO_LEN)
04865             /*
04866              * Define a local function (i.e., one nested at the top level of
04867              * another function), parented by the current scope chain, and
04868              * stored in a local variable slot that the compiler allocated.
04869              * This is an optimization over JSOP_DEFFUN that avoids requiring
04870              * a call object for the outer function's activation.
04871              */
04872             slot = GET_VARNO(pc2);
04873             obj = ATOM_TO_OBJECT(atom);
04874 
04875             JS_ASSERT(!fp->blockChain);
04876             if (!(fp->flags & JSFRAME_POP_BLOCKS)) {
04877                 /*
04878                  * If the compiler-created function object (obj) is scoped by a
04879                  * let-induced body block, temporarily update fp->blockChain so
04880                  * that js_GetScopeChain will clone the block into the runtime
04881                  * scope needed to parent the function object's clone.
04882                  */
04883                 parent = OBJ_GET_PARENT(cx, obj);
04884                 if (OBJ_GET_CLASS(cx, parent) == &js_BlockClass)
04885                     fp->blockChain = parent;
04886                 parent = js_GetScopeChain(cx, fp);
04887             } else {
04888                 /*
04889                  * We have already emulated JSOP_ENTERBLOCK for the enclosing
04890                  * body block, for a prior JSOP_DEFLOCALFUN in the prolog,  so
04891                  * we just load fp->scopeChain into parent.
04892                  *
04893                  * In typical execution scenarios, the prolog bytecodes that
04894                  * include this JSOP_DEFLOCALFUN run, then come main bytecodes
04895                  * including JSOP_ENTERBLOCK for the outermost (body) block.
04896                  * JSOP_ENTERBLOCK will detect that it need not do anything if
04897                  * the body block was entered above due to a local function.
04898                  * Finally the matching JSOP_LEAVEBLOCK runs.
04899                  *
04900                  * If the matching JSOP_LEAVEBLOCK for the body block does not
04901                  * run for some reason, the body block will be properly "put"
04902                  * (via js_PutBlockObject) by the PutBlockObjects call at the
04903                  * bottom of js_Interpret.
04904                  */
04905                 parent = fp->scopeChain;
04906                 JS_ASSERT(OBJ_GET_CLASS(cx, parent) == &js_BlockClass);
04907                 JS_ASSERT(OBJ_GET_PROTO(cx, parent) == OBJ_GET_PARENT(cx, obj));
04908                 JS_ASSERT(OBJ_GET_CLASS(cx, OBJ_GET_PARENT(cx, parent))
04909                           == &js_CallClass);
04910             }
04911 
04912             /* If re-parenting, store a clone of the function object. */
04913             if (OBJ_GET_PARENT(cx, obj) != parent) {
04914                 SAVE_SP_AND_PC(fp);
04915                 obj = js_CloneFunctionObject(cx, obj, parent);
04916                 if (!obj) {
04917                     ok = JS_FALSE;
04918                     goto out;
04919                 }
04920             }
04921             fp->vars[slot] = OBJECT_TO_JSVAL(obj);
04922           END_LITOPX_CASE(JSOP_DEFLOCALFUN)
04923 
04924           BEGIN_LITOPX_CASE(JSOP_ANONFUNOBJ, 0)
04925             /* Push the specified function object literal. */
04926             obj = ATOM_TO_OBJECT(atom);
04927 
04928             /* If re-parenting, push a clone of the function object. */
04929             SAVE_SP_AND_PC(fp);
04930             parent = js_GetScopeChain(cx, fp);
04931             if (!parent) {
04932                 ok = JS_FALSE;
04933                 goto out;
04934             }
04935             if (OBJ_GET_PARENT(cx, obj) != parent) {
04936                 obj = js_CloneFunctionObject(cx, obj, parent);
04937                 if (!obj) {
04938                     ok = JS_FALSE;
04939                     goto out;
04940                 }
04941             }
04942             PUSH_OPND(OBJECT_TO_JSVAL(obj));
04943             obj = NULL;
04944           END_LITOPX_CASE(JSOP_ANONFUNOBJ)
04945 
04946           BEGIN_LITOPX_CASE(JSOP_NAMEDFUNOBJ, 0)
04947             /* ECMA ed. 3 FunctionExpression: function Identifier [etc.]. */
04948             rval = ATOM_KEY(atom);
04949             JS_ASSERT(VALUE_IS_FUNCTION(cx, rval));
04950 
04951             /*
04952              * 1. Create a new object as if by the expression new Object().
04953              * 2. Add Result(1) to the front of the scope chain.
04954              *
04955              * Step 2 is achieved by making the new object's parent be the
04956              * current scope chain, and then making the new object the parent
04957              * of the Function object clone.
04958              */
04959             SAVE_SP_AND_PC(fp);
04960             obj2 = js_GetScopeChain(cx, fp);
04961             if (!obj2) {
04962                 ok = JS_FALSE;
04963                 goto out;
04964             }
04965             parent = js_NewObject(cx, &js_ObjectClass, NULL, obj2);
04966             if (!parent) {
04967                 ok = JS_FALSE;
04968                 goto out;
04969             }
04970 
04971             /*
04972              * 3. Create a new Function object as specified in section 13.2
04973              * with [parameters and body specified by the function expression
04974              * that was parsed by the compiler into a Function object, and
04975              * saved in the script's atom map].
04976              *
04977              * Protect parent from GC after js_CloneFunctionObject calls into
04978              * js_NewObject, which displaces the newborn object root in cx by
04979              * allocating the clone, then runs a last-ditch GC while trying
04980              * to allocate the clone's slots vector.  Another, multi-threaded
04981              * path: js_CloneFunctionObject => js_NewObject => OBJ_GET_CLASS
04982              * which may suspend the current request in ClaimScope, with the
04983              * newborn displaced as in the first scenario.
04984              */
04985             fp->scopeChain = parent;
04986             obj = js_CloneFunctionObject(cx, JSVAL_TO_OBJECT(rval), parent);
04987             if (!obj) {
04988                 ok = JS_FALSE;
04989                 goto out;
04990             }
04991 
04992             /*
04993              * Protect obj from any GC hiding below OBJ_DEFINE_PROPERTY.  All
04994              * paths from here must flow through the "Restore fp->scopeChain"
04995              * code below the OBJ_DEFINE_PROPERTY call.
04996              */
04997             fp->scopeChain = obj;
04998             rval = OBJECT_TO_JSVAL(obj);
04999 
05000             /*
05001              * 4. Create a property in the object Result(1).  The property's
05002              * name is [fun->atom, the identifier parsed by the compiler],
05003              * value is Result(3), and attributes are { DontDelete, ReadOnly }.
05004              */
05005             fun = (JSFunction *) JS_GetPrivate(cx, obj);
05006             attrs = JSFUN_GSFLAG2ATTR(fun->flags);
05007             if (attrs) {
05008                 attrs |= JSPROP_SHARED;
05009                 rval = JSVAL_VOID;
05010             }
05011             ok = OBJ_DEFINE_PROPERTY(cx, parent, ATOM_TO_JSID(fun->atom), rval,
05012                                      (attrs & JSPROP_GETTER)
05013                                      ? JS_EXTENSION (JSPropertyOp) obj
05014                                      : NULL,
05015                                      (attrs & JSPROP_SETTER)
05016                                      ? JS_EXTENSION (JSPropertyOp) obj
05017                                      : NULL,
05018                                      attrs |
05019                                      JSPROP_ENUMERATE | JSPROP_PERMANENT |
05020                                      JSPROP_READONLY,
05021                                      NULL);
05022 
05023             /* Restore fp->scopeChain now that obj is defined in parent. */
05024             fp->scopeChain = obj2;
05025             if (!ok) {
05026                 cx->weakRoots.newborn[GCX_OBJECT] = NULL;
05027                 goto out;
05028             }
05029 
05030             /*
05031              * 5. Remove Result(1) from the front of the scope chain [no-op].
05032              * 6. Return Result(3).
05033              */
05034             PUSH_OPND(OBJECT_TO_JSVAL(obj));
05035             obj = NULL;
05036           END_LITOPX_CASE(JSOP_NAMEDFUNOBJ)
05037 
05038           BEGIN_LITOPX_CASE(JSOP_CLOSURE, 0)
05039             /*
05040              * ECMA ed. 3 extension: a named function expression in a compound
05041              * statement (not at the top statement level of global code, or at
05042              * the top level of a function body).
05043              *
05044              * Get immediate operand atom, which is a function object literal.
05045              * From it, get the function to close.
05046              */
05047             JS_ASSERT(VALUE_IS_FUNCTION(cx, ATOM_KEY(atom)));
05048             obj = ATOM_TO_OBJECT(atom);
05049 
05050             /*
05051              * Clone the function object with the current scope chain as the
05052              * clone's parent.  The original function object is the prototype
05053              * of the clone.  Do this only if re-parenting; the compiler may
05054              * have seen the right parent already and created a sufficiently
05055              * well-scoped function object.
05056              */
05057             SAVE_SP_AND_PC(fp);
05058             obj2 = js_GetScopeChain(cx, fp);
05059             if (!obj2) {
05060                 ok = JS_FALSE;
05061                 goto out;
05062             }
05063             if (OBJ_GET_PARENT(cx, obj) != obj2) {
05064                 obj = js_CloneFunctionObject(cx, obj, obj2);
05065                 if (!obj) {
05066                     ok = JS_FALSE;
05067                     goto out;
05068                 }
05069             }
05070 
05071             /*
05072              * Protect obj from any GC hiding below OBJ_DEFINE_PROPERTY.  All
05073              * paths from here must flow through the "Restore fp->scopeChain"
05074              * code below the OBJ_DEFINE_PROPERTY call.
05075              */
05076             fp->scopeChain = obj;
05077             rval = OBJECT_TO_JSVAL(obj);
05078 
05079             /*
05080              * Make a property in fp->varobj with id fun->atom and value obj,
05081              * unless fun is a getter or setter (in which case, obj is cast to
05082              * a JSPropertyOp and passed accordingly).
05083              */
05084             fun = (JSFunction *) JS_GetPrivate(cx, obj);
05085             attrs = JSFUN_GSFLAG2ATTR(fun->flags);
05086             if (attrs) {
05087                 attrs |= JSPROP_SHARED;
05088                 rval = JSVAL_VOID;
05089             }
05090             attrs |= JSPROP_ENUMERATE | JSPROP_PERMANENT;
05091             parent = fp->varobj;
05092             id = ATOM_TO_JSID(fun->atom);
05093             ok = js_CheckRedeclaration(cx, parent, id, attrs, NULL, NULL) &&
05094                  OBJ_DEFINE_PROPERTY(cx, parent, id, rval,
05095                                      (attrs & JSPROP_GETTER)
05096                                      ? JS_EXTENSION (JSPropertyOp) obj
05097                                      : NULL,
05098                                      (attrs & JSPROP_SETTER)
05099                                      ? JS_EXTENSION (JSPropertyOp) obj
05100                                      : NULL,
05101                                      attrs,
05102                                      &prop);
05103 
05104             /* Restore fp->scopeChain now that obj is defined in fp->varobj. */
05105             fp->scopeChain = obj2;
05106             if (!ok) {
05107                 cx->weakRoots.newborn[GCX_OBJECT] = NULL;
05108                 goto out;
05109             }
05110             OBJ_DROP_PROPERTY(cx, parent, prop);
05111           END_LITOPX_CASE(JSOP_CLOSURE)
05112 
05113 #if JS_HAS_GETTER_SETTER
05114           BEGIN_CASE(JSOP_GETTER)
05115           BEGIN_CASE(JSOP_SETTER)
05116             op2 = (JSOp) *++pc;
05117             switch (op2) {
05118               case JSOP_SETNAME:
05119               case JSOP_SETPROP:
05120                 atom = GET_ATOM(cx, script, pc);
05121                 id   = ATOM_TO_JSID(atom);
05122                 rval = FETCH_OPND(-1);
05123                 i = -1;
05124                 goto gs_pop_lval;
05125 
05126               case JSOP_SETELEM:
05127                 rval = FETCH_OPND(-1);
05128                 FETCH_ELEMENT_ID(-2, id);
05129                 i = -2;
05130               gs_pop_lval:
05131                 FETCH_OBJECT(cx, i - 1, lval, obj);
05132                 break;
05133 
05134               case JSOP_INITPROP:
05135                 JS_ASSERT(sp - fp->spbase >= 2);
05136                 rval = FETCH_OPND(-1);
05137                 i = -1;
05138                 atom = GET_ATOM(cx, script, pc);
05139                 id   = ATOM_TO_JSID(atom);
05140                 goto gs_get_lval;
05141 
05142               default:
05143                 JS_ASSERT(op2 == JSOP_INITELEM);
05144                 JS_ASSERT(sp - fp->spbase >= 3);
05145                 rval = FETCH_OPND(-1);
05146                 FETCH_ELEMENT_ID(-2, id);
05147                 i = -2;
05148               gs_get_lval:
05149                 lval = FETCH_OPND(i-1);
05150                 JS_ASSERT(JSVAL_IS_OBJECT(lval));
05151                 obj = JSVAL_TO_OBJECT(lval);
05152                 break;
05153             }
05154 
05155             /* Ensure that id has a type suitable for use with obj. */
05156             CHECK_ELEMENT_ID(obj, id);
05157 
05158             SAVE_SP_AND_PC(fp);
05159             if (JS_TypeOfValue(cx, rval) != JSTYPE_FUNCTION) {
05160                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
05161                                      JSMSG_BAD_GETTER_OR_SETTER,
05162                                      (op == JSOP_GETTER)
05163                                      ? js_getter_str
05164                                      : js_setter_str);
05165                 ok = JS_FALSE;
05166                 goto out;
05167             }
05168 
05169             /*
05170              * Getters and setters are just like watchpoints from an access
05171              * control point of view.
05172              */
05173             ok = OBJ_CHECK_ACCESS(cx, obj, id, JSACC_WATCH, &rtmp, &attrs);
05174             if (!ok)
05175                 goto out;
05176 
05177             if (op == JSOP_GETTER) {
05178                 getter = JS_EXTENSION (JSPropertyOp) JSVAL_TO_OBJECT(rval);
05179                 setter = NULL;
05180                 attrs = JSPROP_GETTER;
05181             } else {
05182                 getter = NULL;
05183                 setter = JS_EXTENSION (JSPropertyOp) JSVAL_TO_OBJECT(rval);
05184                 attrs = JSPROP_SETTER;
05185             }
05186             attrs |= JSPROP_ENUMERATE | JSPROP_SHARED;
05187 
05188             /* Check for a readonly or permanent property of the same name. */
05189             ok = js_CheckRedeclaration(cx, obj, id, attrs, NULL, NULL);
05190             if (!ok)
05191                 goto out;
05192 
05193             ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, getter, setter,
05194                                      attrs, NULL);
05195             if (!ok)
05196                 goto out;
05197 
05198             obj = NULL;
05199             sp += i;
05200             if (js_CodeSpec[op2].ndefs)
05201                 STORE_OPND(-1, rval);
05202             len = js_CodeSpec[op2].length;
05203             DO_NEXT_OP(len);
05204 #endif /* JS_HAS_GETTER_SETTER */
05205 
05206           BEGIN_CASE(JSOP_NEWINIT)
05207             argc = 0;
05208             fp->sharpDepth++;
05209             goto do_new;
05210 
05211           BEGIN_CASE(JSOP_ENDINIT)
05212             if (--fp->sharpDepth == 0)
05213                 fp->sharpArray = NULL;
05214 
05215             /* Re-set the newborn root to the top of this object tree. */
05216             JS_ASSERT(sp - fp->spbase >= 1);
05217             lval = FETCH_OPND(-1);
05218             JS_ASSERT(JSVAL_IS_OBJECT(lval));
05219             cx->weakRoots.newborn[GCX_OBJECT] = JSVAL_TO_GCTHING(lval);
05220           END_CASE(JSOP_ENDINIT)
05221 
05222           BEGIN_CASE(JSOP_INITPROP)
05223             /* Pop the property's value into rval. */
05224             JS_ASSERT(sp - fp->spbase >= 2);
05225             rval = FETCH_OPND(-1);
05226 
05227             /* Get the immediate property name into id. */
05228             atom = GET_ATOM(cx, script, pc);
05229             id   = ATOM_TO_JSID(atom);
05230             i = -1;
05231             goto do_init;
05232 
05233           BEGIN_CASE(JSOP_INITELEM)
05234             /* Pop the element's value into rval. */
05235             JS_ASSERT(sp - fp->spbase >= 3);
05236             rval = FETCH_OPND(-1);
05237 
05238             /* Pop and conditionally atomize the element id. */
05239             FETCH_ELEMENT_ID(-2, id);
05240             i = -2;
05241 
05242           do_init:
05243             /* Find the object being initialized at top of stack. */
05244             lval = FETCH_OPND(i-1);
05245             JS_ASSERT(JSVAL_IS_OBJECT(lval));
05246             obj = JSVAL_TO_OBJECT(lval);
05247 
05248             /* Ensure that id has a type suitable for use with obj. */
05249             CHECK_ELEMENT_ID(obj, id);
05250 
05251             /* Set the property named by obj[id] to rval. */
05252             SAVE_SP_AND_PC(fp);
05253             ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
05254             if (!ok)
05255                 goto out;
05256             sp += i;
05257             len = js_CodeSpec[op].length;
05258             DO_NEXT_OP(len);
05259 
05260 #if JS_HAS_SHARP_VARS
05261           BEGIN_CASE(JSOP_DEFSHARP)
05262             SAVE_SP_AND_PC(fp);
05263             obj = fp->sharpArray;
05264             if (!obj) {
05265                 obj = js_NewArrayObject(cx, 0, NULL);
05266                 if (!obj) {
05267                     ok = JS_FALSE;
05268                     goto out;
05269                 }
05270                 fp->sharpArray = obj;
05271             }
05272             i = (jsint) GET_ATOM_INDEX(pc);
05273             id = INT_TO_JSID(i);
05274             rval = FETCH_OPND(-1);
05275             if (JSVAL_IS_PRIMITIVE(rval)) {
05276                 char numBuf[12];
05277                 JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i);
05278                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
05279                                      JSMSG_BAD_SHARP_DEF, numBuf);
05280                 ok = JS_FALSE;
05281                 goto out;
05282             }
05283             ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
05284             if (!ok)
05285                 goto out;
05286           END_CASE(JSOP_DEFSHARP)
05287 
05288           BEGIN_CASE(JSOP_USESHARP)
05289             i = (jsint) GET_ATOM_INDEX(pc);
05290             id = INT_TO_JSID(i);
05291             obj = fp->sharpArray;
05292             if (!obj) {
05293                 rval = JSVAL_VOID;
05294             } else {
05295                 SAVE_SP_AND_PC(fp);
05296                 ok = OBJ_GET_PROPERTY(cx, obj, id, &rval);
05297                 if (!ok)
05298                     goto out;
05299             }
05300             if (!JSVAL_IS_OBJECT(rval)) {
05301                 char numBuf[12];
05302                 JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i);
05303 
05304                 SAVE_SP_AND_PC(fp);
05305                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
05306                                      JSMSG_BAD_SHARP_USE, numBuf);
05307                 ok = JS_FALSE;
05308                 goto out;
05309             }
05310             PUSH_OPND(rval);
05311           END_CASE(JSOP_USESHARP)
05312 #endif /* JS_HAS_SHARP_VARS */
05313 
05314           /* No-ops for ease of decompilation and jit'ing. */
05315           EMPTY_CASE(JSOP_TRY)
05316           EMPTY_CASE(JSOP_FINALLY)
05317 
05318           /* Reset the stack to the given depth. */
05319           BEGIN_CASE(JSOP_SETSP)
05320             i = (jsint) GET_ATOM_INDEX(pc);
05321             JS_ASSERT(i >= 0);
05322 
05323             for (obj = fp->blockChain; obj; obj = OBJ_GET_PARENT(cx, obj)) {
05324                 JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_BlockClass);
05325                 if (OBJ_BLOCK_DEPTH(cx, obj) + (jsint)OBJ_BLOCK_COUNT(cx, obj) <= i) {
05326                     JS_ASSERT(OBJ_BLOCK_DEPTH(cx, obj) < i || OBJ_BLOCK_COUNT(cx, obj) == 0);
05327                     break;
05328                 }
05329             }
05330             fp->blockChain = obj;
05331 
05332             JS_ASSERT(ok);
05333             for (obj = fp->scopeChain;
05334                  (clasp = OBJ_GET_CLASS(cx, obj)) == &js_WithClass ||
05335                  clasp == &js_BlockClass;
05336                  obj = OBJ_GET_PARENT(cx, obj)) {
05337                 if (JS_GetPrivate(cx, obj) != fp ||
05338                     OBJ_BLOCK_DEPTH(cx, obj) < i) {
05339                     break;
05340                 }
05341                 if (clasp == &js_BlockClass)
05342                     ok &= js_PutBlockObject(cx, obj);
05343                 else
05344                     JS_SetPrivate(cx, obj, NULL);
05345             }
05346 
05347             fp->scopeChain = obj;
05348 
05349             /* Set sp after js_PutBlockObject to avoid potential GC hazards. */
05350             sp = fp->spbase + i;
05351 
05352             /* Don't fail until after we've updated all stacks. */
05353             if (!ok)
05354                 goto out;
05355           END_CASE(JSOP_SETSP)
05356 
05357           BEGIN_CASE(JSOP_GOSUB)
05358             JS_ASSERT(cx->exception != JSVAL_HOLE);
05359             if (!cx->throwing) {
05360                 lval = JSVAL_HOLE;
05361             } else {
05362                 lval = cx->exception;
05363                 cx->throwing = JS_FALSE;
05364             }
05365             PUSH(lval);
05366             i = PTRDIFF(pc, script->main, jsbytecode) + JSOP_GOSUB_LENGTH;
05367             len = GET_JUMP_OFFSET(pc);
05368             PUSH(INT_TO_JSVAL(i));
05369           END_VARLEN_CASE
05370 
05371           BEGIN_CASE(JSOP_GOSUBX)
05372             JS_ASSERT(cx->exception != JSVAL_HOLE);
05373             if (!cx->throwing) {
05374                 lval = JSVAL_HOLE;
05375             } else {
05376                 lval = cx->exception;
05377                 cx->throwing = JS_FALSE;
05378             }
05379             PUSH(lval);
05380             i = PTRDIFF(pc, script->main, jsbytecode) + JSOP_GOSUBX_LENGTH;
05381             len = GET_JUMPX_OFFSET(pc);
05382             PUSH(INT_TO_JSVAL(i));
05383           END_VARLEN_CASE
05384 
05385           BEGIN_CASE(JSOP_RETSUB)
05386             rval = POP();
05387             JS_ASSERT(JSVAL_IS_INT(rval));
05388             lval = POP();
05389             if (lval != JSVAL_HOLE) {
05390                 /*
05391                  * Exception was pending during finally, throw it *before* we
05392                  * adjust pc, because pc indexes into script->trynotes.  This
05393                  * turns out not to be necessary, but it seems clearer.  And
05394                  * it points out a FIXME: 350509, due to Igor Bukanov.
05395                  */
05396                 cx->throwing = JS_TRUE;
05397                 cx->exception = lval;
05398                 ok = JS_FALSE;
05399                 goto out;
05400             }
05401             len = JSVAL_TO_INT(rval);
05402             pc = script->main;
05403           END_VARLEN_CASE
05404 
05405           BEGIN_CASE(JSOP_EXCEPTION)
05406             JS_ASSERT(cx->throwing);
05407             PUSH(cx->exception);
05408             cx->throwing = JS_FALSE;
05409           END_CASE(JSOP_EXCEPTION)
05410 
05411           BEGIN_CASE(JSOP_THROWING)
05412             JS_ASSERT(!cx->throwing);
05413             cx->throwing = JS_TRUE;
05414             cx->exception = POP_OPND();
05415           END_CASE(JSOP_THROWING)
05416 
05417           BEGIN_CASE(JSOP_THROW)
05418             JS_ASSERT(!cx->throwing);
05419             cx->throwing = JS_TRUE;
05420             cx->exception = POP_OPND();
05421             ok = JS_FALSE;
05422             /* let the code at out try to catch the exception. */
05423             goto out;
05424 
05425           BEGIN_CASE(JSOP_SETLOCALPOP)
05426             /*
05427              * The stack must have a block with at least one local slot below
05428              * the exception object.
05429              */
05430             JS_ASSERT(sp - fp->spbase >= 2);
05431             slot = GET_UINT16(pc);
05432             JS_ASSERT(slot + 1 < (uintN)depth);
05433             fp->spbase[slot] = POP_OPND();
05434           END_CASE(JSOP_SETLOCALPOP)
05435 
05436           BEGIN_CASE(JSOP_INSTANCEOF)
05437             SAVE_SP_AND_PC(fp);
05438             rval = FETCH_OPND(-1);
05439             if (JSVAL_IS_PRIMITIVE(rval) ||
05440                 !(obj = JSVAL_TO_OBJECT(rval))->map->ops->hasInstance) {
05441                 str = js_DecompileValueGenerator(cx, -1, rval, NULL);
05442                 if (str) {
05443                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
05444                                          JSMSG_BAD_INSTANCEOF_RHS,
05445                                          JS_GetStringBytes(str));
05446                 }
05447                 ok = JS_FALSE;
05448                 goto out;
05449             }
05450             lval = FETCH_OPND(-2);
05451             cond = JS_FALSE;
05452             ok = obj->map->ops->hasInstance(cx, obj, lval, &cond);
05453             if (!ok)
05454                 goto out;
05455             sp--;
05456             STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));
05457           END_CASE(JSOP_INSTANCEOF)
05458 
05459 #if JS_HAS_DEBUGGER_KEYWORD
05460           BEGIN_CASE(JSOP_DEBUGGER)
05461           {
05462             JSTrapHandler handler = rt->debuggerHandler;
05463             if (handler) {
05464                 SAVE_SP_AND_PC(fp);
05465                 switch (handler(cx, script, pc, &rval,
05466                                 rt->debuggerHandlerData)) {
05467                   case JSTRAP_ERROR:
05468                     ok = JS_FALSE;
05469                     goto out;
05470                   case JSTRAP_CONTINUE:
05471                     break;
05472                   case JSTRAP_RETURN:
05473                     fp->rval = rval;
05474                     goto out;
05475                   case JSTRAP_THROW:
05476                     cx->throwing = JS_TRUE;
05477                     cx->exception = rval;
05478                     ok = JS_FALSE;
05479                     goto out;
05480                   default:;
05481                 }
05482                 LOAD_INTERRUPT_HANDLER(rt);
05483             }
05484           }
05485           END_CASE(JSOP_DEBUGGER)
05486 #endif /* JS_HAS_DEBUGGER_KEYWORD */
05487 
05488 #if JS_HAS_XML_SUPPORT
05489           BEGIN_CASE(JSOP_DEFXMLNS)
05490             rval = POP();
05491             SAVE_SP_AND_PC(fp);
05492             ok = js_SetDefaultXMLNamespace(cx, rval);
05493             if (!ok)
05494                 goto out;
05495           END_CASE(JSOP_DEFXMLNS)
05496 
05497           BEGIN_CASE(JSOP_ANYNAME)
05498             SAVE_SP_AND_PC(fp);
05499             ok = js_GetAnyName(cx, &rval);
05500             if (!ok)
05501                 goto out;
05502             PUSH_OPND(rval);
05503           END_CASE(JSOP_ANYNAME)
05504 
05505           BEGIN_LITOPX_CASE(JSOP_QNAMEPART, 0)
05506             PUSH_OPND(ATOM_KEY(atom));
05507           END_LITOPX_CASE(JSOP_QNAMEPART)
05508 
05509           BEGIN_LITOPX_CASE(JSOP_QNAMECONST, 0)
05510             rval = ATOM_KEY(atom);
05511             lval = FETCH_OPND(-1);
05512             SAVE_SP_AND_PC(fp);
05513             obj = js_ConstructXMLQNameObject(cx, lval, rval);
05514             if (!obj) {
05515                 ok = JS_FALSE;
05516                 goto out;
05517             }
05518             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
05519           END_LITOPX_CASE(JSOP_QNAMECONST)
05520 
05521           BEGIN_CASE(JSOP_QNAME)
05522             rval = FETCH_OPND(-1);
05523             lval = FETCH_OPND(-2);
05524             SAVE_SP_AND_PC(fp);
05525             obj = js_ConstructXMLQNameObject(cx, lval, rval);
05526             if (!obj) {
05527                 ok = JS_FALSE;
05528                 goto out;
05529             }
05530             sp--;
05531             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
05532           END_CASE(JSOP_QNAME)
05533 
05534           BEGIN_CASE(JSOP_TOATTRNAME)
05535             rval = FETCH_OPND(-1);
05536             SAVE_SP_AND_PC(fp);
05537             ok = js_ToAttributeName(cx, &rval);
05538             if (!ok)
05539                 goto out;
05540             STORE_OPND(-1, rval);
05541           END_CASE(JSOP_TOATTRNAME)
05542 
05543           BEGIN_CASE(JSOP_TOATTRVAL)
05544             rval = FETCH_OPND(-1);
05545             JS_ASSERT(JSVAL_IS_STRING(rval));
05546             SAVE_SP_AND_PC(fp);
05547             str = js_EscapeAttributeValue(cx, JSVAL_TO_STRING(rval));
05548             if (!str) {
05549                 ok = JS_FALSE;
05550                 goto out;
05551             }
05552             STORE_OPND(-1, STRING_TO_JSVAL(str));
05553           END_CASE(JSOP_TOATTRVAL)
05554 
05555           BEGIN_CASE(JSOP_ADDATTRNAME)
05556           BEGIN_CASE(JSOP_ADDATTRVAL)
05557             rval = FETCH_OPND(-1);
05558             lval = FETCH_OPND(-2);
05559             str = JSVAL_TO_STRING(lval);
05560             str2 = JSVAL_TO_STRING(rval);
05561             SAVE_SP_AND_PC(fp);
05562             str = js_AddAttributePart(cx, op == JSOP_ADDATTRNAME, str, str2);
05563             if (!str) {
05564                 ok = JS_FALSE;
05565                 goto out;
05566             }
05567             sp--;
05568             STORE_OPND(-1, STRING_TO_JSVAL(str));
05569           END_CASE(JSOP_ADDATTRNAME)
05570 
05571           BEGIN_CASE(JSOP_BINDXMLNAME)
05572             lval = FETCH_OPND(-1);
05573             SAVE_SP_AND_PC(fp);
05574             ok = js_FindXMLProperty(cx, lval, &obj, &rval);
05575             if (!ok)
05576                 goto out;
05577             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
05578             PUSH_OPND(rval);
05579           END_CASE(JSOP_BINDXMLNAME)
05580 
05581           BEGIN_CASE(JSOP_SETXMLNAME)
05582             obj = JSVAL_TO_OBJECT(FETCH_OPND(-3));
05583             lval = FETCH_OPND(-2);
05584             rval = FETCH_OPND(-1);
05585             SAVE_SP_AND_PC(fp);
05586             ok = js_SetXMLProperty(cx, obj, lval, &rval);
05587             if (!ok)
05588                 goto out;
05589             sp -= 2;
05590             STORE_OPND(-1, rval);
05591             obj = NULL;
05592           END_CASE(JSOP_SETXMLNAME)
05593 
05594           BEGIN_CASE(JSOP_XMLNAME)
05595             lval = FETCH_OPND(-1);
05596             SAVE_SP_AND_PC(fp);
05597             ok = js_FindXMLProperty(cx, lval, &obj, &rval);
05598             if (!ok)
05599                 goto out;
05600             ok = js_GetXMLProperty(cx, obj, rval, &rval);
05601             if (!ok)
05602                 goto out;
05603             STORE_OPND(-1, rval);
05604           END_CASE(JSOP_XMLNAME)
05605 
05606           BEGIN_CASE(JSOP_DESCENDANTS)
05607           BEGIN_CASE(JSOP_DELDESC)
05608             FETCH_OBJECT(cx, -2, lval, obj);
05609             rval = FETCH_OPND(-1);
05610             SAVE_SP_AND_PC(fp);
05611             ok = js_GetXMLDescendants(cx, obj, rval, &rval);
05612             if (!ok)
05613                 goto out;
05614 
05615             if (op == JSOP_DELDESC) {
05616                 sp[-1] = rval;          /* set local root */
05617                 ok = js_DeleteXMLListElements(cx, JSVAL_TO_OBJECT(rval));
05618                 if (!ok)
05619                     goto out;
05620                 rval = JSVAL_TRUE;      /* always succeed */
05621             }
05622 
05623             sp--;
05624             STORE_OPND(-1, rval);
05625           END_CASE(JSOP_DESCENDANTS)
05626 
05627           BEGIN_CASE(JSOP_FILTER)
05628             FETCH_OBJECT(cx, -1, lval, obj);
05629             len = GET_JUMP_OFFSET(pc);
05630             SAVE_SP_AND_PC(fp);
05631             ok = js_FilterXMLList(cx, obj, pc + js_CodeSpec[op].length, &rval);
05632             if (!ok)
05633                 goto out;
05634             JS_ASSERT(fp->sp == sp);
05635             STORE_OPND(-1, rval);
05636           END_VARLEN_CASE
05637 
05638           BEGIN_CASE(JSOP_ENDFILTER)
05639             *result = POP_OPND();
05640             goto out;
05641 
05642           EMPTY_CASE(JSOP_STARTXML)
05643           EMPTY_CASE(JSOP_STARTXMLEXPR)
05644 
05645           BEGIN_CASE(JSOP_TOXML)
05646             rval = FETCH_OPND(-1);
05647             SAVE_SP_AND_PC(fp);
05648             obj = js_ValueToXMLObject(cx, rval);
05649             if (!obj) {
05650                 ok = JS_FALSE;
05651                 goto out;
05652             }
05653             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
05654           END_CASE(JSOP_TOXML)
05655 
05656           BEGIN_CASE(JSOP_TOXMLLIST)
05657             rval = FETCH_OPND(-1);
05658             SAVE_SP_AND_PC(fp);
05659             obj = js_ValueToXMLListObject(cx, rval);
05660             if (!obj) {
05661                 ok = JS_FALSE;
05662                 goto out;
05663             }
05664             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
05665           END_CASE(JSOP_TOXMLLIST)
05666 
05667           BEGIN_CASE(JSOP_XMLTAGEXPR)
05668             rval = FETCH_OPND(-1);
05669             SAVE_SP_AND_PC(fp);
05670             str = js_ValueToString(cx, rval);
05671             if (!str) {
05672                 ok = JS_FALSE;
05673                 goto out;
05674             }
05675             STORE_OPND(-1, STRING_TO_JSVAL(str));
05676           END_CASE(JSOP_XMLTAGEXPR)
05677 
05678           BEGIN_CASE(JSOP_XMLELTEXPR)
05679             rval = FETCH_OPND(-1);
05680             SAVE_SP_AND_PC(fp);
05681             if (VALUE_IS_XML(cx, rval)) {
05682                 str = js_ValueToXMLString(cx, rval);
05683             } else {
05684                 str = js_ValueToString(cx, rval);
05685                 if (str)
05686                     str = js_EscapeElementValue(cx, str);
05687             }
05688             if (!str) {
05689                 ok = JS_FALSE;
05690                 goto out;
05691             }
05692             STORE_OPND(-1, STRING_TO_JSVAL(str));
05693           END_CASE(JSOP_XMLELTEXPR)
05694 
05695           BEGIN_LITOPX_CASE(JSOP_XMLOBJECT, 0)
05696             SAVE_SP_AND_PC(fp);
05697             obj = js_CloneXMLObject(cx, ATOM_TO_OBJECT(atom));
05698             if (!obj) {
05699                 ok = JS_FALSE;
05700                 goto out;
05701             }
05702             PUSH_OPND(OBJECT_TO_JSVAL(obj));
05703             obj = NULL;
05704           END_LITOPX_CASE(JSOP_XMLOBJECT)
05705 
05706           BEGIN_LITOPX_CASE(JSOP_XMLCDATA, 0)
05707             str = ATOM_TO_STRING(atom);
05708             obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_TEXT, NULL, str);
05709             if (!obj) {
05710                 ok = JS_FALSE;
05711                 goto out;
05712             }
05713             PUSH_OPND(OBJECT_TO_JSVAL(obj));
05714           END_LITOPX_CASE(JSOP_XMLCDATA)
05715 
05716           BEGIN_LITOPX_CASE(JSOP_XMLCOMMENT, 0)
05717             str = ATOM_TO_STRING(atom);
05718             obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_COMMENT, NULL, str);
05719             if (!obj) {
05720                 ok = JS_FALSE;
05721                 goto out;
05722             }
05723             PUSH_OPND(OBJECT_TO_JSVAL(obj));
05724           END_LITOPX_CASE(JSOP_XMLCOMMENT)
05725 
05726           BEGIN_LITOPX_CASE(JSOP_XMLPI, 0)
05727             str = ATOM_TO_STRING(atom);
05728             rval = FETCH_OPND(-1);
05729             str2 = JSVAL_TO_STRING(rval);
05730             SAVE_SP_AND_PC(fp);
05731             obj = js_NewXMLSpecialObject(cx,
05732                                          JSXML_CLASS_PROCESSING_INSTRUCTION,
05733                                          str, str2);
05734             if (!obj) {
05735                 ok = JS_FALSE;
05736                 goto out;
05737             }
05738             STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
05739           END_LITOPX_CASE(JSOP_XMLPI)
05740 
05741           BEGIN_LITOPX_CASE(JSOP_GETMETHOD, 0)
05742             /* Get an immediate atom naming the property. */
05743             id   = ATOM_TO_JSID(atom);
05744             lval = FETCH_OPND(-1);
05745             SAVE_SP_AND_PC(fp);
05746             if (!JSVAL_IS_PRIMITIVE(lval)) {
05747                 STORE_OPND(-1, lval);
05748                 obj = JSVAL_TO_OBJECT(lval);
05749 
05750                 /* Special-case XML object method lookup, per ECMA-357. */
05751                 if (OBJECT_IS_XML(cx, obj)) {
05752                     JSXMLObjectOps *ops;
05753 
05754                     ops = (JSXMLObjectOps *) obj->map->ops;
05755                     obj = ops->getMethod(cx, obj, id, &rval);
05756                     if (!obj)
05757                         ok = JS_FALSE;
05758                 } else {
05759                     CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval));
05760                 }
05761             } else {
05762                 if (JSVAL_IS_STRING(lval)) {
05763                     i = JSProto_String;
05764                 } else if (JSVAL_IS_NUMBER(lval)) {
05765                     i = JSProto_Number;
05766                 } else if (JSVAL_IS_BOOLEAN(lval)) {
05767                     i = JSProto_Boolean;
05768                 } else {
05769                     JS_ASSERT(JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval));
05770                     str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
05771                                                      lval, NULL);
05772                     if (str) {
05773                         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
05774                                              JSMSG_NO_PROPERTIES,
05775                                              JS_GetStringBytes(str));
05776                     }
05777                     ok = JS_FALSE;
05778                     goto out;
05779                 }
05780                 ok = js_GetClassPrototype(cx, NULL, INT_TO_JSID(i), &obj);
05781                 if (!ok)
05782                     goto out;
05783                 JS_ASSERT(obj);
05784                 STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
05785                 CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval));
05786                 obj = (JSObject *) lval; /* keep tagged as non-object */
05787             }
05788             if (!ok)
05789                 goto out;
05790             STORE_OPND(-1, rval);
05791           END_LITOPX_CASE(JSOP_GETMETHOD)
05792 
05793           BEGIN_LITOPX_CASE(JSOP_SETMETHOD, 0)
05794             /* Get an immediate atom naming the property. */
05795             id   = ATOM_TO_JSID(atom);
05796             rval = FETCH_OPND(-1);
05797             FETCH_OBJECT(cx, -2, lval, obj);
05798             SAVE_SP_AND_PC(fp);
05799 
05800             /* Special-case XML object method lookup, per ECMA-357. */
05801             if (OBJECT_IS_XML(cx, obj)) {
05802                 JSXMLObjectOps *ops;
05803 
05804                 ops = (JSXMLObjectOps *) obj->map->ops;
05805                 ok = ops->setMethod(cx, obj, id, &rval);
05806             } else {
05807                 CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval));
05808             }
05809             if (!ok)
05810                 goto out;
05811             --sp;
05812             STORE_OPND(-1, rval);
05813             obj = NULL;
05814           END_LITOPX_CASE(JSOP_SETMETHOD)
05815 
05816           BEGIN_CASE(JSOP_GETFUNNS)
05817             SAVE_SP_AND_PC(fp);
05818             ok = js_GetFunctionNamespace(cx, &rval);
05819             if (!ok)
05820                 goto out;
05821             PUSH_OPND(rval);
05822           END_CASE(JSOP_GETFUNNS)
05823 #endif /* JS_HAS_XML_SUPPORT */
05824 
05825           BEGIN_LITOPX_CASE(JSOP_ENTERBLOCK, 0)
05826             obj = ATOM_TO_OBJECT(atom);
05827             JS_ASSERT(fp->spbase + OBJ_BLOCK_DEPTH(cx, obj) == sp);
05828             vp = sp + OBJ_BLOCK_COUNT(cx, obj);
05829             JS_ASSERT(vp <= fp->spbase + depth);
05830             while (sp < vp) {
05831                 STORE_OPND(0, JSVAL_VOID);
05832                 sp++;
05833             }
05834 
05835             /*
05836              * If this frame had to reflect the compile-time block chain into
05837              * the runtime scope chain, we can't optimize block scopes out of
05838              * runtime any longer, because an outer block that parents obj has
05839              * been cloned onto the scope chain.  To avoid re-cloning such a
05840              * parent and accumulating redundant clones via js_GetScopeChain,
05841              * we must clone each block eagerly on entry, and push it on the
05842              * scope chain, until this frame pops.
05843              */
05844             if (fp->flags & JSFRAME_POP_BLOCKS) {
05845                 JS_ASSERT(!fp->blockChain);
05846 
05847                 /*
05848                  * Check whether JSOP_DEFLOCALFUN emulated JSOP_ENTERBLOCK for
05849                  * the body block in order to correctly scope the local cloned
05850                  * function object it creates.
05851                  */
05852                 parent = fp->scopeChain;
05853                 if (OBJ_GET_PROTO(cx, parent) == obj) {
05854                     JS_ASSERT(OBJ_GET_CLASS(cx, parent) == &js_BlockClass);
05855                 } else {
05856                     obj = js_CloneBlockObject(cx, obj, parent, fp);
05857                     if (!obj) {
05858                         ok = JS_FALSE;
05859                         goto out;
05860                     }
05861                     fp->scopeChain = obj;
05862                 }
05863             } else {
05864                 JS_ASSERT(!fp->blockChain ||
05865                           OBJ_GET_PARENT(cx, obj) == fp->blockChain);
05866                 fp->blockChain = obj;
05867             }
05868           END_LITOPX_CASE(JSOP_ENTERBLOCK)
05869 
05870           BEGIN_CASE(JSOP_LEAVEBLOCKEXPR)
05871           BEGIN_CASE(JSOP_LEAVEBLOCK)
05872           {
05873             JSObject **chainp;
05874 
05875             /* Grab the result of the expression. */
05876             if (op == JSOP_LEAVEBLOCKEXPR)
05877                 rval = FETCH_OPND(-1);
05878 
05879             chainp = &fp->blockChain;
05880             obj = *chainp;
05881             if (!obj) {
05882                 chainp = &fp->scopeChain;
05883                 obj = *chainp;
05884 
05885                 /*
05886                  * This block was cloned, so clear its private data and sync
05887                  * its locals to their property slots.
05888                  */
05889                 SAVE_SP_AND_PC(fp);
05890                 ok = js_PutBlockObject(cx, obj);
05891                 if (!ok)
05892                     goto out;
05893             }
05894 
05895             sp -= GET_UINT16(pc);
05896             JS_ASSERT(fp->spbase <= sp && sp <= fp->spbase + depth);
05897 
05898             /* Store the result into the topmost stack slot. */
05899             if (op == JSOP_LEAVEBLOCKEXPR)
05900                 STORE_OPND(-1, rval);
05901 
05902             JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_BlockClass);
05903             JS_ASSERT(op == JSOP_LEAVEBLOCKEXPR
05904                       ? fp->spbase + OBJ_BLOCK_DEPTH(cx, obj) == sp - 1
05905                       : fp->spbase + OBJ_BLOCK_DEPTH(cx, obj) == sp);
05906 
05907             *chainp = OBJ_GET_PARENT(cx, obj);
05908             JS_ASSERT(chainp != &fp->blockChain ||
05909                       !*chainp ||
05910                       OBJ_GET_CLASS(cx, *chainp) == &js_BlockClass);
05911           }
05912           END_CASE(JSOP_LEAVEBLOCK)
05913 
05914           BEGIN_CASE(JSOP_GETLOCAL)
05915             slot = GET_UINT16(pc);
05916             JS_ASSERT(slot < (uintN)depth);
05917             PUSH_OPND(fp->spbase[slot]);
05918             obj = NULL;
05919           END_CASE(JSOP_GETLOCAL)
05920 
05921           BEGIN_CASE(JSOP_SETLOCAL)
05922             slot = GET_UINT16(pc);
05923             JS_ASSERT(slot < (uintN)depth);
05924             vp = &fp->spbase[slot];
05925             GC_POKE(cx, *vp);
05926             *vp = FETCH_OPND(-1);
05927             obj = NULL;
05928           END_CASE(JSOP_SETLOCAL)
05929 
05930 /* NB: This macro doesn't use JS_BEGIN_MACRO/JS_END_MACRO around its body. */
05931 #define FAST_LOCAL_INCREMENT_OP(PRE,OPEQ,MINMAX)                              \
05932     slot = GET_UINT16(pc);                                                    \
05933     JS_ASSERT(slot < (uintN)depth);                                           \
05934     vp = fp->spbase + slot;                                                   \
05935     rval = *vp;                                                               \
05936     if (!JSVAL_IS_INT(rval) || rval == INT_TO_JSVAL(JSVAL_INT_##MINMAX))      \
05937         goto do_nonint_fast_incop;                                            \
05938     PRE = rval;                                                               \
05939     rval OPEQ 2;                                                              \
05940     *vp = rval;                                                               \
05941     PUSH_OPND(PRE)
05942 
05943           BEGIN_CASE(JSOP_INCLOCAL)
05944             FAST_LOCAL_INCREMENT_OP(rval, +=, MAX);
05945           END_CASE(JSOP_INCLOCAL)
05946 
05947           BEGIN_CASE(JSOP_DECLOCAL)
05948             FAST_LOCAL_INCREMENT_OP(rval, -=, MIN);
05949           END_CASE(JSOP_DECLOCAL)
05950 
05951           BEGIN_CASE(JSOP_LOCALINC)
05952             FAST_LOCAL_INCREMENT_OP(rtmp, +=, MAX);
05953           END_CASE(JSOP_LOCALINC)
05954 
05955           BEGIN_CASE(JSOP_LOCALDEC)
05956             FAST_LOCAL_INCREMENT_OP(rtmp, -=, MIN);
05957           END_CASE(JSOP_LOCALDEC)
05958 
05959 #undef FAST_LOCAL_INCREMENT_OP
05960 
05961           BEGIN_CASE(JSOP_ENDITER)
05962             JS_ASSERT(!JSVAL_IS_PRIMITIVE(sp[-1]));
05963             iterobj = JSVAL_TO_OBJECT(sp[-1]);
05964 
05965             /*
05966              * js_CloseNativeIterator checks whether the iterator is not
05967              * native, and also detects the case of a native iterator that
05968              * has already escaped, even though a for-in loop caused it to
05969              * be created.  See jsiter.c.
05970              */
05971             SAVE_SP_AND_PC(fp);
05972             js_CloseNativeIterator(cx, iterobj);
05973             *--sp = JSVAL_NULL;
05974           END_CASE(JSOP_ENDITER)
05975 
05976 #if JS_HAS_GENERATORS
05977           BEGIN_CASE(JSOP_GENERATOR)
05978             pc += JSOP_GENERATOR_LENGTH;
05979             SAVE_SP_AND_PC(fp);
05980             obj = js_NewGenerator(cx, fp);
05981             if (!obj) {
05982                 ok = JS_FALSE;
05983             } else {
05984                 JS_ASSERT(!fp->callobj && !fp->argsobj);
05985                 fp->rval = OBJECT_TO_JSVAL(obj);
05986             }
05987             goto out;
05988 
05989           BEGIN_CASE(JSOP_YIELD)
05990             ASSERT_NOT_THROWING(cx);
05991             if (fp->flags & JSFRAME_FILTERING) {
05992                 /* FIXME: bug 309894 -- fix to eliminate this error. */
05993                 SAVE_SP_AND_PC(fp);
05994                 JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
05995                                        JSMSG_YIELD_FROM_FILTER);
05996                 ok = JS_FALSE;
05997                 goto out;
05998             }
05999             if (FRAME_TO_GENERATOR(fp)->state == JSGEN_CLOSING) {
06000                 str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
06001                                                  fp->argv[-2], NULL);
06002                 if (str) {
06003                     JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
06004                                            JSMSG_BAD_GENERATOR_YIELD,
06005                                            JSSTRING_CHARS(str));
06006                 }
06007                 ok = JS_FALSE;
06008                 goto out;
06009             }
06010             fp->rval = FETCH_OPND(-1);
06011             fp->flags |= JSFRAME_YIELDING;
06012             pc += JSOP_YIELD_LENGTH;
06013             SAVE_SP_AND_PC(fp);
06014             goto out;
06015 
06016           BEGIN_CASE(JSOP_ARRAYPUSH)
06017             slot = GET_UINT16(pc);
06018             JS_ASSERT(slot < (uintN)depth);
06019             lval = fp->spbase[slot];
06020             obj  = JSVAL_TO_OBJECT(lval);
06021             JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_ArrayClass);
06022             rval = FETCH_OPND(-1);
06023 
06024             /* We know that the array is created with only a 'length' slot. */
06025             i = obj->map->freeslot - (JSSLOT_FREE(&js_ArrayClass) + 1);
06026             id = INT_TO_JSID(i);
06027 
06028             SAVE_SP_AND_PC(fp);
06029             ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
06030             if (!ok)
06031                 goto out;
06032             --sp;
06033           END_CASE(JSOP_ARRAYPUSH)
06034 #endif /* JS_HAS_GENERATORS */
06035 
06036 #if !JS_HAS_GENERATORS
06037           L_JSOP_GENERATOR:
06038           L_JSOP_YIELD:
06039           L_JSOP_ARRAYPUSH:
06040 #endif
06041 
06042 #if !JS_HAS_DESTRUCTURING
06043           L_JSOP_FOREACHKEYVAL:
06044           L_JSOP_ENUMCONSTELEM:
06045 #endif
06046 
06047 #ifdef JS_THREADED_INTERP
06048           L_JSOP_BACKPATCH:
06049           L_JSOP_BACKPATCH_POP:
06050 #else
06051           default:
06052 #endif
06053           {
06054             char numBuf[12];
06055             JS_snprintf(numBuf, sizeof numBuf, "%d", op);
06056             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
06057                                  JSMSG_BAD_BYTECODE, numBuf);
06058             ok = JS_FALSE;
06059             goto out;
06060           }
06061 
06062 #ifndef JS_THREADED_INTERP
06063 
06064         } /* switch (op) */
06065 
06066     advance_pc:
06067         pc += len;
06068 
06069 #ifdef DEBUG
06070         if (tracefp) {
06071             intN ndefs, n;
06072             jsval *siter;
06073 
06074             ndefs = js_CodeSpec[op].ndefs;
06075             if (ndefs) {
06076                 SAVE_SP_AND_PC(fp);
06077                 if (op == JSOP_FORELEM && sp[-1] == JSVAL_FALSE)
06078                     --ndefs;
06079                 for (n = -ndefs; n < 0; n++) {
06080                     str = js_DecompileValueGenerator(cx, n, sp[n], NULL);
06081                     if (str) {
06082                         fprintf(tracefp, "%s %s",
06083                                 (n == -ndefs) ? "  output:" : ",",
06084                                 JS_GetStringBytes(str));
06085                     }
06086                 }
06087                 fprintf(tracefp, " @ %d\n", sp - fp->spbase);
06088             }
06089             fprintf(tracefp, "  stack: ");
06090             for (siter = fp->spbase; siter < sp; siter++) {
06091                 str = js_ValueToSource(cx, *siter);
06092                 fprintf(tracefp, "%s ",
06093                         str ? JS_GetStringBytes(str) : "<null>");
06094             }
06095             fputc('\n', tracefp);
06096         }
06097 #endif /* DEBUG */
06098     }
06099 #endif /* !JS_THREADED_INTERP */
06100 
06101 out:
06102     if (!ok) {
06103         /*
06104          * Has an exception been raised?  Also insist that we are not in an
06105          * XML filtering predicate expression, to avoid catching exceptions
06106          * within the filtering predicate, such as this example taken from
06107          * tests/e4x/Regress/regress-301596.js:
06108          *
06109          *    try {
06110          *        <xml/>.(@a == 1);
06111          *        throw 5;
06112          *    } catch (e) {
06113          *    }
06114          *
06115          * The inner interpreter activation executing the predicate bytecode
06116          * will throw "reference to undefined XML name @a" (or 5, in older
06117          * versions that followed the first edition of ECMA-357 and evaluated
06118          * unbound identifiers to undefined), and the exception must not be
06119          * caught until control unwinds to the outer interpreter activation.
06120          *
06121          * Otherwise, the wrong stack depth will be restored by JSOP_SETSP,
06122          * and the catch will move into the filtering predicate expression,
06123          * leading to double catch execution if it rethrows.
06124          *
06125          * FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=309894
06126          */
06127         if (cx->throwing && !(fp->flags & JSFRAME_FILTERING)) {
06128             /*
06129              * Call debugger throw hook if set (XXX thread safety?).
06130              */
06131             JSTrapHandler handler = rt->throwHook;
06132             if (handler) {
06133                 SAVE_SP_AND_PC(fp);
06134                 switch (handler(cx, script, pc, &rval, rt->throwHookData)) {
06135                   case JSTRAP_ERROR:
06136                     cx->throwing = JS_FALSE;
06137                     goto no_catch;
06138                   case JSTRAP_RETURN:
06139                     ok = JS_TRUE;
06140                     cx->throwing = JS_FALSE;
06141                     fp->rval = rval;
06142                     goto no_catch;
06143                   case JSTRAP_THROW:
06144                     cx->exception = rval;
06145                   case JSTRAP_CONTINUE:
06146                   default:;
06147                 }
06148                 LOAD_INTERRUPT_HANDLER(rt);
06149             }
06150 
06151             /*
06152              * Look for a try block in script that can catch this exception.
06153              */
06154 #if JS_HAS_GENERATORS
06155             if (JS_LIKELY(cx->exception != JSVAL_ARETURN)) {
06156                 SCRIPT_FIND_CATCH_START(script, pc, pc);
06157                 if (!pc)
06158                     goto no_catch;
06159             } else {
06160                 pc = js_FindFinallyHandler(script, pc);
06161                 if (!pc) {
06162                     cx->throwing = JS_FALSE;
06163                     ok = JS_TRUE;
06164                     fp->rval = JSVAL_VOID;
06165                     goto no_catch;
06166                 }
06167             }
06168 #else
06169             SCRIPT_FIND_CATCH_START(script, pc, pc);
06170             if (!pc)
06171                 goto no_catch;
06172 #endif
06173 
06174             /* Don't clear cx->throwing to save cx->exception from GC. */
06175             len = 0;
06176             ok = JS_TRUE;
06177             DO_NEXT_OP(len);
06178         }
06179 no_catch:;
06180     }
06181 
06182     /*
06183      * Check whether control fell off the end of a lightweight function, or an
06184      * exception thrown under such a function was not caught by it.  If so, go
06185      * to the inline code under JSOP_RETURN.
06186      */
06187     if (inlineCallCount)
06188         goto inline_return;
06189 
06190     /*
06191      * Reset sp before freeing stack slots, because our caller may GC soon.
06192      * Clear spbase to indicate that we've popped the 2 * depth operand slots.
06193      * Restore the previous frame's execution state.
06194      */
06195     if (JS_LIKELY(mark != NULL)) {
06196         /* If fp has blocks on its scope chain, home their locals now. */
06197         if (fp->flags & JSFRAME_POP_BLOCKS) {
06198             SAVE_SP_AND_PC(fp);
06199             ok &= PutBlockObjects(cx, fp);
06200         }
06201 
06202         fp->sp = fp->spbase;
06203         fp->spbase = NULL;
06204         js_FreeRawStack(cx, mark);
06205     } else {
06206         SAVE_SP(fp);
06207     }
06208 
06209 out2:
06210     if (cx->version == currentVersion && currentVersion != originalVersion)
06211         js_SetVersion(cx, originalVersion);
06212     cx->interpLevel--;
06213     return ok;
06214 
06215 atom_not_defined:
06216     {
06217         const char *printable;
06218 
06219         ASSERT_SAVED_SP_AND_PC(fp);
06220         printable = js_AtomToPrintableString(cx, atom);
06221         if (printable)
06222             js_ReportIsNotDefined(cx, printable);
06223         ok = JS_FALSE;
06224         goto out;
06225     }
06226 }