* ECMA-compatible for/in bytecodes eval object just once, before loop.
* ECMA-compatible for/in evals the object just once, before loop.
js_Interpret(JSContext *cx, jsval *result){    JSRuntime *rt;    JSStackFrame *fp;    JSScript *script;    JSObject *obj, *obj2, *proto, *parent;    JSBranchCallback onbranch;    JSBool ok, cond;    ptrdiff_t depth, len;    jsval *sp, *newsp;    void *mark;    jsbytecode *pc, *pc2, *endpc;    JSOp op, op2;    JSCodeSpec *cs;    JSAtom *atom;    uintN argc, slot;    jsval *vp, lval, rval, ltmp, rtmp;    jsid id;    JSObject *withobj, *origobj, *propobj;    JSIdArray *ida;    jsval iter_state;    JSProperty *prop;    JSScopeProperty *sprop;    JSString *str, *str2, *str3;    size_t length, length2, length3;    jschar *chars;    jsint i, j;    jsdouble d, d2;    JSFunction *fun;    JSType type;#ifdef DEBUG    FILE *tracefp;#endif#if JS_HAS_SWITCH_STATEMENT    jsint low, high;    uintN off, npairs;    JSBool match;#endif#if JS_HAS_LEXICAL_CLOSURE    JSFunction *fun2;    JSObject *closure;#endif#if JS_HAS_EXPORT_IMPORT    uintN attrs;#endif#if JS_HAS_EXCEPTIONS    JSTryNote *tn;    ptrdiff_t offset;#endif    if (cx->interpLevel == MAX_INTERP_LEVEL) {	JS_ReportError(cx, "too much recursion");	return JS_FALSE;    }    cx->interpLevel++;    *result = JSVAL_VOID;    rt = cx->runtime;    /*     * Set registerized frame pointer and derived pointers.     */    fp = cx->fp;    script = fp->script;    obj = fp->scopeChain;    /*     * Prepare to call a user-supplied branch handler, and abort the script     * if it returns false.     */    onbranch = cx->branchCallback;    ok = JS_TRUE;#define CHECK_BRANCH(len) {                                                   \    if (len < 0 && onbranch) {                                                \	SAVE_SP(fp);                                                          \	if (!(ok = (*onbranch)(cx, script)))                                  \	    goto out;                                                         \    }                                                                         \}    /*     * Allocate operand and pc stack slots for the script's worst-case depth.     */    depth = (ptrdiff_t)script->depth;    newsp = js_AllocStack(cx, (uintN)(2 * depth), &mark);    if (!newsp) {	ok = JS_FALSE;	goto out;    }    newsp += depth;    fp->sp = sp = newsp;    pc = script->code;    endpc = pc + script->length;    while (pc < endpc) {	fp->pc = pc;	op = (JSOp)*pc;      do_op:	cs = &js_CodeSpec[op];	len = cs->length;#ifdef DEBUG	tracefp = cx->tracefp;	if (tracefp) {	    intN nuses, n;	    fprintf(tracefp, "%4u: ", js_PCToLineNumber(script, pc));	    js_Disassemble1(cx, script, pc, pc - script->code, JS_FALSE,			    tracefp);	    nuses = cs->nuses;	    if (nuses) {		fp->sp = sp - nuses;		for (n = 0; n < nuses; n++) {		    str = js_DecompileValueGenerator(cx, *fp->sp, NULL);		    if (str != NULL) {			fprintf(tracefp, "%s %s",				(n == 0) ? "  inputs:" : ",",				JS_GetStringBytes(str));		    }		    fp->sp++;		}		putc('\n', tracefp);	    }	}#endif	if (rt->interruptHandler) {	    JSTrapHandler handler = (JSTrapHandler) rt->interruptHandler;            /* check copy of pointer for safety in multithreaded situation */            if (handler) {	        switch (handler(cx, script, pc, &rval,			        rt->interruptHandlerData)) {	          case JSTRAP_ERROR:		    ok = JS_FALSE;		    goto out;	          case JSTRAP_CONTINUE:		    break;	          case JSTRAP_RETURN:		    fp->rval = rval;		    goto out;	          default:;	        }            }	}	switch (op) {	  case JSOP_NOP:	    break;	  case JSOP_PUSH:	    PUSH_OPND(JSVAL_VOID);	    break;	  case JSOP_POP:	    sp--;	    break;	  case JSOP_POP2:	    sp -= 2;	    break;	  case JSOP_POPV:	    *result = POP();	    break;	  case JSOP_ENTERWITH:	    rval = POP();	    VALUE_TO_OBJECT(cx, rval, obj);	    withobj = js_NewObject(cx, &js_WithClass, obj, fp->scopeChain);	    if (!withobj)		goto out;	    fp->scopeChain = withobj;	    PUSH_OPND(OBJECT_TO_JSVAL(withobj));	    break;	  case JSOP_LEAVEWITH:	    rval = POP();	    PR_ASSERT(JSVAL_IS_OBJECT(rval));	    withobj = JSVAL_TO_OBJECT(rval);	    PR_ASSERT(OBJ_GET_CLASS(cx, withobj) == &js_WithClass);	    rval = OBJ_GET_SLOT(cx, withobj, JSSLOT_PARENT);	    PR_ASSERT(JSVAL_IS_OBJECT(rval));	    fp->scopeChain = JSVAL_TO_OBJECT(rval);	    break;	  case JSOP_RETURN:	    CHECK_BRANCH(-1);	    fp->rval = POP();	    goto out;	  case JSOP_GOTO:	    len = GET_JUMP_OFFSET(pc);	    CHECK_BRANCH(len);	    break;	  case JSOP_IFEQ:	    POP_BOOLEAN(cx, rval, cond);	    if (cond == JS_FALSE) {		len = GET_JUMP_OFFSET(pc);		CHECK_BRANCH(len);	    }	    break;	  case JSOP_IFNE:	    POP_BOOLEAN(cx, rval, cond);	    if (cond != JS_FALSE) {		len = GET_JUMP_OFFSET(pc);		CHECK_BRANCH(len);	    }	    break;#if !JS_BUG_SHORT_CIRCUIT	  case JSOP_OR:	    POP_BOOLEAN(cx, rval, cond);	    if (cond == JS_TRUE) {		len = GET_JUMP_OFFSET(pc);		PUSH_OPND(rval);	    }	    break;	  case JSOP_AND:	    POP_BOOLEAN(cx, rval, cond);	    if (cond == JS_FALSE) {		len = GET_JUMP_OFFSET(pc);		PUSH_OPND(rval);	    }	    break;#endif	  case JSOP_TOOBJECT:	    rval = POP();	    SAVE_SP(fp);	    ok = js_ValueToObject(cx, rval, &obj);	    if (!ok)		goto out;	    PUSH(OBJECT_TO_JSVAL(obj));	    break;#define POP_ELEMENT_ID(id) {                                                  \    /* If the index is not a jsint, atomize it. */                            \    id = (jsid) POP();                                                        \    if (JSVAL_IS_INT(id)) {                                                   \    	atom = NULL;                                                          \    } else {                                                                  \	atom = js_ValueToStringAtom(cx, (jsval)id);                           \	if (!atom) {                                                          \	    ok = JS_FALSE;                                                    \	    goto out;                                                         \	}                                                                     \	id = (jsid)atom;                                                      \    }                                                                         \}#if JS_HAS_IN_OPERATOR	  case JSOP_IN:	    rval = POP();            if (!JSVAL_IS_OBJECT(rval) || rval == JSVAL_NULL) {                JS_ReportError(cx, "target of 'in' operator must be an object");                ok = JS_FALSE;                goto out;            }            obj = JSVAL_TO_OBJECT(rval);	    POP_ELEMENT_ID(id);	    ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);	    if (!ok)		goto out;	    PUSH_OPND(BOOLEAN_TO_JSVAL(prop != NULL));	    break;#endif /* JS_HAS_IN_OPERATOR */	  case JSOP_FORNAME:	    rval = POP();	    /* FALL THROUGH */	  case JSOP_FORNAME2:	    atom = GET_ATOM(cx, script, pc);	    id   = (jsid)atom;	    SAVE_SP(fp);	    ok = js_FindVariable(cx, id, &obj, &obj2, &prop);	    if (!ok)		goto out;	    PR_ASSERT(prop);	    OBJ_DROP_PROPERTY(cx, obj2, prop);	    lval = OBJECT_TO_JSVAL(obj);	    goto do_forinloop;	  case JSOP_FORPROP:	    rval = POP();	    /* FALL THROUGH */	  case JSOP_FORPROP2:	    lval = POP();	    atom = GET_ATOM(cx, script, pc);	    id   = (jsid)atom;	    goto do_forinloop;	  case JSOP_FORELEM:	    rval = POP();	    /* FALL THROUGH */	  case JSOP_FORELEM2:	    POP_ELEMENT_ID(id);	    lval = POP();	  do_forinloop:	    /*             * ECMA-compatible for/in bytecodes eval object just once, before loop.             */	    if (cs->format & JOF_FOR2) {		obj = JSVAL_TO_OBJECT(sp[-1]);		vp = sp - 2;	    } else {                /* Old-style (pre-ECMA) JSOPs */		SAVE_SP(fp);		ok = js_ValueToObject(cx, rval, &obj);		if (!ok)		    goto out;		vp = sp - 1;	    }	    /* If the thing to the right of 'in' has no properties, break. */	    if (!obj) {		rval = JSVAL_FALSE;		goto end_forinloop;	    }	    /*             * Save the thing to the right of 'in' as origobj.  Later on we use             * this variable to suppress enumeration of shadowed prototype             * properties.             */	    origobj = obj;	    /*             * Reach under the top of stack to find our property iterator, a             * JSObject that contains the iteration state.  (An object is used             * rather than a native struct so that the iteration state is             * cleaned up via GC if the for-in loop terminates abruptly.)             */	    rval = *vp;            /* Is this the first iteration ? */	    if (JSVAL_IS_VOID(rval)) {		/* Yes, create a new JSObject to hold the iterator state */		propobj = js_NewObject(cx, &prop_iterator_class, NULL, NULL);		if (!propobj) {		    ok = JS_FALSE;		    goto out;		}		/*		 * Rewrite the iterator so we know to do the next case.		 * Do this before calling the enumerator, which could		 * displace cx->newborn and cause GC.		 */		*vp = OBJECT_TO_JSVAL(propobj);                ok = OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, 0);		propobj->slots[JSSLOT_ITR_STATE] = iter_state;		if (!ok)                    goto out;		/*                 * Stash private iteration state into property iterator object.                 * NB: This code knows that the first slots are pre-allocated.                 */		PR_ASSERT(JS_INITIAL_NSLOTS >= 5);		propobj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(obj);	    } else {		/* This is not the first iteration. Recover iterator state. */		propobj = JSVAL_TO_OBJECT(rval);                obj = JSVAL_TO_OBJECT(propobj->slots[JSSLOT_PARENT]);                iter_state = propobj->slots[JSSLOT_ITR_STATE];	    }          enum_next_property:            /* Get the next jsid to be enumerated and store it in rval */            OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &rval);            propobj->slots[JSSLOT_ITR_STATE] = iter_state;            /* No more jsids to iterate in obj ? */            if (iter_state == JSVAL_NULL) {                /* Enumerate the properties on obj's prototype chain */		obj = OBJ_GET_PROTO(cx, obj);		if (!obj) {		    /* End of property list -- terminate loop. */		    rval = JSVAL_FALSE;		    goto end_forinloop;		}                ok = OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, 0);		propobj->slots[JSSLOT_ITR_STATE] = iter_state;		if (!ok)                    goto out;		/* Stash private iteration state into iterator JSObject. */		propobj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(obj);                goto enum_next_property;            }	    /* Skip deleted and shadowed properties, leave next id in rval. */            if (obj != origobj) {                /* Have we already enumerated a clone of this property? */		ok = OBJ_LOOKUP_PROPERTY(cx, origobj, rval, &obj2, &prop);		if (!ok)		    goto out;		if (prop) {		    OBJ_DROP_PROPERTY(cx, obj2, prop);                    /* Yes, don't enumerate again.  Go to the next property */		    if (obj2 != obj)                        goto enum_next_property;                }	    }	    /* Convert lval to a non-null object containing id. */	    VALUE_TO_OBJECT(cx, lval, obj);	    /* Make sure rval is a string for uniformity and compatibility. */	    if (!JSVAL_IS_INT(rval)) {		rval = ATOM_KEY((JSAtom *)rval);	    } else if ((cx->version <= JSVERSION_1_1) &&                       (cx->version >= JSVERSION_1_0)) {		str = js_NumberToString(cx, (jsdouble) JSVAL_TO_INT(rval));		if (!str) {		    ok = JS_FALSE;		    goto out;		}		/* Hold via sp[0] in case the GC runs under OBJ_SET_PROPERTY. */		rval = sp[0] = STRING_TO_JSVAL(str);	    }	    /* Set the variable obj[id] to refer to rval. */	    ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);	    if (!ok)		goto out;	    /* Push true to keep looping through properties. */	    rval = JSVAL_TRUE;	  end_forinloop:	    PUSH_OPND(rval);	    break;	  case JSOP_DUP:	    PR_ASSERT(sp > newsp);	    rval = sp[-1];	    PUSH_OPND(rval);	    break;	  case JSOP_DUP2:	    PR_ASSERT(sp - 1 > newsp);	    lval = sp[-2];	    rval = sp[-1];	    PUSH_OPND(lval);	    PUSH_OPND(rval);	    break;#define PROPERTY_OP(call) {                                                   \    /* Pop the left part and resolve it to a non-null object. */              \    lval = POP();                                                             \    VALUE_TO_OBJECT(cx, lval, obj);                                           \									      \    /* Get or set the property, set ok false if error, true if success. */    \    call;                                                                     \    if (!ok)                                                                  \	goto out;                                                             \}#define ELEMENT_OP(call) {                                                    \    POP_ELEMENT_ID(id);                                                       \    PROPERTY_OP(call);                                                        \}#define CACHED_GET(call) {                                                    \    PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, prop);                   \    if (PROP_FOUND(prop)) {                                                   \	sprop = (JSScopeProperty *)prop;                                      \	slot = (uintN)sprop->slot;                                            \	rval = OBJ_GET_SLOT(cx, obj, slot);                                   \	ok = SPROP_GET(cx, sprop, obj, obj, &rval);                           \	if (ok)                                                               \	    OBJ_SET_SLOT(cx, obj, slot, rval);                                \    } else {                                                                  \	SAVE_SP(fp);                                                          \	ok = call;                                                            \	/* No fill here: js_GetProperty fills the cache. */                   \    }                                                                         \}#if JS_BUG_SET_ENUMERATE#define SET_ENUMERATE_ATTR(sprop) ((sprop)->attrs |= JSPROP_ENUMERATE)#else#define SET_ENUMERATE_ATTR(sprop) ((void)0)#endif#define CACHED_SET(call) {                                                    \    PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, prop);                   \    if (PROP_FOUND(prop) &&                                                   \	!(sprop = (JSScopeProperty *)prop,                                    \	  sprop->attrs & (JSPROP_READONLY | JSPROP_ASSIGNHACK))) {            \	ok = SPROP_SET(cx, sprop, obj, obj, &rval);                           \	if (ok) {                                                             \	    SET_ENUMERATE_ATTR(sprop);                                        \	    OBJ_SET_SLOT(cx, obj, sprop->slot, rval);                         \	}                                                                     \    } else {                                                                  \	SAVE_SP(fp);                                                          \	ok = call;                                                            \	/* No fill here: js_SetProperty writes through the cache. */          \    }                                                                         \}	  case JSOP_SETNAME:	    /* Get an immediate atom naming the variable to set. */	    atom = GET_ATOM(cx, script, pc);	    id   = (jsid)atom;	    SAVE_SP(fp);	    ok = js_FindVariable(cx, id, &obj, &obj2, &prop);	    if (!ok)		goto out;	    PR_ASSERT(prop);	    OBJ_DROP_PROPERTY(cx, obj2, prop);	    /* Pop the right-hand side and set obj[id] to it. */	    rval = POP();	    /* Try to hit the property cache, FindVariable primes it. */	    CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval));	    if (!ok)		goto out;	    /* Push the right-hand side as our result. */	    PUSH_OPND(rval);	    break;	  case JSOP_BINDNAME:	    atom = GET_ATOM(cx, script, pc);	    SAVE_SP(fp);	    ok = js_FindVariable(cx, (jsid)atom, &obj, &obj2, &prop);	    if (!ok)		goto out;	    OBJ_DROP_PROPERTY(cx, obj2, prop);	    PUSH_OPND(OBJECT_TO_JSVAL(obj));	    break;	  case JSOP_SETNAME2:	    atom = GET_ATOM(cx, script, pc);	    id   = (jsid)atom;	    rval = POP();	    lval = POP();	    PR_ASSERT(!JSVAL_IS_PRIMITIVE(lval));	    obj  = JSVAL_TO_OBJECT(lval);	    CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval));	    if (!ok)		goto out;	    PUSH_OPND(rval);	    break;#define INTEGER_OP(OP, EXTRA_CODE) {                                          \    SAVE_SP(fp);                                                              \    ok = PopInt(cx, &j) && PopInt(cx, &i);                                    \    RESTORE_SP(fp);                                                           \    if (!ok)                                                                  \	goto out;                                                             \    EXTRA_CODE                                                                \    i = i OP j;                                                               \    PUSH_NUMBER(cx, i);                                                       \}#define BITWISE_OP(OP)		INTEGER_OP(OP, (void) 0;)#define SIGNED_SHIFT_OP(OP)	INTEGER_OP(OP, j &= 31;)	  case JSOP_BITOR:	    BITWISE_OP(|);	    break;	  case JSOP_BITXOR:	    BITWISE_OP(^);	    break;	  case JSOP_BITAND:	    BITWISE_OP(&);	    break;#ifdef XP_PC#define COMPARE_DOUBLES(LVAL, OP, RVAL, IFNAN)                                \    ((JSDOUBLE_IS_NaN(LVAL) || JSDOUBLE_IS_NaN(RVAL))                         \     ? (IFNAN)                                                                \     : (LVAL) OP (RVAL))#else#define COMPARE_DOUBLES(LVAL, OP, RVAL, IFNAN) ((LVAL) OP (RVAL))#endif#define RELATIONAL_OP(OP) {                                                   \    rval = POP();                                                             \    lval = POP();                                                             \    /* Optimize for two int-tagged operands (typical loop control). */        \    if ((lval & rval) & JSVAL_INT) {                                          \	ltmp = lval ^ JSVAL_VOID;                                             \	rtmp = rval ^ JSVAL_VOID;                                             \	if (ltmp && rtmp) {                                                   \	    cond = JSVAL_TO_INT(lval) OP JSVAL_TO_INT(rval);                  \	} else {                                                              \	    d  = ltmp ? JSVAL_TO_INT(lval) : *rt->jsNaN;                      \	    d2 = rtmp ? JSVAL_TO_INT(rval) : *rt->jsNaN;                      \	    cond = COMPARE_DOUBLES(d, OP, d2, JS_FALSE);                      \	}                                                                     \    } else {                                                                  \	VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_NUMBER, &lval);                   \	/* Need lval for strcmp or ToNumber later, so root it via sp[0]. */   \	sp[0] = lval;                                                         \	VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_NUMBER, &rval);                   \	if (JSVAL_IS_STRING(lval) && JSVAL_IS_STRING(rval)) {                 \	    str  = JSVAL_TO_STRING(lval);                                     \	    str2 = JSVAL_TO_STRING(rval);                                     \	    cond = js_CompareStrings(str, str2) OP 0;                         \	} else {                                                              \	    /* Need rval after ToNumber(lval), so root it via sp[1]. */       \	    sp[1] = rval;                                                     \	    VALUE_TO_NUMBER(cx, lval, d);                                     \	    VALUE_TO_NUMBER(cx, rval, d2);                                    \	    cond = COMPARE_DOUBLES(d, OP, d2, JS_FALSE);                      \	}                                                                     \    }                                                                         \    PUSH_OPND(BOOLEAN_TO_JSVAL(cond));                                        \}#define EQUALITY_OP(OP, IFNAN) {                                              \    rval = POP();                                                             \    lval = POP();                                                             \    ltmp = JSVAL_TAG(lval);                                                   \    rtmp = JSVAL_TAG(rval);                                                   \    if (ltmp == rtmp) {                                                       \	if (ltmp == JSVAL_STRING) {                                           \	    str  = JSVAL_TO_STRING(lval);                                     \	    str2 = JSVAL_TO_STRING(rval);                                     \	    cond = js_CompareStrings(str, str2) OP 0;                         \	} else if (ltmp == JSVAL_DOUBLE) {                                    \	    d  = *JSVAL_TO_DOUBLE(lval);                                      \	    d2 = *JSVAL_TO_DOUBLE(rval);                                      \	    cond = COMPARE_DOUBLES(d, OP, d2, IFNAN);                         \	} else {                                                              \	    /* Handle all undefined (=>NaN) and int combinations. */          \	    cond = lval OP rval;                                              \	}                                                                     \    } else {                                                                  \	if (JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval)) {                     \	    cond = (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) OP 1;         \	} else if (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) {              \	    cond = 1 OP 0;                                                    \	} else {                                                              \	    if (ltmp == JSVAL_OBJECT) {                                       \		VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_VOID, &lval);             \		ltmp = JSVAL_TAG(lval);                                       \	    } else if (rtmp == JSVAL_OBJECT) {                                \		VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_VOID, &rval);             \		rtmp = JSVAL_TAG(rval);                                       \	    }                                                                 \	    if (ltmp == JSVAL_STRING && rtmp == JSVAL_STRING) {               \		str  = JSVAL_TO_STRING(lval);                                 \		str2 = JSVAL_TO_STRING(rval);                                 \		cond = js_CompareStrings(str, str2) OP 0;                     \	    } else {                                                          \		/* Need rval after ToNumber(lval), so root it via sp[1]. */   \		sp[1] = rval;                                                 \		VALUE_TO_NUMBER(cx, lval, d);                                 \		VALUE_TO_NUMBER(cx, rval, d2);                                \		cond = COMPARE_DOUBLES(d, OP, d2, IFNAN);                     \	    }                                                                 \	}                                                                     \    }                                                                         \    PUSH_OPND(BOOLEAN_TO_JSVAL(cond));                                        \}	  case JSOP_EQ:	    EQUALITY_OP(==, JS_FALSE);