home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / js / src / jsinterp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  72.4 KB  |  2,429 lines

  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20.  * JavaScript bytecode interpreter.
  21.  */
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <math.h>
  25. #include "prtypes.h"
  26. #include "prlog.h"
  27. #include "jsapi.h"
  28. #include "jsarray.h"
  29. #include "jsatom.h"
  30. #include "jsbool.h"
  31. #include "jscntxt.h"
  32. #include "jsconfig.h"
  33. #include "jsdbgapi.h"
  34. #include "jsfun.h"
  35. #include "jsgc.h"
  36. #include "jsinterp.h"
  37. #include "jslock.h"
  38. #include "jsnum.h"
  39. #include "jsobj.h"
  40. #include "jsopcode.h"
  41. #include "jsscope.h"
  42. #include "jsscript.h"
  43. #include "jsstr.h"
  44.  
  45. void
  46. js_FlushPropertyCache(JSContext *cx)
  47. {
  48.     JSPropertyCache *cache;
  49.     JSPropertyCacheEntry *end, *pce;
  50.  
  51.     cache = &cx->runtime->propertyCache;
  52.     if (cache->empty)
  53.     return;
  54.  
  55.     end = &cache->table[PROPERTY_CACHE_SIZE];
  56.     for (pce = &cache->table[0]; pce < end; pce++) {
  57.     if (pce->property) {
  58.         pce->property = NULL;
  59.         if (!JSVAL_IS_INT(pce->symbolid))
  60.         js_DropAtom(cx, (JSAtom *)pce->symbolid);
  61.         pce->symbolid = JSVAL_NULL;
  62.     }
  63.     }
  64.     cache->empty = JS_TRUE;
  65.     cache->flushes++;
  66. }
  67.  
  68. void
  69. js_FlushPropertyCacheByProp(JSContext *cx, JSProperty *prop)
  70. {
  71.     JSPropertyCache *cache;
  72.     JSBool empty;
  73.     JSPropertyCacheEntry *end, *pce;
  74.  
  75.     cache = &cx->runtime->propertyCache;
  76.     if (cache->empty)
  77.     return;
  78.  
  79.     empty = JS_TRUE;
  80.     end = &cache->table[PROPERTY_CACHE_SIZE];
  81.     for (pce = &cache->table[0]; pce < end; pce++) {
  82.     if (pce->property) {
  83.         if (pce->property == prop) {
  84.         pce->property = NULL;
  85.         if (!JSVAL_IS_INT(pce->symbolid))
  86.             js_DropAtom(cx, (JSAtom *)pce->symbolid);
  87.         pce->symbolid = JSVAL_NULL;
  88.         } else {
  89.         empty = JS_FALSE;
  90.         }
  91.     }
  92.     }
  93.     cache->empty = empty;
  94.     cache->pflushes++;
  95. }
  96.  
  97. /*
  98.  * Class for for/in loop property iterator objects.
  99.  */
  100. #define JSSLOT_PROP_OBJECT  (JSSLOT_START)
  101. #define JSSLOT_PROP_NEXT    (JSSLOT_START+1)
  102.  
  103. static void
  104. prop_iterator_finalize(JSContext *cx, JSObject *obj)
  105. {
  106.     jsval pval;
  107.     JSProperty *prop;
  108.  
  109.     pval = OBJ_GET_SLOT(obj, JSSLOT_PROP_NEXT);
  110.     prop = JSVAL_TO_PRIVATE(pval);
  111.     if (prop)
  112.     js_DropProperty(cx, prop);
  113. }
  114.  
  115. static JSClass prop_iterator_class = {
  116.     "PropertyIterator",
  117.     0,
  118.     JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,
  119.     JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   prop_iterator_finalize
  120. };
  121.  
  122. /*
  123.  * Stack macros and functions.  These all use a local variable, jsval *sp, to
  124.  * point to the next free stack slot.  SAVE_SP must be called before any call
  125.  * to a function that may invoke the interpreter.  RESTORE_SP must be called
  126.  * only after return from Call, because only Call changes fp->sp.
  127.  */
  128. #define PUSH(v)         (*sp++ = (v))
  129. #define POP()           (*--sp)
  130. #define SAVE_SP(fp)     ((fp)->sp = sp)
  131. #define RESTORE_SP(fp)  (sp = (fp)->sp)
  132.  
  133. /*
  134.  * Push the generating bytecode's pc onto the parallel pc stack that runs
  135.  * depth slots below the operands.
  136.  *
  137.  * NB: PUSH_OPND uses sp, depth, and pc from its lexical environment.  See
  138.  * Interpret for these local variables' declarations and uses.
  139.  */
  140. #define PUSH_OPND(v)    (sp[-depth] = (jsval)pc, PUSH(v))
  141.  
  142. /*
  143.  * Push the jsdouble d using sp, depth, and pc from the lexical environment.
  144.  * Try to convert d to a jsint that fits in a jsval, otherwise GC-alloc space
  145.  * for it and push a reference.
  146.  */
  147. #define PUSH_NUMBER(cx, d)                                                    \
  148.     PR_BEGIN_MACRO                                                            \
  149.     jsint _i;                                                             \
  150.     jsval _v;                                                             \
  151.                                           \
  152.     _i = (jsint)d;                                                        \
  153.     if (JSDOUBLE_IS_INT(d, _i) && INT_FITS_IN_JSVAL(_i)) {                \
  154.         _v = INT_TO_JSVAL(_i);                                            \
  155.     } else {                                                              \
  156.         ok = js_NewDoubleValue(cx, d, &_v);                               \
  157.         if (!ok)                                                          \
  158.         goto out;                                                     \
  159.     }                                                                     \
  160.     PUSH_OPND(_v);                                                        \
  161.     PR_END_MACRO
  162.  
  163. #define POP_NUMBER(cx, d)                                                     \
  164.     PR_BEGIN_MACRO                                                            \
  165.     jsval _v;                                                             \
  166.                                           \
  167.     _v = POP();                                                           \
  168.     VALUE_TO_NUMBER(cx, _v, d);                                           \
  169.     PR_END_MACRO
  170.  
  171. /*
  172.  * This POP variant is called only for bitwise operators, so we don't bother
  173.  * to inline it.  The calls in Interpret must therefore SAVE_SP first!
  174.  */
  175. static JSBool
  176. PopInt(JSContext *cx, jsint *ip, JSBool *validp)
  177. {
  178.     JSStackFrame *fp;
  179.     jsval *sp, v;
  180.     jsdouble d;
  181.     jsint i;
  182.  
  183.     fp = cx->fp;
  184.     RESTORE_SP(fp);
  185.     v = POP();
  186.     SAVE_SP(fp);
  187.     if (JSVAL_IS_INT(v)) {
  188.     *ip = JSVAL_TO_INT(v);
  189.     return JS_TRUE;
  190.     }
  191.     if (!JS_ValueToNumber(cx, v, &d))
  192.     return JS_FALSE;
  193.     i = (jsint)d;
  194.     *ip = i;
  195. #ifdef XP_PC
  196.     if (JSDOUBLE_IS_NaN(d)) {
  197.     *validp = JS_FALSE;
  198.     return JS_TRUE;
  199.     }
  200. #endif
  201.     *validp &= ((jsdouble)i == d || (jsdouble)(jsuint)i == d);
  202.     return JS_TRUE;
  203. }
  204.  
  205. /*
  206.  * Optimized conversion macros that test for the desired type in v before
  207.  * homing sp and calling a conversion function.
  208.  */
  209. #define VALUE_TO_NUMBER(cx, v, d)                                             \
  210.     PR_BEGIN_MACRO                                                            \
  211.     if (JSVAL_IS_INT(v)) {                                                \
  212.         d = (jsdouble)JSVAL_TO_INT(v);                                    \
  213.     } else if (JSVAL_IS_DOUBLE(v)) {                                      \
  214.         d = *JSVAL_TO_DOUBLE(v);                                          \
  215.     } else {                                                              \
  216.         SAVE_SP(fp);                                                      \
  217.         JS_LOCK_RUNTIME_VOID(rt, ok = js_ValueToNumber(cx, v, &d));       \
  218.         if (!ok)                                                          \
  219.         goto out;                                                     \
  220.     }                                                                     \
  221.     PR_END_MACRO
  222.  
  223. #define VALUE_TO_BOOLEAN(cx, v, b)                                            \
  224.     PR_BEGIN_MACRO                                                            \
  225.     if (v == JSVAL_NULL) {                                                \
  226.         b = JS_FALSE;                                                     \
  227.     } else if (JSVAL_IS_BOOLEAN(v)) {                                     \
  228.         b = JSVAL_TO_BOOLEAN(v);                                          \
  229.     } else {                                                              \
  230.         SAVE_SP(fp);                                                      \
  231.         JS_LOCK_RUNTIME_VOID(rt, ok = js_ValueToBoolean(cx, v, &b));      \
  232.         if (!ok)                                                          \
  233.         goto out;                                                     \
  234.     }                                                                     \
  235.     PR_END_MACRO
  236.  
  237. #define VALUE_TO_OBJECT(cx, v, obj)                                           \
  238.     PR_BEGIN_MACRO                                                            \
  239.     if (JSVAL_IS_OBJECT(v) && v != JSVAL_NULL) {                          \
  240.         obj = JSVAL_TO_OBJECT(v);                                         \
  241.     } else {                                                              \
  242.         SAVE_SP(fp);                                                      \
  243.         JS_LOCK_RUNTIME_VOID(rt, obj = js_ValueToNonNullObject(cx, v));   \
  244.         if (!obj) {                                                       \
  245.         ok = JS_FALSE;                                                \
  246.         goto out;                                                     \
  247.         }                                                                 \
  248.     }                                                                     \
  249.     PR_END_MACRO
  250.  
  251. #if JS_BUG_VOID_TOSTRING
  252. #define CHECK_VOID_TOSTRING(cx, v, vp)                                        \
  253.     if (JSVAL_IS_VOID(v)) {                                                   \
  254.     _str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); \
  255.     *vp = STRING_TO_JSVAL(_str);                                          \
  256.     }
  257. #else
  258. #define CHECK_VOID_TOSTRING(cx, v, vp)  /* nothing */
  259. #endif
  260.  
  261. #if JS_BUG_EAGER_TOSTRING
  262. #define TRY_VALUE_OF(cx, v, vp, TOSTRING_CODE) TOSTRING_CODE
  263. #else
  264. #define TRY_VALUE_OF(cx, v, vp, TOSTRING_CODE)                                \
  265.     js_TryValueOf(cx, JSVAL_TO_OBJECT(v), JSTYPE_VOID, vp);                   \
  266.     v = *vp;                                                                  \
  267.     if (JSVAL_IS_OBJECT(v) && v != JSVAL_NULL) {                              \
  268.         TOSTRING_CODE                                                         \
  269.     }
  270. #endif
  271.  
  272. #define VALUE_TO_PRIMITIVE(cx, v, vp)                                         \
  273.     PR_BEGIN_MACRO                                                            \
  274.     JSString *_str;                                                       \
  275.                                                                               \
  276.     if (!JSVAL_IS_OBJECT(v) || v == JSVAL_NULL) {                         \
  277.         CHECK_VOID_TOSTRING(cx, v, vp);                                   \
  278.     } else {                                                              \
  279.         SAVE_SP(cx->fp);                                                  \
  280.         TRY_VALUE_OF(cx, v, vp,                                           \
  281.         JS_LOCK_VOID(cx,                                              \
  282.             _str = js_ObjectToString(cx, JSVAL_TO_OBJECT(v)));        \
  283.         if (!_str) {                                                  \
  284.             ok = JS_FALSE;                                            \
  285.             goto out;                                                 \
  286.         }                                                             \
  287.         *vp = STRING_TO_JSVAL(_str);                                  \
  288.         )                                                                 \
  289.     }                                                                     \
  290.     PR_END_MACRO
  291.  
  292. static jsval *
  293. AllocStack(JSContext *cx, uintN nslots)
  294. {
  295.     jsval *sp;
  296.  
  297.     PR_ARENA_ALLOCATE(sp, &cx->stackPool, nslots * sizeof(jsval));
  298.     if (!sp) {
  299.     JS_ReportError(cx, "stack overflow in %s",
  300.                (cx->fp && cx->fp->fun)
  301.                ? JS_GetFunctionName(cx->fp->fun)
  302.                : "script");
  303.     }
  304.     return sp;
  305. }
  306.  
  307. JSBool
  308. js_GetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  309. {
  310.     JSStackFrame *fp;
  311.  
  312.     for (fp = cx->fp; fp; fp = fp->down) {
  313.     /* Find most recent non-native function frame. */
  314.     if (fp->fun && !fp->fun->call) {
  315.         if (fp->fun->object == obj) {
  316.         PR_ASSERT((uintN)JSVAL_TO_INT(id) < fp->fun->nargs);
  317.         *vp = fp->argv[JSVAL_TO_INT(id)];
  318.         }
  319.         return JS_TRUE;
  320.     }
  321.     }
  322.     return JS_TRUE;
  323. }
  324.  
  325. JSBool
  326. js_SetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  327. {
  328.     JSStackFrame *fp;
  329.  
  330.     for (fp = cx->fp; fp; fp = fp->down) {
  331.     /* Find most recent non-native function frame. */
  332.     if (fp->fun && !fp->fun->call) {
  333.         if (fp->fun->object == obj) {
  334.         PR_ASSERT((uintN)JSVAL_TO_INT(id) < fp->fun->nargs);
  335.         fp->argv[JSVAL_TO_INT(id)] = *vp;
  336.         }
  337.         return JS_TRUE;
  338.     }
  339.     }
  340.     return JS_TRUE;
  341. }
  342.  
  343. JSBool
  344. js_GetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  345. {
  346.     JSStackFrame *fp;
  347.     jsint slot;
  348.  
  349.     for (fp = cx->fp; fp; fp = fp->down) {
  350.     /* Find most recent non-native function frame. */
  351.     if (fp->fun && !fp->fun->call) {
  352.         if (fp->fun->object == obj) {
  353.         slot = JSVAL_TO_INT(id);
  354.         PR_ASSERT((uintN)slot < fp->fun->nvars);
  355.         if ((uintN)slot < fp->nvars)
  356.             *vp = fp->vars[slot];
  357.         }
  358.         return JS_TRUE;
  359.     }
  360.     }
  361.     return JS_TRUE;
  362. }
  363.  
  364. JSBool
  365. js_SetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  366. {
  367.     JSStackFrame *fp;
  368.     jsint slot;
  369.  
  370.     for (fp = cx->fp; fp; fp = fp->down) {
  371.     /* Find most recent non-native function frame. */
  372.     if (fp->fun && !fp->fun->call) {
  373.         if (fp->fun->object == obj) {
  374.         slot = JSVAL_TO_INT(id);
  375.         PR_ASSERT((uintN)slot < fp->fun->nvars);
  376.         if ((uintN)slot < fp->nvars)
  377.             fp->vars[slot] = *vp;
  378.         }
  379.         return JS_TRUE;
  380.     }
  381.     }
  382.     return JS_TRUE;
  383. }
  384.  
  385. static JSBool
  386. Interpret(JSContext *cx, jsval *result);
  387.  
  388. /*
  389.  * Find a function reference and its 'this' object implicit first parameter
  390.  * under argc arguments on cx's stack, and call the function.  Push missing
  391.  * required arguments, allocate declared local variables, and pop everything
  392.  * when done.  Then push the return value.
  393.  */
  394. JSBool
  395. js_DoCall(JSContext *cx, uintN argc)
  396. {
  397.     JSStackFrame *fp, frame;
  398.     jsval *sp, *newsp;
  399.     jsval *vp, aval;
  400.     JSObject *closure, *funobj, *parent, *thisp;
  401.     JSFunction *fun;
  402.     void *mark;
  403.     intN nslots, nalloc, surplus;
  404.     JSBool ok;
  405.  
  406.     /* Reach under our args to find the function ref on the stack. */
  407.     fp = cx->fp;
  408.     sp = fp->sp;
  409.     vp = sp - (2 + argc);
  410.  
  411.     /* Reset fp->sp so error reports decompile *vp's generator. */
  412.     fp->sp = vp;
  413.     closure = JSVAL_TO_OBJECT(*vp);
  414.     fun = JS_ValueToFunction(cx, *vp);
  415.     fp->sp = sp;
  416.     if (!fun)
  417.     return JS_FALSE;
  418.  
  419.     /* Get the function's parent object in case it's bound or orphaned. */
  420.     funobj = fun->object;
  421.     parent = OBJ_GET_PARENT(funobj);
  422.     thisp = JSVAL_TO_OBJECT(vp[1]);
  423.     if (fun->flags & (JSFUN_BOUND_METHOD | JSFUN_GLOBAL_PARENT)) {
  424.     /* Combine the above to optimize the common case (neither bit set). */
  425.     if (fun->flags & JSFUN_BOUND_METHOD)
  426.         thisp = parent;
  427.     else
  428.         parent = 0;
  429.     }
  430.  
  431.     /* Make vp refer to funobj to keep it available as argv[-2]. */
  432.     *vp = OBJECT_TO_JSVAL(funobj);
  433.  
  434.     /* Initialize a stack frame, except for thisp and scopeChain. */
  435.     frame.object = NULL;
  436.     frame.script = fun->script;
  437.     frame.fun = fun;
  438.     frame.argc = argc;
  439.     frame.argv = sp - argc;
  440.     frame.rval = JSVAL_VOID;
  441.     frame.nvars = fun->nvars;
  442.     frame.vars = sp;
  443.     frame.down = fp;
  444.     frame.annotation = NULL;
  445.     frame.pc = NULL;
  446.     frame.sp = sp;
  447. #if JS_HAS_SHARP_VARS
  448.     frame.sharpDepth = 0;
  449.     frame.sharpArray = NULL;
  450. #endif
  451.  
  452. #if JS_HAS_LEXICAL_CLOSURE
  453.     /* If calling a closure, set funobj to the call object eagerly. */
  454.     if (closure->map->clasp == &js_ClosureClass) {
  455.     frame.scopeChain = NULL;
  456.     parent = OBJ_GET_PARENT(closure);
  457.     funobj = js_GetCallObject(cx, &frame, parent);
  458.     if (!funobj)
  459.         return JS_FALSE;
  460.     thisp = parent;
  461. #if JS_BUG_WITH_CLOSURE
  462.     while (thisp->map->clasp == &js_WithClass) {
  463.         JSObject *proto = OBJ_GET_PROTO(thisp);
  464.         if (!proto)
  465.         break;
  466.         thisp = proto;
  467.     }
  468. #endif
  469.     }
  470. #endif
  471.  
  472.     /* Now set frame.thisp, so that the closure special case can reset it. */
  473.     frame.thisp = thisp;
  474.  
  475.     /* From here on, control must flow through label out: to return. */
  476.     JS_LOCK_VOID(cx, cx->fp = &frame);
  477.     mark = PR_ARENA_MARK(&cx->stackPool);
  478.  
  479.     /* Check for missing arguments expected by the function. */
  480.     nslots = (intN)((argc < fun->nargs) ? fun->nargs - argc : 0);
  481.     if (nslots) {
  482.     /* All arguments must be contiguous, so we may have to copy actuals. */
  483.     nalloc = nslots;
  484.     if ((pruword)(sp + nslots) > cx->stackPool.current->limit)
  485.         nalloc += argc;
  486.  
  487.     /* Take advantage of the surplus slots in the caller's frame depth. */
  488.     surplus = (jsval *)mark - sp;
  489.     PR_ASSERT(surplus >= 0);
  490.     nalloc -= surplus;
  491.  
  492.     /* Check whether we have enough space in the caller's frame. */
  493.     if (nalloc > 0) {
  494.         /* Need space for actuals plus missing formals minus surplus. */
  495.         newsp = AllocStack(cx, (uintN)nalloc);
  496.         if (!newsp) {
  497.         ok = JS_FALSE;
  498.         goto out;
  499.         }
  500.  
  501.         /* If we couldn't allocate contiguous args, copy actuals now. */
  502.         if (newsp != mark) {
  503.         if (argc)
  504.             memcpy(newsp, frame.argv, argc * sizeof(jsval));
  505.         frame.argv = newsp;
  506.         frame.vars = frame.sp = newsp + argc;
  507.         RESTORE_SP(&frame);
  508.         }
  509.     }
  510.  
  511.     /* Advance frame.vars to make room for the missing args. */
  512.     frame.vars += nslots;
  513.  
  514.     /* Push void to initialize missing args. */
  515.     while (--nslots >= 0)
  516.         PUSH(JSVAL_VOID);
  517.     }
  518.  
  519.     /* Now allocate stack space for local variables. */
  520.     nslots = (intN)frame.nvars;
  521.     if (nslots) {
  522.     surplus = (intN)((jsval *)cx->stackPool.current->avail - frame.vars);
  523.     if (surplus < nslots) {
  524.         newsp = AllocStack(cx, (uintN)nslots);
  525.         if (!newsp) {
  526.         ok = JS_FALSE;
  527.         goto out;
  528.         }
  529.         if (newsp != sp) {
  530.         /* NB: Discontinuity between argv and vars. */
  531.         frame.vars = frame.sp = newsp;
  532.         RESTORE_SP(&frame);
  533.         }
  534.     }
  535.  
  536.     /* Push void to initialize local variables. */
  537.     while (--nslots >= 0)
  538.         PUSH(JSVAL_VOID);
  539.     }
  540.  
  541.     /* Store the current sp in frame before calling fun. */
  542.     SAVE_SP(&frame);
  543.  
  544.     /* Call the function, either a native method or an interpreted script. */
  545.     if (fun->call) {
  546.     frame.scopeChain = fp->scopeChain;
  547.     ok = fun->call(cx, thisp, argc, frame.argv, &frame.rval);
  548.     } else if (fun->script) {
  549.     frame.scopeChain = funobj;
  550.     if (!parent) {
  551. #if JS_HAS_CALL_OBJECT
  552.         /* Scope with a call object parented by cx's global object. */
  553.         funobj = js_GetCallObject(cx, &frame, cx->globalObject);
  554.         if (!funobj) {
  555.         ok = JS_FALSE;
  556.         goto out;
  557.         }
  558. #else
  559.         /* Bad old code slams globalObject directly into funobj. */
  560.         OBJ_SET_PARENT(funobj, cx->globalObject);
  561. #endif
  562.     }
  563.     ok = Interpret(cx, &aval);
  564. #if !JS_HAS_CALL_OBJECT
  565.     if (!parent)
  566.         OBJ_SET_PARENT(funobj, NULL);
  567. #endif
  568.     } else {
  569.     /* fun might be onerror trying to report a syntax error in itself. */
  570.     frame.scopeChain = NULL;
  571.     ok = JS_TRUE;
  572.     }
  573.  
  574. out:
  575.     /*
  576.      * XXX - Checking frame.annotation limits the use of the hook for
  577.      * uses other than releasing annotations, but avoids one C function
  578.      * call for every JS function call.
  579.      */
  580.     if (frame.annotation &&
  581.     js_InterpreterHooks &&
  582.     js_InterpreterHooks->destroyFrame) {
  583.         js_InterpreterHooks->destroyFrame(cx, &frame);
  584.     }
  585.  
  586. #if JS_HAS_CALL_OBJECT
  587.     /* If frame has a call object, clear its back-pointer. */
  588.     if (frame.object)
  589.     ok &= js_PutCallObject(cx, &frame);
  590. #endif
  591.  
  592.     /* Pop everything off the stack and store the return value. */
  593.     PR_ARENA_RELEASE(&cx->stackPool, mark);
  594.     JS_LOCK_VOID(cx, cx->fp = fp);
  595.     fp->sp = vp + 1;
  596.     *vp = frame.rval;
  597.     return ok;
  598. }
  599.  
  600. JSBool
  601. js_Call(JSContext *cx, JSObject *obj, jsval fval, uintN argc, jsval *argv,
  602.     jsval *rval)
  603. {
  604.     void *mark;
  605.     JSStackFrame *fp, *oldfp, frame;
  606.     jsval *oldsp, *sp;
  607.     uintN i;
  608.     JSBool ok;
  609.  
  610.     mark = PR_ARENA_MARK(&cx->stackPool);
  611.     fp = oldfp = cx->fp;
  612.     if (!fp) {
  613.     memset(&frame, 0, sizeof frame);
  614.     JS_LOCK_VOID(cx, cx->fp = fp = &frame);
  615.     }
  616.     oldsp = fp->sp;
  617.     sp = AllocStack(cx, 2 + argc);
  618.     if (!sp)
  619.     return JS_FALSE;
  620.     fp->sp = sp;
  621.  
  622.     PUSH(fval);
  623.     PUSH(OBJECT_TO_JSVAL(obj));
  624.     for (i = 0; i < argc; i++)
  625.     PUSH(argv[i]);
  626.     SAVE_SP(fp);
  627.     ok = js_DoCall(cx, argc);
  628.     if (ok) {
  629.     RESTORE_SP(fp);
  630.     *rval = POP();
  631.     }
  632.  
  633.     PR_ARENA_RELEASE(&cx->stackPool, mark);
  634.     fp->sp = oldsp;
  635.     if (oldfp != fp)
  636.     JS_LOCK_VOID(cx, cx->fp = oldfp);
  637.     return ok;
  638. }
  639.  
  640. JSBool
  641. js_Execute(JSContext *cx, JSObject *chain, JSScript *script, JSStackFrame *down,
  642.        jsval *result)
  643. {
  644.     JSStackFrame *oldfp, frame;
  645.     JSBool ok;
  646.  
  647.     oldfp = cx->fp;
  648.     frame.object = NULL;
  649.     frame.script = script;
  650.     frame.fun = NULL;
  651.     frame.thisp = down ? down->thisp : chain;
  652.     frame.argc = frame.nvars = 0;
  653.     frame.argv = frame.vars = NULL;
  654.     frame.rval = JSVAL_VOID;
  655.     frame.down = down;
  656.     frame.annotation = NULL;
  657.     frame.scopeChain = chain;
  658.     frame.pc = NULL;
  659.     frame.sp = oldfp ? oldfp->sp : NULL;
  660. #if JS_HAS_SHARP_VARS
  661.     frame.sharpDepth = 0;
  662.     frame.sharpArray = down ? down->sharpArray : NULL;
  663. #endif
  664.     JS_LOCK_VOID(cx, cx->fp = &frame);
  665.     ok = Interpret(cx, result);
  666.     JS_LOCK_VOID(cx, cx->fp = oldfp);
  667.     return ok;
  668. }
  669.  
  670. #if JS_HAS_EXPORT_IMPORT
  671. /*
  672.  * If id is JSVAL_VOID, import all exported properties from obj.
  673.  */
  674. static JSBool
  675. ImportProperty(JSContext *cx, JSObject *obj, jsval id)
  676. {
  677.     JSBool all;
  678.     JSProperty *prop, *prop2;
  679.     JSString *str;
  680.     JSObject *source, *target, *funobj, *closure;
  681.     JSFunction *fun;
  682.     jsval value;
  683.  
  684.     PR_ASSERT(JS_IS_LOCKED(cx));
  685.  
  686.     all = JSVAL_IS_VOID(id);
  687.     if (all) {
  688.     if (!obj->map->clasp->enumerate(cx, obj))
  689.         return JS_FALSE;
  690.     prop = obj->map->props;
  691.     if (!prop)
  692.         return JS_TRUE;
  693.     } else {
  694.     if (!js_LookupProperty(cx, obj, id, &obj, &prop))
  695.         return JS_FALSE;
  696.     if (!prop) {
  697.         str = js_ValueToSource(cx, js_IdToValue(id));
  698.         if (str)
  699.         js_ReportIsNotDefined(cx, JS_GetStringBytes(str));
  700.         return JS_FALSE;
  701.     }
  702.     if (!(prop->flags & JSPROP_EXPORTED)) {
  703.         str = js_ValueToSource(cx, js_IdToValue(id));
  704.         if (str) {
  705.         JS_ReportError(cx, "%s is not exported",
  706.                    JS_GetStringBytes(str));
  707.         }
  708.         return JS_FALSE;
  709.     }
  710.     }
  711.  
  712.     source = prop->object;
  713.     target = js_FindVariableScope(cx, &fun);
  714.     if (!target)
  715.     return JS_FALSE;
  716.     do {
  717.     if (!(prop->flags & JSPROP_EXPORTED))
  718.         continue;
  719.     value = source->slots[prop->slot];
  720.     if (JSVAL_IS_FUNCTION(value)) {
  721.         funobj = JSVAL_TO_OBJECT(value);
  722.         closure = js_ConstructObject(cx, &js_ClosureClass, funobj, obj);
  723.         if (!closure)
  724.         return JS_FALSE;
  725.         value = OBJECT_TO_JSVAL(closure);
  726.     }
  727.     prop2 = js_DefineProperty(cx, target,
  728.                   all ? sym_id(prop->symbols) : id,
  729.                   value, NULL, NULL,
  730.                   prop->flags & ~JSPROP_EXPORTED);
  731.     if (!prop2)
  732.         return JS_FALSE;
  733.     } while (all && (prop = prop->next) != NULL);
  734.     return JS_TRUE;
  735. }
  736. #endif /* JS_HAS_EXPORT_IMPORT */
  737.  
  738. #if !defined XP_PC || !defined _MSC_VER || _MSC_VER > 800
  739. #define MAX_INTERP_LEVEL 1000
  740. #else
  741. #define MAX_INTERP_LEVEL 30
  742. #endif
  743.  
  744. static JSBool
  745. Interpret(JSContext *cx, jsval *result)
  746. {
  747.     JSRuntime *rt;
  748.     JSStackFrame *fp;
  749.     JSScript *script;
  750.     jsbytecode *pc, *pc2, *endpc;
  751.     JSBranchCallback onbranch;
  752.     JSBool ok, dropAtom, cond, valid;
  753.     void *mark;
  754.     jsval *sp, *newsp;
  755.     ptrdiff_t depth, len;
  756.     uintN argc, slot;
  757.     JSOp op, op2;
  758.     JSCodeSpec *cs;
  759.     JSAtom *atom;
  760.     jsval *vp, lval, rval, ltmp, rtmp, id;
  761.     JSObject *obj, *obj2, *proto, *parent;
  762.     JSObject *withobj;
  763.     JSObject *origobj, *propobj, *iterobj;
  764.     JSProperty *prop, *prop2;
  765.     JSString *str, *str2, *str3;
  766.     size_t length, length2, length3;
  767.     jschar *chars;
  768.     jsint i, j;
  769.     jsdouble d, d2;
  770.     JSFunction *fun;
  771.     JSType type;
  772. #ifdef DEBUG
  773.     FILE *tracefp;
  774. #endif
  775. #if JS_HAS_SWITCH_STATEMENT
  776.     jsint low, high;
  777.     uintN off, npairs;
  778.     JSBool match;
  779. #endif
  780. #if JS_HAS_LEXICAL_CLOSURE
  781.     JSFunction *fun2;
  782.     JSObject *closure;
  783. #endif
  784.  
  785.     if (cx->interpLevel == MAX_INTERP_LEVEL) {
  786.     JS_ReportError(cx, "too much recursion");
  787.     return JS_FALSE;
  788.     }
  789.     cx->interpLevel++;
  790.     *result = JSVAL_VOID;
  791.     rt = cx->runtime;
  792.  
  793.     /*
  794.      * Set registerized frame pointer and derived script pointer.
  795.      */
  796.     fp = cx->fp;
  797.     script = fp->script;
  798.  
  799.     /*
  800.      * Prepare to call a user-supplied branch handler, and abort the script
  801.      * if it returns false.
  802.      */
  803.     onbranch = cx->branchCallback;
  804.     ok = JS_TRUE;
  805.     dropAtom = JS_FALSE;
  806. #define CHECK_BRANCH(len) {                                                   \
  807.     if (len < 0 && onbranch && !(ok = (*onbranch)(cx, script)))               \
  808.     goto out;                                                             \
  809. }
  810.  
  811.     /*
  812.      * Allocate operand and pc stack slots for the script's worst-case depth.
  813.      */
  814.     mark = PR_ARENA_MARK(&cx->stackPool);
  815.     depth = (ptrdiff_t)script->depth;
  816.     newsp = AllocStack(cx, (uintN)(2 * depth));
  817.     if (!newsp) {
  818.     ok = JS_FALSE;
  819.     goto out;
  820.     }
  821.     newsp += depth;
  822.     fp->sp = sp = newsp;
  823.  
  824. #ifdef JS_THREADSAFE
  825.     obj = NULL;
  826.     ok = JS_AddRoot(cx, &obj);
  827.     if (!ok)
  828.     goto out;
  829. #endif
  830.  
  831.     pc = script->code;
  832.     endpc = pc + script->length;
  833.  
  834.     while (pc < endpc) {
  835.     fp->pc = pc;
  836.     op = *pc;
  837.       do_op:
  838.     cs = &js_CodeSpec[op];
  839.     len = cs->length;
  840.  
  841. #ifdef DEBUG
  842.     tracefp = cx->tracefp;
  843.     if (tracefp) {
  844.         intN nuses, n;
  845.         jsval v;
  846.  
  847.         fprintf(tracefp, "%4u: ", js_PCToLineNumber(script, pc));
  848.         js_Disassemble1(cx, script, pc, pc - script->code, JS_FALSE,
  849.                 tracefp);
  850.         nuses = cs->nuses;
  851.         if (nuses) {
  852.         fp->sp = sp - nuses;
  853.         for (n = nuses; n > 0; n--) {
  854.             v = sp[-n];
  855.             if ((str = js_ValueToSource(cx, v)) != NULL) {
  856.             fprintf(tracefp, "%s %s",
  857.                 (n == nuses) ? "  inputs:" : ",",
  858.                 JS_GetStringBytes(str));
  859.             }
  860.         }
  861.         putc('\n', tracefp);
  862.         SAVE_SP(fp);
  863.         }
  864.     }
  865. #endif
  866.  
  867.     if (rt->interruptHandler) {
  868.         JSTrapHandler handler = (JSTrapHandler) rt->interruptHandler;
  869.  
  870.         switch (handler(cx, script, pc, &rval,
  871.                 rt->interruptHandlerData)) {
  872.           case JSTRAP_ERROR:
  873.         ok = JS_FALSE;
  874.         goto out;
  875.           case JSTRAP_CONTINUE:
  876.         break;
  877.           case JSTRAP_RETURN:
  878.         fp->rval = rval;
  879.         goto out;
  880.           default:;
  881.         }
  882.     }
  883.  
  884.     switch (op) {
  885.       case JSOP_NOP:
  886.         break;
  887.  
  888.       case JSOP_PUSH:
  889.         PUSH_OPND(JSVAL_VOID);
  890.         break;
  891.  
  892.       case JSOP_POP:
  893.         sp--;
  894.         break;
  895.  
  896.       case JSOP_POPV:
  897.         *result = POP();
  898.         break;
  899.  
  900.       case JSOP_ENTERWITH:
  901.         rval = POP();
  902.         VALUE_TO_OBJECT(cx, rval, obj);
  903.         withobj = js_NewObject(cx, &js_WithClass, obj, fp->scopeChain);
  904.         if (!withobj)
  905.         goto out;
  906.         fp->scopeChain = withobj;
  907.         PUSH(OBJECT_TO_JSVAL(withobj));
  908.         break;
  909.  
  910.       case JSOP_LEAVEWITH:
  911.         rval = POP();
  912.         PR_ASSERT(JSVAL_IS_OBJECT(rval));
  913.         withobj = JSVAL_TO_OBJECT(rval);
  914.         PR_ASSERT(withobj->map->clasp == &js_WithClass);
  915.  
  916.         rval = OBJ_GET_SLOT(withobj, JSSLOT_PARENT);
  917.         PR_ASSERT(JSVAL_IS_OBJECT(rval));
  918.         fp->scopeChain = JSVAL_TO_OBJECT(rval);
  919.         break;
  920.  
  921.       case JSOP_RETURN:
  922.         CHECK_BRANCH(-1);
  923.         fp->rval = POP();
  924.         goto out;
  925.  
  926.       case JSOP_GOTO:
  927.         len = GET_JUMP_OFFSET(pc);
  928.         CHECK_BRANCH(len);
  929.         break;
  930.  
  931.       case JSOP_IFEQ:
  932.         rval = POP();
  933.         VALUE_TO_BOOLEAN(cx, rval, cond);
  934.         if (cond == JS_FALSE) {
  935.         len = GET_JUMP_OFFSET(pc);
  936.         CHECK_BRANCH(len);
  937.         }
  938.         break;
  939.  
  940.       case JSOP_IFNE:
  941.         rval = POP();
  942.         VALUE_TO_BOOLEAN(cx, rval, cond);
  943.         if (cond != JS_FALSE) {
  944.         len = GET_JUMP_OFFSET(pc);
  945.         CHECK_BRANCH(len);
  946.         }
  947.         break;
  948.  
  949. #if !JS_BUG_SHORT_CIRCUIT
  950.       case JSOP_OR:
  951.         rval = POP();
  952.         VALUE_TO_BOOLEAN(cx, rval, cond);
  953.         if (cond == JS_TRUE) {
  954.         len = GET_JUMP_OFFSET(pc);
  955.         PUSH_OPND(rval);
  956.         }
  957.         break;
  958.  
  959.       case JSOP_AND:
  960.         rval = POP();
  961.         VALUE_TO_BOOLEAN(cx, rval, cond);
  962.         if (cond == JS_FALSE) {
  963.         len = GET_JUMP_OFFSET(pc);
  964.         PUSH_OPND(rval);
  965.         }
  966.         break;
  967. #endif
  968.  
  969.       case JSOP_FORNAME:
  970.         atom = GET_ATOM(cx, script, pc);
  971.         id   = (jsval)atom;
  972.         rval = POP();
  973.  
  974.         SAVE_SP(fp);
  975.         JS_LOCK_RUNTIME_VOID(rt, ok = js_FindVariable(cx, id, &obj, &prop));
  976.         if (!ok)
  977.         goto out;
  978.         PR_ASSERT(prop);
  979.         lval = OBJECT_TO_JSVAL(obj);
  980.         goto do_forinloop;
  981.  
  982.       case JSOP_FORPROP:
  983.         atom = GET_ATOM(cx, script, pc);
  984.         id   = (jsval)atom;
  985.         rval = POP();
  986.         lval = POP();
  987.         goto do_forinloop;
  988.  
  989. #define FIX_ELEMENT_ID(id) {                                                  \
  990.     /* If the index is other than a nonnegative int, atomize it. */           \
  991.     i = JSVAL_IS_INT(id) ? JSVAL_TO_INT(id) : -1;                             \
  992.     if (i < 0) {                                                              \
  993.     JS_LOCK_RUNTIME_VOID(rt, atom = js_ValueToStringAtom(cx, id));        \
  994.     if (!atom) {                                                          \
  995.         ok = JS_FALSE;                                                    \
  996.         goto out;                                                         \
  997.     }                                                                     \
  998.     id = (jsval)atom;                                                     \
  999.     dropAtom = JS_TRUE;                                                   \
  1000.     }                                                                         \
  1001. }
  1002.  
  1003.       case JSOP_FORELEM:
  1004.         rval = POP();
  1005.         id   = POP();
  1006.         lval = POP();
  1007.  
  1008.         /* If the index is other than a nonnegative int, atomize it. */
  1009.         FIX_ELEMENT_ID(id);
  1010.  
  1011.       do_forinloop:
  1012.         /* Lock the entire bytecode's critical section if threadsafe. */
  1013.         SAVE_SP(fp);
  1014.         JS_LOCK_RUNTIME(rt);
  1015.         ok = js_ValueToObject(cx, rval, &obj);
  1016.         if (!ok) {
  1017.         JS_UNLOCK_RUNTIME(rt);
  1018.         goto out;
  1019.         }
  1020.  
  1021.         /* If the thing to the right of 'in' has no properties, break. */
  1022.         if (!obj) {
  1023.         rval = JSVAL_FALSE;
  1024.         goto end_forinloop;
  1025.         }
  1026.  
  1027.         /*
  1028.          * Start from the shared scope object that owns the properties.
  1029.          * This means we won't visit properties added during the loop if
  1030.          * the nominal object was unmutated before the loop.  But call
  1031.          * enumerate first in case it mutates obj.
  1032.          */
  1033.         vp = sp - 1;
  1034.         if (JSVAL_IS_VOID(*vp)) {
  1035.         /* Let lazy reflectors be eager so for/in finds everything. */
  1036.         ok = obj->map->clasp->enumerate(cx, obj);
  1037.         if (!ok) {
  1038.             JS_UNLOCK_RUNTIME(rt);
  1039.             goto out;
  1040.         }
  1041.         }
  1042.         obj = ((JSScope *)obj->map)->object;
  1043.  
  1044.         /* Save obj as origobj to suppress prototype properties. */
  1045.         origobj = obj;
  1046.       do_forin_again:
  1047.         proto = JS_GetPrototype(cx, obj);
  1048.  
  1049.         /* Reach under top of stack to find our property iterator. */
  1050.         if (JSVAL_IS_VOID(*vp)) {
  1051.         prop = obj->map->props;
  1052.  
  1053.         /* Set the iterator to point to the first property. */
  1054.         propobj = js_NewObject(cx, &prop_iterator_class, NULL, NULL);
  1055.         if (!propobj) {
  1056.             JS_UNLOCK_RUNTIME(rt);
  1057.             ok = JS_FALSE;
  1058.             goto out;
  1059.         }
  1060.         OBJ_SET_SLOT(propobj, JSSLOT_PROP_OBJECT, OBJECT_TO_JSVAL(obj));
  1061.         OBJ_SET_SLOT(propobj, JSSLOT_PROP_NEXT, PRIVATE_TO_JSVAL(NULL));
  1062.  
  1063.         /* Rewrite the iterator so we know to do the next case. */
  1064.         *vp = OBJECT_TO_JSVAL(propobj);
  1065.         } else {
  1066.         /* Use the iterator to find the next property. */
  1067.         propobj = JSVAL_TO_OBJECT(*vp);
  1068.         rval = OBJ_GET_SLOT(propobj, JSSLOT_PROP_NEXT);
  1069.         prop = JSVAL_TO_PRIVATE(rval);
  1070.  
  1071.         rval = OBJ_GET_SLOT(propobj, JSSLOT_PROP_OBJECT);
  1072.         iterobj = JSVAL_TO_OBJECT(rval);
  1073.  
  1074.         /* If we're enumerating a prototype, reset obj and prototype. */
  1075.         if (obj != iterobj) {
  1076.             obj = iterobj;
  1077.             proto = JS_GetPrototype(cx, obj);
  1078.         }
  1079.         PR_ASSERT(!prop || prop->object == obj);
  1080.         }
  1081.  
  1082.         /* Skip deleted and predefined/hidden properties. */
  1083.         while (prop) {
  1084.         if (prop->symbols && (prop->flags & JSPROP_ENUMERATE)) {
  1085.             /* Have we already enumerated a clone of this property? */
  1086.             ok = js_LookupProperty(cx, origobj,
  1087.                        sym_id(prop->symbols), NULL,
  1088.                        &prop2);
  1089.             if (!ok) {
  1090.             JS_UNLOCK_RUNTIME(rt);
  1091.             goto out;
  1092.             }
  1093.             if (prop2 == prop) {
  1094.             /* No, go ahead and enumerate it. */
  1095.             break;
  1096.             }
  1097.         }
  1098.         prop = prop->next;
  1099.         }
  1100.  
  1101.         if (!prop) {
  1102.         /* Enumerate prototype properties, if there are any. */
  1103.         if (proto) {
  1104.             obj = proto;
  1105.             OBJ_SET_SLOT(propobj, JSSLOT_PROP_OBJECT,
  1106.                  OBJECT_TO_JSVAL(obj));
  1107.             rval = OBJ_GET_SLOT(propobj, JSSLOT_PROP_NEXT);
  1108.             prop = JSVAL_TO_PRIVATE(rval);
  1109.             if (prop)
  1110.             js_DropProperty(cx, prop);
  1111.             prop = obj->map->props;
  1112.             OBJ_SET_SLOT(propobj, JSSLOT_PROP_NEXT,
  1113.                  PRIVATE_TO_JSVAL(prop));
  1114.             js_HoldProperty(cx, prop);
  1115.             goto do_forin_again;
  1116.         }
  1117.  
  1118.         /* End of property list -- terminate this loop. */
  1119.         rval = JSVAL_FALSE;
  1120.         goto end_forinloop;
  1121.         }
  1122.  
  1123.         /* Advance the iterator to the next property (or null). */
  1124.         rval = OBJ_GET_SLOT(propobj, JSSLOT_PROP_NEXT);
  1125.         prop2 = JSVAL_TO_PRIVATE(rval);
  1126.         if (prop2)
  1127.         js_DropProperty(cx, prop2);
  1128.         prop2 = prop->next;
  1129.         OBJ_SET_SLOT(propobj, JSSLOT_PROP_NEXT, PRIVATE_TO_JSVAL(prop2));
  1130.         if (!ok) {
  1131.         JS_UNLOCK_RUNTIME(rt);
  1132.         goto out;
  1133.         }
  1134.         js_HoldProperty(cx, prop2);
  1135.  
  1136.         /* Get the int- or string-valued property name into rval. */
  1137.         rval = js_IdToValue(sym_id(prop->symbols));
  1138.  
  1139.         /* Convert lval to a non-null object containing id. */
  1140.         VALUE_TO_OBJECT(cx, lval, obj);
  1141.  
  1142.         /* Make sure rval is a string for uniformity and compatibility. */
  1143.         if (cx->version < JSVERSION_1_2 && JSVAL_IS_INT(rval)) {
  1144.         str = js_NumberToString(cx, (jsdouble) JSVAL_TO_INT(rval));
  1145.         if (!str) {
  1146.             JS_UNLOCK_RUNTIME(rt);
  1147.             ok = JS_FALSE;
  1148.             goto out;
  1149.         }
  1150.  
  1151.         /* Hold via sp[0] in case the GC runs under js_SetProperty. */
  1152.         rval = sp[0] = STRING_TO_JSVAL(str);
  1153.         }
  1154.  
  1155.         /* Set the variable obj[id] to refer to rval. */
  1156.         prop = js_SetProperty(cx, obj, id, &rval);
  1157.         if (!prop) {
  1158.         JS_UNLOCK_RUNTIME(rt);
  1159.         ok = JS_FALSE;
  1160.         goto out;
  1161.         }
  1162.  
  1163.         /* Push true to keep looping through properties. */
  1164.         rval = JSVAL_TRUE;
  1165.  
  1166.       end_forinloop:
  1167.         if (dropAtom) {
  1168.         js_DropAtom(cx, atom);
  1169.         dropAtom = JS_FALSE;
  1170.         }
  1171.         JS_UNLOCK_RUNTIME(rt);
  1172.         PUSH_OPND(rval);
  1173.         break;
  1174.  
  1175.       case JSOP_DUP:
  1176.         PR_ASSERT(sp > newsp);
  1177.         rval = sp[-1];
  1178.         PUSH_OPND(rval);
  1179.         break;
  1180.  
  1181.       case JSOP_DUP2:
  1182.         PR_ASSERT(sp - 1 > newsp);
  1183.         lval = sp[-2];
  1184.         rval = sp[-1];
  1185.         PUSH_OPND(lval);
  1186.         PUSH_OPND(rval);
  1187.         break;
  1188.  
  1189. #define PROPERTY_OP(call, result) {                                           \
  1190.     /* Pop the left part and resolve it to a non-null object. */              \
  1191.     lval = POP();                                                             \
  1192.     VALUE_TO_OBJECT(cx, lval, obj);                                           \
  1193.                                           \
  1194.     /* Get or set the property, set result zero if error, non-zero if ok. */  \
  1195.     JS_LOCK_RUNTIME(rt);                                                      \
  1196.     call;                                                                     \
  1197.     JS_UNLOCK_RUNTIME(rt);                                                    \
  1198.     if (!result) {                                                            \
  1199.     ok = JS_FALSE;                                                        \
  1200.     goto out;                                                             \
  1201.     }                                                                         \
  1202. }
  1203.  
  1204. #define ELEMENT_OP(call, result) {                                            \
  1205.     id = POP();                                                               \
  1206.     FIX_ELEMENT_ID(id);                                                       \
  1207.     PROPERTY_OP(call, result);                                                \
  1208.     if (dropAtom) {                                                           \
  1209.     JS_LOCK_RUNTIME_VOID(rt, js_DropAtom(cx, atom));                      \
  1210.     dropAtom = JS_FALSE;                                                  \
  1211.     }                                                                         \
  1212. }
  1213.  
  1214. #define CACHED_GET(call) {                                                    \
  1215.     PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, prop);                   \
  1216.     if (PROP_FOUND(prop)) {                                                   \
  1217.     obj2 = prop->object;                                                  \
  1218.     slot = (uintN)prop->slot;                                             \
  1219.     rval = obj2->slots[slot];                                             \
  1220.     ok = prop->getter(cx, obj, prop->id, &rval);                          \
  1221.     if (ok)                                                               \
  1222.         obj2->slots[slot] = rval;                                         \
  1223.     else                                                                  \
  1224.         prop = NULL;                                                      \
  1225.     } else {                                                                  \
  1226.     SAVE_SP(fp);                                                          \
  1227.     prop = call;                                                          \
  1228.     if (prop)                                                             \
  1229.         PROPERTY_CACHE_FILL(cx, &rt->propertyCache, obj, id, prop);       \
  1230.     }                                                                         \
  1231. }
  1232.  
  1233. #define CACHED_SET(call) {                                                    \
  1234.     PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, prop);                   \
  1235.     if (PROP_FOUND(prop) &&                                                   \
  1236.     !(prop->flags & (JSPROP_READONLY | JSPROP_ASSIGNHACK))) {             \
  1237.     ok = prop->setter(cx, obj, prop->id, &rval);                          \
  1238.     if (ok) {                                                             \
  1239.         prop->flags |= JSPROP_ENUMERATE;                                  \
  1240.         prop->object->slots[prop->slot] = rval;                           \
  1241.     } else {                                                              \
  1242.         prop = NULL;                                                      \
  1243.     }                                                                     \
  1244.     } else {                                                                  \
  1245.     SAVE_SP(fp);                                                          \
  1246.     prop = call;                                                          \
  1247.     /* No fill here: js_SetProperty writes through the cache. */          \
  1248.     }                                                                         \
  1249. }
  1250.  
  1251.       case JSOP_SETNAME:
  1252.         /* Get an immediate atom naming the variable to set. */
  1253.         atom = GET_ATOM(cx, script, pc);
  1254.         id   = (jsval)atom;
  1255.  
  1256.         SAVE_SP(fp);
  1257.         JS_LOCK_RUNTIME(rt);
  1258.         ok = js_FindVariable(cx, id, &obj, &prop);
  1259.         if (!ok) {
  1260.         JS_UNLOCK_RUNTIME(rt);
  1261.         goto out;
  1262.         }
  1263.  
  1264.         /* Pop the right-hand side and set obj[id] to it. */
  1265.         rval = POP();
  1266.  
  1267.         /* Try to hit the property cache, FindVariable primes it. */
  1268.         CACHED_SET(js_SetProperty(cx, obj, id, &rval));
  1269.         if (!prop) {
  1270.         JS_UNLOCK_RUNTIME(rt);
  1271.         ok = JS_FALSE;
  1272.         goto out;
  1273.         }
  1274.  
  1275.         /* Push the right-hand side as our result. */
  1276.         PUSH_OPND(rval);
  1277.  
  1278.         /* Quicken this bytecode if possible. */
  1279.         if (obj == fp->scopeChain &&
  1280.         prop && (prop->flags & JSPROP_PERMANENT)) {
  1281.         if (prop->setter == js_SetArgument) {
  1282.             js_PatchOpcode(cx, script, pc, JSOP_SETARG);
  1283.             slot = (uintN)JSVAL_TO_INT(prop->id);
  1284.             SET_ARGNO(pc, slot);
  1285.         } else if (prop->setter == js_SetLocalVariable) {
  1286.             js_PatchOpcode(cx, script, pc, JSOP_SETVAR);
  1287.             slot = (uintN)JSVAL_TO_INT(prop->id);
  1288.             SET_VARNO(pc, slot);
  1289.         }
  1290.         }
  1291.  
  1292.         JS_UNLOCK_RUNTIME(rt);
  1293.         break;
  1294.  
  1295. #define INTEGER_OP(OP, EXTRA_CODE, LEFT_CAST) {                               \
  1296.     valid = JS_TRUE;                                                          \
  1297.     SAVE_SP(fp);                                                              \
  1298.     ok = PopInt(cx, &j, &valid) && PopInt(cx, &i, &valid);                    \
  1299.     RESTORE_SP(fp);                                                           \
  1300.     if (!ok)                                                                  \
  1301.     goto out;                                                             \
  1302.     EXTRA_CODE                                                                \
  1303.     if (!valid) {                                                             \
  1304.     PUSH_OPND(DOUBLE_TO_JSVAL(rt->jsNaN));                                \
  1305.     } else {                                                                  \
  1306.     i = LEFT_CAST i OP j;                                                 \
  1307.     PUSH_NUMBER(cx, i);                                                   \
  1308.     }                                                                         \
  1309. }
  1310.  
  1311. #define BITWISE_OP(OP)        INTEGER_OP(OP, (void) 0;, (jsint))
  1312. #define SIGNED_SHIFT_OP(OP)    INTEGER_OP(OP, j &= 31;, (jsint))
  1313. #define UNSIGNED_SHIFT_OP(OP)    INTEGER_OP(OP, j &= 31;, (jsuint))
  1314.  
  1315.       case JSOP_BITOR:
  1316.         BITWISE_OP(|);
  1317.         break;
  1318.  
  1319.       case JSOP_BITXOR:
  1320.         BITWISE_OP(^);
  1321.         break;
  1322.  
  1323.       case JSOP_BITAND:
  1324.         BITWISE_OP(&);
  1325.         break;
  1326.  
  1327. #ifdef XP_PC
  1328. #define COMPARE_DOUBLES(LVAL, OP, RVAL, IFNAN)                                \
  1329.     ((JSDOUBLE_IS_NaN(LVAL) || JSDOUBLE_IS_NaN(RVAL))                         \
  1330.      ? (IFNAN)                                                                \
  1331.      : (LVAL) OP (RVAL))
  1332. #else
  1333. #define COMPARE_DOUBLES(LVAL, OP, RVAL, IFNAN) ((LVAL) OP (RVAL))
  1334. #endif
  1335.  
  1336. #define RELATIONAL_OP(OP) {                                                   \
  1337.     rval = POP();                                                             \
  1338.     lval = POP();                                                             \
  1339.     /* Optimize for two int-tagged operands (typical loop control). */        \
  1340.     if ((lval & rval) & JSVAL_INT) {                                          \
  1341.     ltmp = lval ^ JSVAL_VOID;                                             \
  1342.     rtmp = rval ^ JSVAL_VOID;                                             \
  1343.     if (ltmp && rtmp) {                                                   \
  1344.         cond = JSVAL_TO_INT(lval) OP JSVAL_TO_INT(rval);                  \
  1345.     } else {                                                              \
  1346.         d  = ltmp ? *rt->jsNaN : JSVAL_TO_INT(lval);                      \
  1347.         d2 = rtmp ? *rt->jsNaN : JSVAL_TO_INT(rval);                      \
  1348.         cond = COMPARE_DOUBLES(d, OP, d2, JS_FALSE);                      \
  1349.     }                                                                     \
  1350.     } else {                                                                  \
  1351.     ltmp = lval, rtmp = rval;                                             \
  1352.     VALUE_TO_PRIMITIVE(cx, lval, &lval);                                  \
  1353.     VALUE_TO_PRIMITIVE(cx, rval, &rval);                                  \
  1354.     if (JSVAL_IS_STRING(lval) && JSVAL_IS_STRING(rval)) {                 \
  1355.         str  = JSVAL_TO_STRING(lval);                                     \
  1356.         str2 = JSVAL_TO_STRING(rval);                                     \
  1357.         cond = js_CompareStrings(str, str2) OP 0;                         \
  1358.     } else {                                                              \
  1359.         VALUE_TO_NUMBER(cx, ltmp, d);                                     \
  1360.         VALUE_TO_NUMBER(cx, rtmp, d2);                                    \
  1361.         cond = COMPARE_DOUBLES(d, OP, d2, JS_FALSE);                      \
  1362.     }                                                                     \
  1363.     }                                                                         \
  1364.     PUSH_OPND(BOOLEAN_TO_JSVAL(cond));                                        \
  1365. }
  1366.  
  1367. #define EQUALITY_OP(OP, IFNAN) {                                              \
  1368.     rval = POP();                                                             \
  1369.     lval = POP();                                                             \
  1370.     ltmp = JSVAL_TAG(lval);                                                   \
  1371.     rtmp = JSVAL_TAG(rval);                                                   \
  1372.     if (ltmp == rtmp) {                                                       \
  1373.     if (ltmp == JSVAL_STRING) {                                           \
  1374.         str  = JSVAL_TO_STRING(lval);                                     \
  1375.         str2 = JSVAL_TO_STRING(rval);                                     \
  1376.         cond = js_CompareStrings(str, str2) OP 0;                         \
  1377.     } else if (ltmp == JSVAL_DOUBLE) {                                    \
  1378.         d  = *JSVAL_TO_DOUBLE(lval);                                      \
  1379.         d2 = *JSVAL_TO_DOUBLE(rval);                                      \
  1380.         cond = COMPARE_DOUBLES(d, OP, d2, IFNAN);                         \
  1381.     } else {                                                              \
  1382.         /* Handle all undefined (=>NaN) and int combinations. */          \
  1383.         cond = lval OP rval;                                              \
  1384.     }                                                                     \
  1385.     } else {                                                                  \
  1386.     if (JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval)) {                     \
  1387.         cond = (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) OP 1;         \
  1388.     } else if (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) {              \
  1389.         cond = 1 OP 0;                                                    \
  1390.     } else {                                                              \
  1391.         ltmp = lval, rtmp = rval;                                         \
  1392.         VALUE_TO_PRIMITIVE(cx, lval, &lval);                              \
  1393.         VALUE_TO_PRIMITIVE(cx, rval, &rval);                              \
  1394.         if (JSVAL_IS_STRING(lval) && JSVAL_IS_STRING(rval)) {             \
  1395.         str  = JSVAL_TO_STRING(lval);                                 \
  1396.         str2 = JSVAL_TO_STRING(rval);                                 \
  1397.         cond = js_CompareStrings(str, str2) OP 0;                     \
  1398.         } else {                                                          \
  1399.         VALUE_TO_NUMBER(cx, ltmp, d);                                 \
  1400.         VALUE_TO_NUMBER(cx, rtmp, d2);                                \
  1401.         cond = COMPARE_DOUBLES(d, OP, d2, IFNAN);                     \
  1402.         }                                                                 \
  1403.     }                                                                     \
  1404.     }                                                                         \
  1405.     PUSH_OPND(BOOLEAN_TO_JSVAL(cond));                                        \
  1406. }
  1407.  
  1408.       case JSOP_EQ:
  1409.         EQUALITY_OP(==, JS_FALSE);
  1410.         break;
  1411.  
  1412.       case JSOP_NE:
  1413.         EQUALITY_OP(!=, JS_TRUE);
  1414.         break;
  1415.  
  1416. #if !JS_BUG_FALLIBLE_EQOPS
  1417. #define NEW_EQUALITY_OP(OP, IFNAN) {                                          \
  1418.     rval = POP();                                                             \
  1419.     lval = POP();                                                             \
  1420.     ltmp = JSVAL_TAG(lval);                                                   \
  1421.     rtmp = JSVAL_TAG(rval);                                                   \
  1422.     if (ltmp == rtmp) {                                                       \
  1423.     if (ltmp == JSVAL_STRING) {                                           \
  1424.         str  = JSVAL_TO_STRING(lval);                                     \
  1425.         str2 = JSVAL_TO_STRING(rval);                                     \
  1426.         cond = js_CompareStrings(str, str2) OP 0;                         \
  1427.     } else if (ltmp == JSVAL_DOUBLE) {                                    \
  1428.         d  = *JSVAL_TO_DOUBLE(lval);                                      \
  1429.         d2 = *JSVAL_TO_DOUBLE(rval);                                      \
  1430.         cond = COMPARE_DOUBLES(d, OP, d2, IFNAN);                         \
  1431.     } else {                                                              \
  1432.         cond = lval OP rval;                                              \
  1433.     }                                                                     \
  1434.     } else {                                                                  \
  1435.     if (ltmp == JSVAL_DOUBLE && JSVAL_IS_INT(rval)) {                     \
  1436.         d  = *JSVAL_TO_DOUBLE(lval);                                      \
  1437.         d2 = JSVAL_TO_INT(rval);                                          \
  1438.         cond = COMPARE_DOUBLES(d, OP, d2, IFNAN);                         \
  1439.     } else if (JSVAL_IS_INT(lval) && rtmp == JSVAL_DOUBLE) {              \
  1440.         d  = JSVAL_TO_INT(lval);                                          \
  1441.         d2 = *JSVAL_TO_DOUBLE(rval);                                      \
  1442.         cond = COMPARE_DOUBLES(d, OP, d2, IFNAN);                         \
  1443.     } else {                                                              \
  1444.         cond = lval OP rval;                                              \
  1445.     }                                                                     \
  1446.     }                                                                         \
  1447.     PUSH_OPND(BOOLEAN_TO_JSVAL(cond));                                        \
  1448. }
  1449.  
  1450.       case JSOP_NEW_EQ:
  1451.         NEW_EQUALITY_OP(==, JS_FALSE);
  1452.         break;
  1453.  
  1454.       case JSOP_NEW_NE:
  1455.         NEW_EQUALITY_OP(!=, JS_TRUE);
  1456.         break;
  1457. #endif /* !JS_BUG_FALLIBLE_EQOPS */
  1458.  
  1459.       case JSOP_LT:
  1460.         RELATIONAL_OP(<);
  1461.         break;
  1462.  
  1463.       case JSOP_LE:
  1464.         RELATIONAL_OP(<=);
  1465.         break;
  1466.  
  1467.       case JSOP_GT:
  1468.         RELATIONAL_OP(>);
  1469.         break;
  1470.  
  1471.       case JSOP_GE:
  1472.         RELATIONAL_OP(>=);
  1473.         break;
  1474.  
  1475. #undef EQUALITY_OP
  1476. #undef RELATIONAL_OP
  1477.  
  1478.       case JSOP_LSH:
  1479.         SIGNED_SHIFT_OP(<<);
  1480.         break;
  1481.  
  1482.       case JSOP_RSH:
  1483.         SIGNED_SHIFT_OP(>>);
  1484.         break;
  1485.  
  1486.       case JSOP_URSH:
  1487.         UNSIGNED_SHIFT_OP(>>);
  1488.         break;
  1489.  
  1490. #undef INTEGER_OP
  1491. #undef BITWISE_OP
  1492. #undef SIGNED_SHIFT_OP
  1493. #undef UNSIGNED_SHIFT_OP
  1494.  
  1495.       case JSOP_ADD:
  1496.         rval = rtmp = POP();
  1497.         lval = ltmp = POP();
  1498.         VALUE_TO_PRIMITIVE(cx, lval, &lval);
  1499.         VALUE_TO_PRIMITIVE(cx, rval, &rval);
  1500.         if ((cond = JSVAL_IS_STRING(lval)) || JSVAL_IS_STRING(rval)) {
  1501.         if (cond) {
  1502.             /* Keep a ref to str on the stack so it isn't GC'd. */
  1503.             str = JSVAL_TO_STRING(lval);
  1504.             PUSH(STRING_TO_JSVAL(str));
  1505.             SAVE_SP(fp);
  1506.             ok = (str2 = JS_ValueToString(cx, rval)) != 0;
  1507.             (void) POP();
  1508.         } else {
  1509.             /* Keep a ref to str2 on the stack so it isn't GC'd. */
  1510.             str2 = JSVAL_TO_STRING(rval);
  1511.             PUSH(STRING_TO_JSVAL(str2));
  1512.             SAVE_SP(fp);
  1513.             ok = (str = JS_ValueToString(cx, lval)) != 0;
  1514.             (void) POP();
  1515.         }
  1516.         if (!ok)
  1517.             goto out;
  1518.         if ((length = str->length) == 0) {
  1519.             str3 = str2;
  1520.         } else if ((length2 = str2->length) == 0) {
  1521.             str3 = str;
  1522.         } else {
  1523.             length3 = length + length2;
  1524.             chars = JS_malloc(cx, (length3 + 1) * sizeof(jschar));
  1525.             if (!chars) {
  1526.             ok = JS_FALSE;
  1527.             goto out;
  1528.             }
  1529.             js_strncpy(chars, str->chars, length);
  1530.             js_strncpy(chars + length, str2->chars, length2);
  1531.             chars[length3] = 0;
  1532.             str3 = js_NewString(cx, chars, length3, 0);
  1533.             if (!str3) {
  1534.             JS_free(cx, chars);
  1535.             ok = JS_FALSE;
  1536.             goto out;
  1537.             }
  1538.         }
  1539.         PUSH_OPND(STRING_TO_JSVAL(str3));
  1540.         } else {
  1541.         VALUE_TO_NUMBER(cx, ltmp, d);
  1542.         VALUE_TO_NUMBER(cx, rtmp, d2);
  1543.         d += d2;
  1544.         PUSH_NUMBER(cx, d);
  1545.         }
  1546.         break;
  1547.  
  1548. #define BINARY_OP(OP) {                                                       \
  1549.     POP_NUMBER(cx, d2);                                                       \
  1550.     POP_NUMBER(cx, d);                                                        \
  1551.     d = d OP d2;                                                              \
  1552.     PUSH_NUMBER(cx, d);                                                       \
  1553. }
  1554.  
  1555.       case JSOP_SUB:
  1556.         BINARY_OP(-);
  1557.         break;
  1558.  
  1559.       case JSOP_MUL:
  1560.         BINARY_OP(*);
  1561.         break;
  1562.  
  1563.       case JSOP_DIV:
  1564.         POP_NUMBER(cx, d2);
  1565.         POP_NUMBER(cx, d);
  1566.         if (d2 == 0) {
  1567.         if (d == 0 || JSDOUBLE_IS_NaN(d))
  1568.             rval = DOUBLE_TO_JSVAL(rt->jsNaN);
  1569.         else if ((JSDOUBLE_HI32(d) ^ JSDOUBLE_HI32(d2)) >> 31)
  1570.             rval = DOUBLE_TO_JSVAL(rt->jsNegativeInfinity);
  1571.         else
  1572.             rval = DOUBLE_TO_JSVAL(rt->jsPositiveInfinity);
  1573.         PUSH_OPND(rval);
  1574.         } else {
  1575.         d /= d2;
  1576.         PUSH_NUMBER(cx, d);
  1577.         }
  1578.         break;
  1579.  
  1580.       case JSOP_MOD:
  1581.         POP_NUMBER(cx, d2);
  1582.         POP_NUMBER(cx, d);
  1583.         if (d2 == 0) {
  1584.         PUSH_OPND(DOUBLE_TO_JSVAL(rt->jsNaN));
  1585.         } else {
  1586. #ifdef XP_PC
  1587.           /* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
  1588.           if (!(JSDOUBLE_IS_FINITE(d) && JSDOUBLE_IS_INFINITE(d2)))
  1589. #endif
  1590.         d = fmod(d, d2);
  1591.         PUSH_NUMBER(cx, d);
  1592.         }
  1593.         break;
  1594.  
  1595.       case JSOP_NOT:
  1596.         rval = POP();
  1597.         VALUE_TO_BOOLEAN(cx, rval, cond);
  1598.         PUSH_OPND(BOOLEAN_TO_JSVAL(!cond));
  1599.         break;
  1600.  
  1601.       case JSOP_BITNOT:
  1602.         valid = JS_TRUE;
  1603.         SAVE_SP(fp);
  1604.         ok = PopInt(cx, &i, &valid);
  1605.         RESTORE_SP(fp);
  1606.         if (!ok)
  1607.         goto out;
  1608.         if (!valid) {
  1609.         PUSH_OPND(DOUBLE_TO_JSVAL(rt->jsNaN));
  1610.         } else {
  1611.         i = ~i;
  1612.         PUSH_NUMBER(cx, i);
  1613.         }
  1614.         break;
  1615.  
  1616.       case JSOP_NEG:
  1617.         POP_NUMBER(cx, d);
  1618.         d = -d;
  1619.         PUSH_NUMBER(cx, d);
  1620.         break;
  1621.  
  1622.       case JSOP_POS:
  1623.         POP_NUMBER(cx, d);
  1624.         PUSH_NUMBER(cx, d);
  1625.         break;
  1626.  
  1627.       case JSOP_NEW:
  1628.         /* Get immediate argc and find the constructor function. */
  1629.         argc = GET_ARGC(pc);
  1630.  
  1631.       do_new:
  1632.         vp = sp - (2 + argc);
  1633.         PR_ASSERT(vp >= newsp);
  1634.  
  1635.         /* Reset fp->sp so error reports decompile *vp's generator. */
  1636.         fp->sp = vp;
  1637.         JS_LOCK_RUNTIME(rt);
  1638.         fun = js_ValueToFunction(cx, *vp);
  1639.         if (!fun) {
  1640.         JS_UNLOCK_RUNTIME(rt);
  1641.         ok = JS_FALSE;
  1642.         goto out;
  1643.         }
  1644.  
  1645.         /* Get the constructor prototype object for this function. */
  1646.         prop = js_GetProperty(cx, fun->object,
  1647.                   (jsval)rt->atomState.classPrototypeAtom,
  1648.                   &rval);
  1649.         if (!prop) {
  1650.         JS_UNLOCK_RUNTIME(rt);
  1651.         ok = JS_FALSE;
  1652.         goto out;
  1653.         }
  1654.         proto = JSVAL_IS_OBJECT(rval) ? JSVAL_TO_OBJECT(rval) : NULL;
  1655.         parent = OBJ_GET_PARENT(fun->object);
  1656.  
  1657.         /* If there is no class prototype, use js_ObjectClass. */
  1658.         if (!proto)
  1659.         obj = js_NewObject(cx, &js_ObjectClass, NULL, parent);
  1660.         else
  1661.         obj = js_NewObject(cx, proto->map->clasp, proto, parent);
  1662.         JS_UNLOCK_RUNTIME(rt);
  1663.         if (!obj) {
  1664.         ok = JS_FALSE;
  1665.         goto out;
  1666.         }
  1667.  
  1668.         /* Now we have an object with a constructor method; call it. */
  1669.         vp[1] = OBJECT_TO_JSVAL(obj);
  1670.         SAVE_SP(fp);
  1671.         ok = js_DoCall(cx, argc);
  1672.         RESTORE_SP(fp);
  1673.         if (!ok) {
  1674.         cx->newborn[GCX_OBJECT] = NULL;
  1675.         goto out;
  1676.         }
  1677.  
  1678.         /* Check the return value and see if it does not refer to obj. */
  1679.         rval = *vp;
  1680.         if (!JSVAL_IS_OBJECT(rval)) {
  1681.         *vp = OBJECT_TO_JSVAL(obj);
  1682.         } else {
  1683.         obj2 = JSVAL_TO_OBJECT(rval);
  1684.         if (obj2 != obj)
  1685.             obj = obj2;
  1686.         }
  1687.         break;
  1688.  
  1689.       case JSOP_DELNAME:
  1690.         atom = GET_ATOM(cx, script, pc);
  1691.         id   = (jsval)atom;
  1692.  
  1693.         JS_LOCK_RUNTIME(rt);
  1694.         ok = js_FindProperty(cx, id, &obj, &prop);
  1695.         if (ok && prop) {
  1696.         /* Call js_DeleteProperty2 to avoid id re-lookup. */
  1697.         ok = js_DeleteProperty2(cx, obj, prop, id, &rval);
  1698.         }
  1699.         JS_UNLOCK_RUNTIME(rt);
  1700.         if (!ok)
  1701.         goto out;
  1702.         PUSH_OPND(rval);
  1703.         break;
  1704.  
  1705.       case JSOP_DELPROP:
  1706.         atom = GET_ATOM(cx, script, pc);
  1707.         id   = (jsval)atom;
  1708.         SAVE_SP(fp);
  1709.         PROPERTY_OP(ok = js_DeleteProperty(cx, obj, id, &rval), ok);
  1710.         PUSH_OPND(rval);
  1711.         break;
  1712.  
  1713.       case JSOP_DELELEM:
  1714.         SAVE_SP(fp);
  1715.         ELEMENT_OP(ok = js_DeleteProperty(cx, obj, id, &rval), ok);
  1716.         PUSH_OPND(rval);
  1717.         break;
  1718.  
  1719.       case JSOP_TYPEOF:
  1720.         rval = POP();
  1721.         type = JS_TypeOfValue(cx, rval);
  1722.         atom = rt->atomState.typeAtoms[type];
  1723.         str  = ATOM_TO_STRING(atom);
  1724.         PUSH_OPND(STRING_TO_JSVAL(str));
  1725.         break;
  1726.  
  1727.       case JSOP_VOID:
  1728.         (void) POP();
  1729.         PUSH_OPND(JSVAL_VOID);
  1730.         break;
  1731.  
  1732.       case JSOP_INCNAME:
  1733.       case JSOP_DECNAME:
  1734.       case JSOP_NAMEINC:
  1735.       case JSOP_NAMEDEC:
  1736.         atom = GET_ATOM(cx, script, pc);
  1737.         id   = (jsval)atom;
  1738.  
  1739.         SAVE_SP(fp);
  1740.         JS_LOCK_RUNTIME_VOID(rt, ok = js_FindVariable(cx, id, &obj, &prop));
  1741.         if (!ok)
  1742.         goto out;
  1743.  
  1744.         /* Quicken this bytecode if possible. */
  1745.         if (obj == fp->scopeChain && (prop->flags & JSPROP_PERMANENT)) {
  1746.         if (prop->setter == js_SetArgument) {
  1747.             js_PatchOpcode(cx, script, pc,
  1748.                    (cs->format & JOF_POST)
  1749.                    ? (cs->format & JOF_INC)
  1750.                      ? JSOP_ARGINC : JSOP_ARGDEC
  1751.                    : (cs->format & JOF_INC)
  1752.                      ? JSOP_INCARG : JSOP_DECARG);
  1753.             slot = (uintN)JSVAL_TO_INT(prop->id);
  1754.             SET_ARGNO(pc, slot);
  1755.             goto do_argincop;
  1756.         }
  1757.         if (prop->setter == js_SetLocalVariable) {
  1758.             js_PatchOpcode(cx, script, pc,
  1759.                    (cs->format & JOF_POST)
  1760.                    ? (cs->format & JOF_INC)
  1761.                      ? JSOP_VARINC : JSOP_VARDEC
  1762.                    : (cs->format & JOF_INC)
  1763.                      ? JSOP_INCVAR : JSOP_DECVAR);
  1764.             slot = (uintN)JSVAL_TO_INT(prop->id);
  1765.             SET_VARNO(pc, slot);
  1766.             goto do_varincop;
  1767.         }
  1768.         }
  1769.  
  1770.         lval = OBJECT_TO_JSVAL(obj);
  1771.         goto do_incop;
  1772.  
  1773.       case JSOP_INCPROP:
  1774.       case JSOP_DECPROP:
  1775.       case JSOP_PROPINC:
  1776.       case JSOP_PROPDEC:
  1777.         atom = GET_ATOM(cx, script, pc);
  1778.         id   = (jsval)atom;
  1779.         lval = POP();
  1780.         goto do_incop;
  1781.  
  1782.       case JSOP_INCELEM:
  1783.       case JSOP_DECELEM:
  1784.       case JSOP_ELEMINC:
  1785.       case JSOP_ELEMDEC:
  1786.         id   = POP();
  1787.         lval = POP();
  1788.  
  1789.         /* If the index is other than a nonnegative int, atomize it. */
  1790.         FIX_ELEMENT_ID(id);
  1791.  
  1792.       do_incop:
  1793.         VALUE_TO_OBJECT(cx, lval, obj);
  1794.  
  1795.         /* The operand must contain a number. */
  1796.         CACHED_GET(js_GetProperty(cx, obj, id, &rval));
  1797.         if (!prop) {
  1798.         ok = JS_FALSE;
  1799.         goto out;
  1800.         }
  1801.         VALUE_TO_NUMBER(cx, rval, d);
  1802.  
  1803.         /* Compute the post- or pre-incremented value. */
  1804.         if (cs->format & JOF_INC)
  1805.         d2 = (cs->format & JOF_POST) ? d++ : ++d;
  1806.         else
  1807.         d2 = (cs->format & JOF_POST) ? d-- : --d;
  1808.  
  1809.         /* Set obj[id] to the resulting number. */
  1810.         ok = js_NewNumberValue(cx, d, &rval);
  1811.         if (!ok)
  1812.         goto out;
  1813.         CACHED_SET(js_SetProperty(cx, obj, id, &rval));
  1814.         if (!prop) {
  1815.         ok = JS_FALSE;
  1816.         goto out;
  1817.         }
  1818.         if (dropAtom) {
  1819.         JS_LOCK_RUNTIME_VOID(rt, js_DropAtom(cx, atom));
  1820.         dropAtom = JS_FALSE;
  1821.         }
  1822.         PUSH_NUMBER(cx, d2);
  1823.         break;
  1824.  
  1825.       case JSOP_INCARG:
  1826.       case JSOP_DECARG:
  1827.       case JSOP_ARGINC:
  1828.       case JSOP_ARGDEC:
  1829.       do_argincop:
  1830.         slot = (uintN)GET_ARGNO(pc);
  1831.         PR_ASSERT(slot < fp->fun->nargs);
  1832.         rval = fp->argv[slot];
  1833.         VALUE_TO_NUMBER(cx, rval, d);
  1834.  
  1835.         /* Compute the post- or pre-incremented value. */
  1836.         if (cs->format & JOF_INC)
  1837.         d2 = (cs->format & JOF_POST) ? d++ : ++d;
  1838.         else
  1839.         d2 = (cs->format & JOF_POST) ? d-- : --d;
  1840.  
  1841.         ok = js_NewNumberValue(cx, d, &rval);
  1842.         if (!ok)
  1843.         goto out;
  1844.         fp->argv[slot] = rval;
  1845.         PUSH_NUMBER(cx, d2);
  1846.         break;
  1847.  
  1848.       case JSOP_INCVAR:
  1849.       case JSOP_DECVAR:
  1850.       case JSOP_VARINC:
  1851.       case JSOP_VARDEC:
  1852.       do_varincop:
  1853.         slot = (uintN)GET_VARNO(pc);
  1854.         PR_ASSERT(slot < fp->fun->nvars);
  1855.         rval = fp->vars[slot];
  1856.         VALUE_TO_NUMBER(cx, rval, d);
  1857.  
  1858.         /* Compute the post- or pre-incremented value. */
  1859.         if (cs->format & JOF_INC)
  1860.         d2 = (cs->format & JOF_POST) ? d++ : ++d;
  1861.         else
  1862.         d2 = (cs->format & JOF_POST) ? d-- : --d;
  1863.  
  1864.         ok = js_NewNumberValue(cx, d, &rval);
  1865.         if (!ok)
  1866.         goto out;
  1867.         fp->vars[slot] = rval;
  1868.         PUSH_NUMBER(cx, d2);
  1869.         break;
  1870.  
  1871.       case JSOP_GETPROP:
  1872.         /* Get an immediate atom naming the property. */
  1873.         atom = GET_ATOM(cx, script, pc);
  1874.         id   = (jsval)atom;
  1875.         PROPERTY_OP(CACHED_GET(js_GetProperty(cx, obj, id, &rval)),
  1876.             prop);
  1877.         PUSH_OPND(rval);
  1878.         break;
  1879.  
  1880.       case JSOP_SETPROP:
  1881.         /* Pop the right-hand side into rval for js_SetProperty. */
  1882.         rval = POP();
  1883.  
  1884.         /* Get an immediate atom naming the property. */
  1885.         atom = GET_ATOM(cx, script, pc);
  1886.         id   = (jsval)atom;
  1887.         PROPERTY_OP(CACHED_SET(js_SetProperty(cx, obj, id, &rval)),
  1888.             prop);
  1889.         PUSH_OPND(rval);
  1890.         break;
  1891.  
  1892.       case JSOP_GETELEM:
  1893.         ELEMENT_OP(CACHED_GET(js_GetProperty(cx, obj, id, &rval)),
  1894.                prop);
  1895.         PUSH_OPND(rval);
  1896.         break;
  1897.  
  1898.       case JSOP_SETELEM:
  1899.         rval = POP();
  1900.         ELEMENT_OP(CACHED_SET(js_SetProperty(cx, obj, id, &rval)),
  1901.                prop);
  1902.         PUSH_OPND(rval);
  1903.         break;
  1904.  
  1905.       case JSOP_PUSHOBJ:
  1906.         PUSH_OPND(OBJECT_TO_JSVAL(obj));
  1907.         break;
  1908.  
  1909.       case JSOP_CALL:
  1910.         argc = GET_ARGC(pc);
  1911.         SAVE_SP(fp);
  1912.         ok = js_DoCall(cx, argc);
  1913.         RESTORE_SP(fp);
  1914.         if (!ok)
  1915.         goto out;
  1916.         break;
  1917.  
  1918.       case JSOP_NAME:
  1919.         atom = GET_ATOM(cx, script, pc);
  1920.         id   = (jsval)atom;
  1921.  
  1922.         JS_LOCK_RUNTIME(rt);
  1923.         ok = js_FindProperty(cx, id, &obj, &prop);
  1924.         if (!ok) {
  1925.         JS_UNLOCK_RUNTIME(rt);
  1926.         goto out;
  1927.         }
  1928.         if (!prop) {
  1929.         /* Kludge to allow (typeof foo == "undefined") tests. */
  1930.         for (pc2 = pc + len; pc2 < endpc; pc2++) {
  1931.             op2 = (JSOp)*pc2;
  1932.             if (op2 == JSOP_TYPEOF) {
  1933.             JS_UNLOCK_RUNTIME(rt);
  1934.             PUSH_OPND(JSVAL_VOID);
  1935.             goto advance_pc;
  1936.             }
  1937.             if (op2 != JSOP_NOP)
  1938.             break;
  1939.         }
  1940.         JS_UNLOCK_RUNTIME(rt);
  1941.         js_ReportIsNotDefined(cx, ATOM_BYTES(atom));
  1942.         ok = JS_FALSE;
  1943.         goto out;
  1944.         }
  1945.  
  1946.         /* Get and push the obj[id] property's value. */
  1947.         obj2 = prop->object;
  1948.         slot = (uintN)prop->slot;
  1949.         rval = obj2->slots[slot];
  1950.         ok = prop->getter(cx, obj, prop->id, &rval);
  1951.         if (!ok) {
  1952.         JS_UNLOCK_RUNTIME(rt);
  1953.         goto out;
  1954.         }
  1955.         obj2->slots[slot] = rval;
  1956.         PUSH_OPND(rval);
  1957.  
  1958.         /* Quicken this bytecode if possible. */
  1959.         if (obj == fp->scopeChain && (prop->flags & JSPROP_PERMANENT)) {
  1960.         if (prop->getter == js_GetArgument) {
  1961.             js_PatchOpcode(cx, script, pc, JSOP_GETARG);
  1962.             slot = (uintN)JSVAL_TO_INT(prop->id);
  1963.             SET_ARGNO(pc, slot);
  1964.         } else if (prop->getter == js_GetLocalVariable) {
  1965.             js_PatchOpcode(cx, script, pc, JSOP_GETVAR);
  1966.             slot = (uintN)JSVAL_TO_INT(prop->id);
  1967.             SET_VARNO(pc, slot);
  1968.         }
  1969.         }
  1970.         JS_UNLOCK_RUNTIME(rt);
  1971.         break;
  1972.  
  1973.       case JSOP_UINT16:
  1974.         i = (jsint) GET_ATOM_INDEX(pc);
  1975.         rval = INT_TO_JSVAL(i);
  1976.         PUSH_OPND(rval);
  1977.         break;
  1978.  
  1979.       case JSOP_NUMBER:
  1980.       case JSOP_STRING:
  1981.         atom = GET_ATOM(cx, script, pc);
  1982.         PUSH_OPND(ATOM_KEY(atom));
  1983.         break;
  1984.  
  1985.       case JSOP_OBJECT:
  1986.         atom = GET_ATOM(cx, script, pc);
  1987.         rval = ATOM_KEY(atom);
  1988.         PR_ASSERT(JSVAL_IS_OBJECT(rval));
  1989.         obj = NULL;
  1990.         PUSH_OPND(rval);
  1991.         break;
  1992.  
  1993.       case JSOP_ZERO:
  1994.         PUSH_OPND(JSVAL_ZERO);
  1995.         break;
  1996.  
  1997.       case JSOP_ONE:
  1998.         PUSH_OPND(JSVAL_ONE);
  1999.         break;
  2000.  
  2001.       case JSOP_NULL:
  2002.         obj = NULL;
  2003.         PUSH_OPND(JSVAL_NULL);
  2004.         break;
  2005.  
  2006.       case JSOP_THIS:
  2007.         obj = fp->thisp;
  2008.         PUSH_OPND(OBJECT_TO_JSVAL(obj));
  2009.         break;
  2010.  
  2011.       case JSOP_FALSE:
  2012.         PUSH_OPND(JSVAL_FALSE);
  2013.         break;
  2014.  
  2015.       case JSOP_TRUE:
  2016.         PUSH_OPND(JSVAL_TRUE);
  2017.         break;
  2018.  
  2019. #if JS_HAS_SWITCH_STATEMENT
  2020.       case JSOP_TABLESWITCH:
  2021.         valid = JS_TRUE;
  2022.         SAVE_SP(fp);
  2023.         ok = PopInt(cx, &i, &valid);
  2024.         RESTORE_SP(fp);
  2025.         if (!ok)
  2026.         goto out;
  2027.  
  2028.         pc2 = pc;
  2029.         len = GET_JUMP_OFFSET(pc2);
  2030.         if (!valid)
  2031.         goto advance_pc;
  2032.  
  2033.         pc2 += 2;
  2034.         low = GET_JUMP_OFFSET(pc2);
  2035.         pc2 += 2;
  2036.         high = GET_JUMP_OFFSET(pc2);
  2037.  
  2038.         i -= low;
  2039.         if ((jsuint)i <= (jsuint)(high - low)) {
  2040.         pc2 += 2 + 2 * i;
  2041.         off = GET_JUMP_OFFSET(pc2);
  2042.         if (off)
  2043.             len = off;
  2044.         }
  2045.         break;
  2046.  
  2047.       case JSOP_LOOKUPSWITCH:
  2048.         lval = POP();
  2049.         pc2 = pc;
  2050.         len = GET_JUMP_OFFSET(pc2);
  2051.  
  2052.         if (!JSVAL_IS_NUMBER(lval) &&
  2053.         !JSVAL_IS_STRING(lval) &&
  2054.         !JSVAL_IS_BOOLEAN(lval)) {
  2055.         goto advance_pc;
  2056.         }
  2057.  
  2058.         pc2 += 2;
  2059.         npairs = GET_ATOM_INDEX(pc2);
  2060.         pc2 += 2;
  2061.  
  2062. #define SEARCH_PAIRS(MATCH_CODE)                                              \
  2063.     while (npairs) {                                                          \
  2064.     atom = GET_ATOM(cx, script, pc2);                                     \
  2065.     rval = ATOM_KEY(atom);                                                \
  2066.     MATCH_CODE                                                            \
  2067.     if (match) {                                                          \
  2068.         pc2 += 2;                                                         \
  2069.         len = GET_JUMP_OFFSET(pc2);                                       \
  2070.         goto advance_pc;                                                  \
  2071.     }                                                                     \
  2072.     pc2 += 4;                                                             \
  2073.     npairs--;                                                             \
  2074.     }
  2075.         if (JSVAL_IS_STRING(lval)) {
  2076.         str  = JSVAL_TO_STRING(lval);
  2077.         SEARCH_PAIRS(
  2078.             match = (JSVAL_IS_STRING(rval) &&
  2079.                  ((str2 = JSVAL_TO_STRING(rval)) == str ||
  2080.                   !js_CompareStrings(str2, str)));
  2081.         )
  2082.         } else if (JSVAL_IS_DOUBLE(lval)) {
  2083.         d = *JSVAL_TO_DOUBLE(lval);
  2084.         SEARCH_PAIRS(
  2085.             match = (JSVAL_IS_DOUBLE(rval) &&
  2086.                  *JSVAL_TO_DOUBLE(rval) == d);
  2087.         )
  2088.         } else {
  2089.         SEARCH_PAIRS(
  2090.             match = (lval == rval);
  2091.         )
  2092.         }
  2093. #undef SEARCH_PAIRS
  2094.         break;
  2095. #endif /* JS_HAS_SWITCH_STATEMENT */
  2096.  
  2097. #if JS_HAS_LEXICAL_CLOSURE
  2098.       case JSOP_CLOSURE:
  2099.         /*
  2100.          * If the nearest variable scope is a function, not a call object,
  2101.          * replace it in the scope chain with its call object.
  2102.          */
  2103.         JS_LOCK_RUNTIME_VOID(rt, obj = js_FindVariableScope(cx, &fun));
  2104.         if (!obj) {
  2105.         ok = JS_FALSE;
  2106.         goto out;
  2107.         }
  2108.  
  2109.         /*
  2110.          * If in a with statement, set obj to the With object's prototype,
  2111.          * i.e., the object specified in the with statement head.
  2112.          */
  2113.         if (fp->scopeChain != obj) {
  2114.         obj = fp->scopeChain;
  2115.         PR_ASSERT(obj->map->clasp == &js_WithClass);
  2116. #if JS_BUG_WITH_CLOSURE
  2117.         while (obj->map->clasp == &js_WithClass) {
  2118.             proto = OBJ_GET_PROTO(obj);
  2119.             if (!proto)
  2120.             break;
  2121.             obj = proto;
  2122.         }
  2123. #endif
  2124.         }
  2125.  
  2126.         /*
  2127.          * Get immediate operand atom, which is a function object literal.
  2128.          * From it, get the function to close.
  2129.          */
  2130.         atom = GET_ATOM(cx, script, pc);
  2131.         PR_ASSERT(ATOM_IS_OBJECT(atom));
  2132.         obj2 = ATOM_TO_OBJECT(atom);
  2133.         fun2 = JS_GetPrivate(cx, obj2);
  2134.  
  2135.         /*
  2136.          * Let closure = new Closure(obj2).
  2137.          * NB: js_ConstructObject does not use the "constructor" property
  2138.          * of the new object it creates, because in this case and others
  2139.          * such as js_WithClass, that property refers to the prototype's
  2140.          * constructor function.
  2141.          */
  2142.         closure = js_ConstructObject(cx, &js_ClosureClass, obj2,
  2143.                      fp->scopeChain);
  2144.         if (!closure) {
  2145.         ok = JS_FALSE;
  2146.         goto out;
  2147.         }
  2148.  
  2149.         /*
  2150.          * Define a property in obj with id fun2->atom and value closure,
  2151.          * but only if fun2 is not anonymous.
  2152.          */
  2153.         if (fun2->atom) {
  2154.         JS_LOCK_RUNTIME_VOID(rt,
  2155.             prop = js_DefineProperty(cx, obj, (jsval)fun2->atom,
  2156.                          OBJECT_TO_JSVAL(closure),
  2157.                          NULL, NULL, JSPROP_ENUMERATE));
  2158.         if (!prop) {
  2159.             cx->newborn[GCX_OBJECT] = NULL;
  2160.             ok = JS_FALSE;
  2161.             goto out;
  2162.         }
  2163.         }
  2164.         PUSH(OBJECT_TO_JSVAL(closure));
  2165.         break;
  2166. #endif /* JS_HAS_LEXICAL_CLOSURE */
  2167.  
  2168. #if JS_HAS_EXPORT_IMPORT
  2169.       case JSOP_EXPORTALL:
  2170.         JS_LOCK_RUNTIME(rt);
  2171.         obj = js_FindVariableScope(cx, &fun);
  2172.         if (!obj) {
  2173.         ok = JS_FALSE;
  2174.         } else {
  2175.         ok = obj->map->clasp->enumerate(cx, obj);
  2176.         if (ok) {
  2177.             for (prop = obj->map->props; prop; prop = prop->next) {
  2178.             if (prop->flags & JSPROP_ENUMERATE) {
  2179.                 ok = prop->getter(cx, obj, id, &rval);
  2180.                 if (!ok)
  2181.                 break;
  2182.                 prop->flags |= JSPROP_EXPORTED;
  2183.             }
  2184.             }
  2185.         }
  2186.         }
  2187.         JS_UNLOCK_RUNTIME(rt);
  2188.         break;
  2189.  
  2190.       case JSOP_EXPORTNAME:
  2191.         atom = GET_ATOM(cx, script, pc);
  2192.         id   = (jsval)atom;
  2193.         JS_LOCK_RUNTIME(rt);
  2194.         obj  = js_FindVariableScope(cx, &fun);
  2195.         prop = obj ? js_GetProperty(cx, obj, id, &rval) : NULL;
  2196.         if (!prop) {
  2197.         JS_UNLOCK_RUNTIME(rt);
  2198.         ok = JS_FALSE;
  2199.         goto out;
  2200.         }
  2201.         prop->flags |= JSPROP_EXPORTED;
  2202.         JS_UNLOCK_RUNTIME(rt);
  2203.         break;
  2204.  
  2205.       case JSOP_IMPORTALL:
  2206.         id = JSVAL_VOID;
  2207.         PROPERTY_OP(ok = ImportProperty(cx, obj, id),
  2208.             ok);
  2209.         break;
  2210.  
  2211.       case JSOP_IMPORTPROP:
  2212.         /* Get an immediate atom naming the property. */
  2213.         atom = GET_ATOM(cx, script, pc);
  2214.         id   = (jsval)atom;
  2215.         PROPERTY_OP(ok = ImportProperty(cx, obj, id),
  2216.             ok);
  2217.         break;
  2218.  
  2219.       case JSOP_IMPORTELEM:
  2220.         ELEMENT_OP(ok = ImportProperty(cx, obj, id),
  2221.                ok);
  2222.         break;
  2223. #endif /* JS_HAS_EXPORT_IMPORT */
  2224.  
  2225.       case JSOP_TRAP:
  2226.         switch (JS_HandleTrap(cx, script, pc, &rval)) {
  2227.           case JSTRAP_ERROR:
  2228.         ok = JS_FALSE;
  2229.         goto out;
  2230.           case JSTRAP_CONTINUE:
  2231.         PR_ASSERT(JSVAL_IS_INT(rval));
  2232.         op = (JSOp) JSVAL_TO_INT(rval);
  2233.         PR_ASSERT((uintN)op < (uintN)JSOP_LIMIT);
  2234.         goto do_op;
  2235.           case JSTRAP_RETURN:
  2236.         fp->rval = rval;
  2237.         goto out;
  2238.           default:;
  2239.         }
  2240.         break;
  2241.  
  2242.       case JSOP_GETARG:
  2243.         obj = fp->scopeChain;
  2244.         slot = (uintN)GET_ARGNO(pc);
  2245.         PR_ASSERT(slot < fp->fun->nargs);
  2246.         PUSH_OPND(fp->argv[slot]);
  2247.         break;
  2248.  
  2249.       case JSOP_SETARG:
  2250.         obj = fp->scopeChain;
  2251.         slot = (uintN)GET_ARGNO(pc);
  2252.         PR_ASSERT(slot < fp->fun->nargs);
  2253.         vp = &fp->argv[slot];
  2254.         GC_POKE(cx, *vp);
  2255.         *vp = sp[-1];
  2256.         break;
  2257.  
  2258.       case JSOP_GETVAR:
  2259.         obj = fp->scopeChain;
  2260.         slot = (uintN)GET_VARNO(pc);
  2261.         PR_ASSERT(slot < fp->fun->nvars);
  2262.         PUSH_OPND(fp->vars[slot]);
  2263.         break;
  2264.  
  2265.       case JSOP_SETVAR:
  2266.         obj = fp->scopeChain;
  2267.         slot = (uintN)GET_VARNO(pc);
  2268.         PR_ASSERT(slot < fp->fun->nvars);
  2269.         vp = &fp->vars[slot];
  2270.         GC_POKE(cx, *vp);
  2271.         *vp = sp[-1];
  2272.         break;
  2273.  
  2274. #ifdef JS_HAS_OBJECT_LITERAL
  2275.       case JSOP_NEWINIT:
  2276.         argc = 0;
  2277. #if JS_HAS_SHARP_VARS
  2278.         fp->sharpDepth++;
  2279. #endif
  2280.         goto do_new;
  2281.  
  2282.       case JSOP_ENDINIT:
  2283. #if JS_HAS_SHARP_VARS
  2284.         if (--fp->sharpDepth == 0)
  2285.         fp->sharpArray = NULL;
  2286. #endif
  2287.         break;
  2288.  
  2289.       case JSOP_INITPROP:
  2290.         /* Pop the property's value into rval. */
  2291.         PR_ASSERT(sp - newsp >= 2);
  2292.         rval = POP();
  2293.  
  2294.         /* Get the immediate property name into id. */
  2295.         atom = GET_ATOM(cx, script, pc);
  2296.         id   = (jsval)atom;
  2297.         goto do_init;
  2298.  
  2299.       case JSOP_INITELEM:
  2300.         /* Pop the element's value into rval. */
  2301.         PR_ASSERT(sp - newsp >= 3);
  2302.         rval = POP();
  2303.  
  2304.         /* Pop and conditionally atomize the element id. */
  2305.         id = POP();
  2306.         FIX_ELEMENT_ID(id);
  2307.  
  2308.       do_init:
  2309.         /* Find the object being initialized at top of stack. */
  2310.         lval = sp[-1];
  2311.         PR_ASSERT(JSVAL_IS_OBJECT(lval));
  2312.         obj = JSVAL_TO_OBJECT(lval);
  2313.  
  2314.         /* Set the property named by obj[id] to rval. */
  2315.         JS_LOCK_RUNTIME_VOID(rt, prop = js_SetProperty(cx, obj, id, &rval));
  2316.         if (!prop) {
  2317.         ok = JS_FALSE;
  2318.         goto out;
  2319.         }
  2320.         if (dropAtom) {
  2321.         JS_LOCK_RUNTIME_VOID(rt, js_DropAtom(cx, atom));
  2322.         dropAtom = JS_FALSE;
  2323.         }
  2324.         break;
  2325.  
  2326. #if JS_HAS_SHARP_VARS
  2327.       case JSOP_DEFSHARP:
  2328.         obj = fp->sharpArray;
  2329.         if (!obj) {
  2330.         obj = js_NewArrayObject(cx, 0, NULL);
  2331.         if (!obj) {
  2332.             ok = JS_FALSE;
  2333.             goto out;
  2334.         }
  2335.         fp->sharpArray = obj;
  2336.         }
  2337.         i = (jsint) GET_ATOM_INDEX(pc);
  2338.         id = INT_TO_JSVAL(i);
  2339.         rval = sp[-1];
  2340.         PR_ASSERT(JSVAL_IS_OBJECT(rval));
  2341.         JS_LOCK_RUNTIME_VOID(rt, prop = js_SetProperty(cx, obj, id, &rval));
  2342.         if (!prop) {
  2343.         ok = JS_FALSE;
  2344.         goto out;
  2345.         }
  2346.         break;
  2347.  
  2348.       case JSOP_USESHARP:
  2349.         i = (jsint) GET_ATOM_INDEX(pc);
  2350.         id = INT_TO_JSVAL(i);
  2351.         obj = fp->sharpArray;
  2352.         if (!obj) {
  2353.         rval = JSVAL_VOID;
  2354.         } else {
  2355.         JS_LOCK_RUNTIME_VOID(rt,
  2356.                      prop = js_GetProperty(cx, obj, id, &rval));
  2357.         if (!prop) {
  2358.             ok = JS_FALSE;
  2359.             goto out;
  2360.         }
  2361.         }
  2362.         if (!JSVAL_IS_OBJECT(rval)) {
  2363.         JS_ReportError(cx, "invalid sharp variable #%u#", (unsigned) i);
  2364.         ok = JS_FALSE;
  2365.         goto out;
  2366.         }
  2367.         PUSH_OPND(rval);
  2368.         break;
  2369. #endif /* JS_HAS_SHARP_VARS */
  2370. #endif /* JS_HAS_OBJECT_LITERAL */
  2371.  
  2372.       default:
  2373.         JS_ReportError(cx, "unimplemented JavaScript bytecode %d", op);
  2374.         ok = JS_FALSE;
  2375.         goto out;
  2376.     }
  2377.  
  2378.     advance_pc:
  2379.     pc += len;
  2380.  
  2381. #ifdef DEBUG
  2382.     if (tracefp) {
  2383.         intN ndefs, n;
  2384.         jsval v;
  2385.  
  2386.         ndefs = cs->ndefs;
  2387.         if (ndefs) {
  2388.         fp->sp = sp - ndefs;
  2389.         for (n = ndefs; n > 0; n--) {
  2390.             v = sp[-n];
  2391.             str = js_ValueToSource(cx, v);
  2392.             if (str) {
  2393.             fprintf(tracefp, "%s %s",
  2394.                 (n == ndefs) ? "  output:" : ",",
  2395.                 JS_GetStringBytes(str));
  2396.             }
  2397.         }
  2398.         putc('\n', tracefp);
  2399.         SAVE_SP(fp);
  2400.         }
  2401.     }
  2402. #endif
  2403.     }
  2404.  
  2405.     /*
  2406.      * Treat end of script as a backward branch to handle all kinds of return
  2407.      * from function.
  2408.      */
  2409.     CHECK_BRANCH(-1);
  2410.  
  2411. out:
  2412.     /*
  2413.      * Restore the previous frame's execution state.
  2414.      */
  2415.     PR_ARENA_RELEASE(&cx->stackPool, mark);
  2416.  
  2417.     if (dropAtom) {
  2418.     JS_LOCK_RUNTIME_VOID(rt, js_DropAtom(cx, atom));
  2419.     dropAtom = JS_FALSE;
  2420.     }
  2421.  
  2422. #ifdef JS_THREADSAFE
  2423.     ok &= JS_RemoveRoot(cx, &obj);
  2424. #endif
  2425.  
  2426.     cx->interpLevel--;
  2427.     return ok;
  2428. }
  2429.