Convert macro code in jsinterp.cpp into inline functions and introduce trace primitives (prim_*, guard_*, call_*).
authorAndreas Gal <gal@uci.edu>
Mon, 26 May 2008 15:27:13 -0700
changeset 17173 343a7e6713a3673d1884d728b97b82a8412e69b9
parent 17172 5c9fdaab8776db17eab4258784a15f3fca4e675c
child 17174 5c552143c1b3c335cd55bdc38d2368213815777b
push idunknown
push userunknown
push dateunknown
milestone1.9.1a1pre
Convert macro code in jsinterp.cpp into inline functions and introduce trace primitives (prim_*, guard_*, call_*).
js/src/jsinterp.cpp
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -2283,148 +2283,408 @@ js_DumpOpMeters()
     }
     fclose(fp);
 }
 
 #endif /* JS_OPSMETER */
 
 #else /* !defined js_invoke_c__ */
 
-#define PUSH_STACK(v)    (*regs.sp++ = (v))
-#define POP_STACK(v)     ((v) = *--regs.sp)
-#define STORE_STACK(n,v) (regs.sp[n] = (v))
-#define FETCH_STACK(n,v) ((v) = regs.sp[n])
-#define ADJUST_STACK(n)  (regs.sp += (n))
+static inline void prim_push_stack(JSFrameRegs& regs, jsval& v) {
+    *regs.sp++ = v;
+}
+
+static inline void prim_pop_stack(JSFrameRegs& regs, jsval& v) {
+    v = *--regs.sp;
+}
+
+static inline void prim_store_stack(JSFrameRegs& regs, int n, jsval& v) {
+    regs.sp[n] = v;
+}
+
+static inline void prim_fetch_stack(JSFrameRegs& regs, int n, jsval& v) {
+    v = regs.sp[n];
+}
+
+static inline void prim_adjust_stack(JSFrameRegs& regs, int n) {
+    regs.sp += n;
+}
+
+#define PUSH_STACK(v)    prim_push_stack(regs, (v))
+#define POP_STACK(v)     prim_pop_stack(regs, (v))
+#define STORE_STACK(n,v) prim_store_stack(regs, (n), (v))
+#define FETCH_STACK(n,v) prim_fetch_stack(regs, (n), (v))
+#define ADJUST_STACK(n)  prim_adjust_stack(regs, (n))
+
+static inline void prim_generate_constant(jsval c, jsval& v) {
+    v = c;
+}
+
+static inline void prim_boolean_to_jsval(JSBool& b, jsval& v) {
+    v = BOOLEAN_TO_JSVAL(b);
+}
+
+static inline void prim_string_to_jsval(JSString*& str, jsval& v) {
+    v = STRING_TO_JSVAL(str);
+}
+
+static inline void prim_object_to_jsval(JSObject*& obj, jsval& v) {
+    v = OBJECT_TO_JSVAL(obj);
+}
+
+static inline void prim_id_to_jsval(jsid& id, jsval& v) {
+    v = ID_TO_VALUE(id);
+}
+
+static inline void push_stack_constant(JSFrameRegs& regs, jsval c) {
+    jsval v;
+    prim_generate_constant(c, v);
+    prim_push_stack(regs, v);
+}
+
+static inline void push_stack_boolean(JSFrameRegs& regs, JSBool& b) {
+    jsval v;
+    prim_boolean_to_jsval(b, v);
+    prim_push_stack(regs, v);
+}
+
+static inline void push_stack_object(JSFrameRegs& regs, JSObject*& obj) {
+    jsval v;
+    prim_object_to_jsval(obj, v);
+    prim_push_stack(regs, v);
+}
+
+static inline void push_stack_id(JSFrameRegs& regs, jsid& id) {
+    jsval v;
+    prim_id_to_jsval(id, v);
+    prim_push_stack(regs, v);
+}
+
+static inline void store_stack_constant(JSFrameRegs& regs, int n, jsval c) {
+    jsval v;
+    prim_generate_constant(c, v);
+    prim_store_stack(regs, n, v);
+}
+
+static inline void store_stack_boolean(JSFrameRegs& regs, int n, JSBool& b) {
+    jsval v;
+    prim_boolean_to_jsval(b, v);
+    prim_store_stack(regs, n, v);
+}
+
+static inline void store_stack_string(JSFrameRegs& regs, int n, JSString*& str) {
+    jsval v;
+    prim_string_to_jsval(str, v);
+    prim_store_stack(regs, n, v);
+}
+
+static inline void store_stack_object(JSFrameRegs& regs, int n, JSObject*& obj) {
+    jsval v;
+    prim_object_to_jsval(obj, v);
+    prim_store_stack(regs, n, v);
+}
+
+#define PUSH_STACK_CONSTANT(c)     push_stack_constant(regs, (c))
+#define PUSH_STACK_BOOLEAN(b)      push_stack_boolean(regs, (b))
+#define PUSH_STACK_OBJECT(obj)     push_stack_object(regs, (obj))
+#define PUSH_STACK_ID(id)          push_stack_id(regs, (id))
+#define STORE_STACK_CONSTANT(n, c) store_stack_constant(regs, (n), (c))
+#define STORE_STACK_BOOLEAN(n, b)  store_stack_boolean(regs, (n), (b))
+#define STORE_STACK_STRING(n, str) store_stack_string(regs, (n), (str))
+#define STORE_STACK_OBJECT(n, obj) store_stack_object(regs, (n), (obj))
+
+static inline bool guard_jsdouble_is_int_and_int_fits_in_jsval(jsdouble& d, jsint& i) {
+    return JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i);
+}
+
+static inline void prim_int_to_jsval(jsint& i, jsval& v) {
+    v = INT_TO_JSVAL(i);
+}
+
+static inline bool call_NewDoubleInRootedValue(JSContext* cx, jsdouble& d, jsval* vp) {
+    return js_NewDoubleInRootedValue(cx, d, vp);
+}
+
+static inline bool store_number(JSContext* cx, JSFrameRegs& regs, int n, jsdouble& d) {
+    jsint i;
+    if (guard_jsdouble_is_int_and_int_fits_in_jsval(d, i))
+        prim_int_to_jsval(i, regs.sp[n]);
+    else if (!call_NewDoubleInRootedValue(cx, d, &regs.sp[n]))
+        return JS_FALSE;
+    return JS_TRUE;
+}
 
 /*
  * Push the jsdouble d using sp from the lexical environment. Try to convert d
  * to a jsint that fits in a jsval, otherwise GC-alloc space for it and push a
  * reference.
  */
+
 #define STORE_NUMBER(cx, n, d)                                                \
-    JS_BEGIN_MACRO                                                            \
-        jsint i_;                                                             \
-                                                                              \
-        if (JSDOUBLE_IS_INT(d, i_) && INT_FITS_IN_JSVAL(i_))                  \
-            regs.sp[n] = INT_TO_JSVAL(i_);                                    \
-        else if (!js_NewDoubleInRootedValue(cx, d, &regs.sp[n]))              \
-            goto error;                                                       \
-    JS_END_MACRO
+    if (!store_number(cx, regs, n, d))                                        \
+        goto error;
+
+static inline bool guard_int_fits_in_jsval(jsint& i) {
+    return INT_FITS_IN_JSVAL(i);
+}
+
+static inline void prim_int_to_double(jsint& i, jsdouble& d) {
+    d = (jsdouble) i;
+}
+
+static inline bool store_int(JSContext* cx, JSFrameRegs& regs, int n, jsint& i) {
+    if (guard_int_fits_in_jsval(i)) {
+        prim_int_to_jsval(i, regs.sp[n]);
+    } else {
+        jsdouble d;
+        prim_int_to_double(i, d);
+        if (!call_NewDoubleInRootedValue(cx, d, &regs.sp[n]))
+            return JS_FALSE;
+    }
+    return JS_TRUE;
+}
 
 #define STORE_INT(cx, n, i)                                                   \
-    JS_BEGIN_MACRO                                                            \
-        if (INT_FITS_IN_JSVAL(i))                                             \
-            regs.sp[n] = INT_TO_JSVAL(i);                                     \
-        else if (!js_NewDoubleInRootedValue(cx, (jsdouble) (i), &regs.sp[n])) \
-            goto error;                                                       \
-    JS_END_MACRO
+    if (!store_int(cx, regs, n, i))                                           \
+        goto error;
+
+static inline bool guard_uint_fits_in_jsval(uint32& u) {
+    return u <= JSVAL_INT_MAX;
+}
+
+static inline void prim_uint_to_jsval(uint32& u, jsval& v) {
+    v = INT_TO_JSVAL(u);
+}
+
+static inline void prim_uint_to_double(uint32& u, jsdouble& d) {
+    d = (jsdouble) u;
+}
+
+static bool store_uint(JSContext* cx, JSFrameRegs& regs, int n, uint32& u) {
+    if (guard_uint_fits_in_jsval(u)) {
+        prim_uint_to_jsval(u, regs.sp[n]);
+    } else {
+        jsdouble d;
+        prim_uint_to_double(u, d);
+        if (!call_NewDoubleInRootedValue(cx, d, &regs.sp[n]))
+            return JS_FALSE;
+    }
+    return JS_TRUE;
+}
 
 #define STORE_UINT(cx, n, u)                                                  \
-    JS_BEGIN_MACRO                                                            \
-        if ((u) <= JSVAL_INT_MAX)                                             \
-            regs.sp[n] = INT_TO_JSVAL(u);                                     \
-        else if (!js_NewDoubleInRootedValue(cx, (jsdouble) (u), &regs.sp[n])) \
-            goto error;                                                       \
-    JS_END_MACRO
+    if (!store_uint(cx, regs, n, u))                                          \
+        goto error;
+
+static inline bool guard_jsval_is_int(jsval& v) {
+    return JSVAL_IS_INT(v);
+}
+
+static inline void prim_jsval_to_int(jsval& v, jsint& i) {
+    i = JSVAL_TO_INT(v);
+}
+
+static inline bool guard_jsval_is_double(jsval& v) {
+    return JSVAL_IS_DOUBLE(v);
+}
+
+static inline void prim_jsval_to_double(jsval& v, jsdouble& d) {
+    d = *JSVAL_TO_DOUBLE(v);
+}
+
+static inline void call_ValueToNumber(JSContext* cx, jsval* vp, jsdouble& d) {
+    d = js_ValueToNumber(cx, vp);
+}
+
+static inline bool guard_jsval_is_null(jsval& v) {
+    return JSVAL_IS_NULL(v);
+}
+
+/*
+ * Optimized conversion function that test for the desired type in v before
+ * homing sp and calling a conversion function.
+ */
+static inline bool value_to_number(JSContext* cx, JSFrameRegs& regs, int n, jsval& v, jsdouble& d) {
+    JS_ASSERT(v == regs.sp[n]);
+    if (guard_jsval_is_int(v)) {
+        int i;
+        prim_jsval_to_int(v, i);
+        prim_int_to_double(i, d);
+    } else if (guard_jsval_is_double(v)) {
+        prim_jsval_to_double(v, d);
+    } else {
+        call_ValueToNumber(cx, &regs.sp[n], d);
+        if (guard_jsval_is_null(regs.sp[n]))
+            return JS_FALSE;
+        JS_ASSERT(JSVAL_IS_NUMBER(regs.sp[n]) || (regs.sp[n] == JSVAL_TRUE));
+    }
+    return JS_TRUE;
+}
+
+#define VALUE_TO_NUMBER(cx, n, v, d)                                          \
+    if (!value_to_number(cx, regs, n, v, d))                                  \
+        goto error;
+
+static inline bool fetch_number(JSContext* cx, JSFrameRegs& regs, int n, jsdouble& d) {
+    jsval v;
+
+    prim_fetch_stack(regs, n, v);
+    return value_to_number(cx, regs, n, v, d);
+}
 
 #define FETCH_NUMBER(cx, n, d)                                                \
-    JS_BEGIN_MACRO                                                            \
-        jsval v_;                                                             \
-                                                                              \
-        FETCH_STACK(n, v_);                                                   \
-        VALUE_TO_NUMBER(cx, n, v_, d);                                        \
-    JS_END_MACRO
+    if (!fetch_number(cx, regs, n, d))                                        \
+        goto error;
+
+static inline void call_ValueToECMAInt32(JSContext* cx, jsval* vp, jsint& i) {
+    i = js_ValueToECMAInt32(cx, vp);
+}
+
+static inline bool fetch_int(JSContext* cx, JSFrameRegs& regs, int n, jsint& i) {
+    jsval v;
+    
+    prim_fetch_stack(regs, n, v);
+    if (guard_jsval_is_int(v)) {
+        prim_jsval_to_int(v, i);
+    } else {
+        call_ValueToECMAInt32(cx, &regs.sp[n], i);
+        if (!guard_jsval_is_null(regs.sp[n]))
+            return JS_FALSE;
+    }
+    return JS_TRUE;
+}
 
 #define FETCH_INT(cx, n, i)                                                   \
-    JS_BEGIN_MACRO                                                            \
-        jsval v_;                                                             \
-                                                                              \
-        FETCH_STACK(n, v_);                                                   \
-        if (JSVAL_IS_INT(v_)) {                                               \
-            i = JSVAL_TO_INT(v_);                                             \
-        } else {                                                              \
-            i = js_ValueToECMAInt32(cx, &regs.sp[n]);                         \
-            if (JSVAL_IS_NULL(regs.sp[n]))                                    \
-                goto error;                                                   \
-        }                                                                     \
-    JS_END_MACRO
+    if (!fetch_int(cx, regs, n, i))                                           \
+        goto error;
+
+static inline void prim_int_to_uint(jsint& i, uint32& u) {
+    u = (uint32) i;
+}
+
+static inline void call_ValueToECMAUint32(JSContext* cx, jsval* vp, uint32& u) {
+    u = js_ValueToECMAUint32(cx, vp);
+}
+
+static inline bool fetch_uint(JSContext* cx, JSFrameRegs& regs, int n, uint32& u) {
+    jsval v;
+    
+    prim_fetch_stack(regs, n, v);
+    if (guard_jsval_is_int(v)) {
+        int i;
+        prim_jsval_to_int(v, i);
+        prim_int_to_uint(i, u);
+    } else {
+        call_ValueToECMAUint32(cx, &regs.sp[n], u);
+        if (guard_jsval_is_null(regs.sp[n]))
+            return JS_FALSE;
+    }
+    return JS_TRUE;
+}
 
 #define FETCH_UINT(cx, n, ui)                                                 \
-    JS_BEGIN_MACRO                                                            \
-        jsval v_;                                                             \
-                                                                              \
-        FETCH_STACK(n, v_);                                                   \
-        if (JSVAL_IS_INT(v_)) {                                               \
-            ui = (uint32) JSVAL_TO_INT(v_);                                   \
-        } else {                                                              \
-            ui = js_ValueToECMAUint32(cx, &regs.sp[n]);                       \
-            if (JSVAL_IS_NULL(regs.sp[n]))                                    \
-                goto error;                                                   \
-        }                                                                     \
-    JS_END_MACRO
-
-/*
- * Optimized conversion macros that test for the desired type in v before
- * homing sp and calling a conversion function.
- */
-#define VALUE_TO_NUMBER(cx, n, v, d)                                          \
-    JS_BEGIN_MACRO                                                            \
-        JS_ASSERT(v == regs.sp[n]);                                           \
-        if (JSVAL_IS_INT(v)) {                                                \
-            d = (jsdouble)JSVAL_TO_INT(v);                                    \
-        } else if (JSVAL_IS_DOUBLE(v)) {                                      \
-            d = *JSVAL_TO_DOUBLE(v);                                          \
-        } else {                                                              \
-            d = js_ValueToNumber(cx, &regs.sp[n]);                            \
-            if (JSVAL_IS_NULL(regs.sp[n]))                                    \
-                goto error;                                                   \
-            JS_ASSERT(JSVAL_IS_NUMBER(regs.sp[n]) ||                          \
-                      regs.sp[n] == JSVAL_TRUE);                              \
-        }                                                                     \
-    JS_END_MACRO
+    if (!fetch_uint(cx, regs, n, ui))                                         \
+        goto error;
+
+static inline void prim_generate_boolean_constant(JSBool c, JSBool& b) {
+    b = c;
+}
+
+static inline bool guard_jsval_is_boolean(jsval& v) {
+    return JSVAL_IS_BOOLEAN(v);
+}
+
+static inline void prim_jsval_to_boolean(jsval& v, JSBool& b) {
+    b = JSVAL_TO_BOOLEAN(v);
+}
+
+static inline bool call_ValueToBoolean(jsval& v, JSBool& b) {
+    b = js_ValueToBoolean(v);
+}
+
+static inline void pop_boolean(JSContext* cx, JSFrameRegs& regs, jsval& v, JSBool& b) {
+    prim_fetch_stack(regs, -1, v);
+    if (guard_jsval_is_null(v)) {
+        prim_generate_boolean_constant(JS_FALSE, b);
+    } else if (guard_jsval_is_boolean(v)) {
+        prim_jsval_to_boolean(v, b);
+    } else {
+        call_ValueToBoolean(v, b);
+    }
+    prim_adjust_stack(regs, -1);
+}
 
 #define POP_BOOLEAN(cx, v, b)                                                 \
-    JS_BEGIN_MACRO                                                            \
-        FETCH_STACK(-1, v);                                                   \
-        if (v == JSVAL_NULL) {                                                \
-            b = JS_FALSE;                                                     \
-        } else if (JSVAL_IS_BOOLEAN(v)) {                                     \
-            b = JSVAL_TO_BOOLEAN(v);                                          \
-        } else {                                                              \
-            b = js_ValueToBoolean(v);                                         \
-        }                                                                     \
-        regs.sp--;                                                            \
-    JS_END_MACRO
+    pop_boolean(cx, regs, v, b);                                              \
+
+static inline bool guard_jsval_is_primitive(jsval& v) {
+    return JSVAL_IS_PRIMITIVE(v);
+}
+
+static inline void prim_jsval_to_object(jsval& v, JSObject*& obj) {
+    obj = JSVAL_TO_OBJECT(v);
+}
+
+static inline void call_jsValueToNonNullObject(JSContext* cx, jsval& v, JSObject*& obj) {
+    obj = js_ValueToNonNullObject(cx, v);
+}
+
+static inline bool guard_obj_is_null(JSObject*& obj) {
+    return !obj;
+}
+
+static inline void call_ValueToNonNullObject(JSContext* cx, jsval& v, JSObject*& obj) {
+    obj = js_ValueToNonNullObject(cx, v);
+}
+
+static inline bool value_to_object(JSContext* cx, JSFrameRegs& regs, int n, jsval& v, JSObject*& obj) {
+    if (!guard_jsval_is_primitive(v)) {
+        prim_jsval_to_object(v, obj);
+    } else {
+        call_ValueToNonNullObject(cx, v, obj);
+        if (guard_obj_is_null(obj))
+            return JS_FALSE;
+        jsval x;
+        prim_object_to_jsval(obj, x);
+        prim_store_stack(regs, n, x);
+    }
+    return JS_TRUE;
+}
 
 #define VALUE_TO_OBJECT(cx, n, v, obj)                                        \
-    JS_BEGIN_MACRO                                                            \
-        if (!JSVAL_IS_PRIMITIVE(v)) {                                         \
-            obj = JSVAL_TO_OBJECT(v);                                         \
-        } else {                                                              \
-            obj = js_ValueToNonNullObject(cx, v);                             \
-            if (!obj)                                                         \
-                goto error;                                                   \
-            STORE_STACK(n, OBJECT_TO_JSVAL(obj));                             \
-        }                                                                     \
-    JS_END_MACRO
+    if (!value_to_object(cx, regs, n, v, obj))                                \
+        goto error;
+
+static inline bool fetch_object(JSContext* cx, JSFrameRegs& regs, int n, jsval& v, JSObject*& obj) {
+    prim_fetch_stack(regs, n, v);
+    return value_to_object(cx, regs, n, v, obj);
+}
 
 #define FETCH_OBJECT(cx, n, v, obj)                                           \
-    JS_BEGIN_MACRO                                                            \
-        FETCH_STACK(n, v);                                                    \
-        VALUE_TO_OBJECT(cx, n, v, obj);                                       \
-    JS_END_MACRO
+    if (!fetch_object(cx, regs, n, v, obj))                                   \
+        goto error;
+
+static inline bool call_obj_default_value(JSContext* cx, JSObject*& obj, JSType hint, jsval* vp) {
+    return OBJ_DEFAULT_VALUE(cx, obj, hint, vp);
+}
+
+static inline bool default_value(JSContext* cx, JSFrameRegs& regs, int n, JSType hint, jsval& v) {
+    JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
+    JS_ASSERT(v == regs.sp[n]);
+    JSObject* obj;
+    prim_jsval_to_object(v, obj);
+    if (!call_obj_default_value(cx, obj, hint, &regs.sp[n])) 
+        return JS_FALSE;
+    prim_fetch_stack(regs, n, v);
+    return JS_TRUE;
+}
 
 #define DEFAULT_VALUE(cx, n, hint, v)                                         \
-    JS_BEGIN_MACRO                                                            \
-        JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));                                    \
-        JS_ASSERT(v == regs.sp[n]);                                           \
-        if (!OBJ_DEFAULT_VALUE(cx, JSVAL_TO_OBJECT(v), hint, &regs.sp[n]))    \
-            goto error;                                                       \
-        v = regs.sp[n];                                                       \
-    JS_END_MACRO
+    if (!default_value(cx, regs, n, hint, v))                                 \
+        goto error;
 
 /*
  * Quickly test if v is an int from the [-2**29, 2**29) range, that is, when
  * the lowest bit of v is 1 and the bits 30 and 31 are both either 0 or 1. For
  * such v we can do increment or decrement via adding or subtracting two
  * without checking that the result overflows JSVAL_INT_MIN or JSVAL_INT_MAX.
  */
 #define CAN_DO_FAST_INC_DEC(v)     (((((v) << 1) ^ v) & 0x80000001) == 1)
@@ -2854,17 +3114,17 @@ js_Interpret(JSContext *cx)
 #endif
           END_EMPTY_CASES
 
           /* ADD_EMPTY_CASE is not used here as JSOP_LINENO_LENGTH == 3. */
           BEGIN_CASE(JSOP_LINENO)
           END_CASE(JSOP_LINENO)
 
           BEGIN_CASE(JSOP_PUSH)
-            PUSH_STACK(JSVAL_VOID);
+            PUSH_STACK_CONSTANT(JSVAL_VOID);
           END_CASE(JSOP_PUSH)
 
           BEGIN_CASE(JSOP_POP)
             ADJUST_STACK(-1);
           END_CASE(JSOP_POP)
 
           BEGIN_CASE(JSOP_POPN)
             ADJUST_STACK(-(int)GET_UINT16(regs.pc));
@@ -3126,17 +3386,18 @@ js_Interpret(JSContext *cx)
                 js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rval, NULL);
                 goto error;
             }
             obj = JSVAL_TO_OBJECT(rval);
             FETCH_ELEMENT_ID(obj, -2, id);
             if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
                 goto error;
             ADJUST_STACK(-1);
-            STORE_STACK(-1, BOOLEAN_TO_JSVAL(prop != NULL));
+            cond = prop != NULL;
+            STORE_STACK_BOOLEAN(-1, cond);
             if (prop)
                 OBJ_DROP_PROPERTY(cx, obj2, prop);
           END_CASE(JSOP_IN)
 
           BEGIN_CASE(JSOP_FOREACH)
             flags = JSITER_ENUMERATE | JSITER_FOREACH;
             goto value_to_iter;
 
@@ -3448,17 +3709,17 @@ js_Interpret(JSContext *cx)
                     entry = NULL;
                     LOAD_ATOM(0);
                 }
                 id = ATOM_TO_JSID(atom);
                 obj = js_FindIdentifierBase(cx, id, entry);
                 if (!obj)
                     goto error;
             } while (0);
-            PUSH_STACK(OBJECT_TO_JSVAL(obj));
+            PUSH_STACK_OBJECT(obj);
           END_CASE(JSOP_BINDNAME)
 
 #define BITWISE_OP(OP)                                                        \
     JS_BEGIN_MACRO                                                            \
         FETCH_INT(cx, -2, i);                                                 \
         FETCH_INT(cx, -1, j);                                                 \
         i = i OP j;                                                           \
         ADJUST_STACK(-1);                                                     \
@@ -3495,17 +3756,17 @@ js_Interpret(JSContext *cx)
                 cond = js_CompareStrings(str, str2) OP 0;                     \
             } else {                                                          \
                 VALUE_TO_NUMBER(cx, -2, lval, d);                             \
                 VALUE_TO_NUMBER(cx, -1, rval, d2);                            \
                 cond = JSDOUBLE_COMPARE(d, OP, d2, JS_FALSE);                 \
             }                                                                 \
         }                                                                     \
         ADJUST_STACK(-1);                                                     \
-        STORE_STACK(-1, BOOLEAN_TO_JSVAL(cond));                              \
+        STORE_STACK_BOOLEAN(-1, cond);                                        \
     JS_END_MACRO
 
 /*
  * NB: These macros can't use JS_BEGIN_MACRO/JS_END_MACRO around their bodies
  * because they begin if/else chains, so callers must not put semicolons after
  * the call expressions!
  */
 #if JS_HAS_XML_SUPPORT
@@ -3583,34 +3844,34 @@ js_Interpret(JSContext *cx)
                 } else {                                                      \
                     VALUE_TO_NUMBER(cx, -2, lval, d);                         \
                     VALUE_TO_NUMBER(cx, -1, rval, d2);                        \
                     cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN);                \
                 }                                                             \
             }                                                                 \
         }                                                                     \
         ADJUST_STACK(-1);                                                     \
-        STORE_STACK(-1, BOOLEAN_TO_JSVAL(cond));                              \
+        STORE_STACK_BOOLEAN(-1, cond);                                        \
     JS_END_MACRO
 
           BEGIN_CASE(JSOP_EQ)
             EQUALITY_OP(==, JS_FALSE);
           END_CASE(JSOP_EQ)
 
           BEGIN_CASE(JSOP_NE)
             EQUALITY_OP(!=, JS_TRUE);
           END_CASE(JSOP_NE)
 
 #define STRICT_EQUALITY_OP(OP)                                                \
     JS_BEGIN_MACRO                                                            \
         FETCH_STACK(-1, rval);                                                \
         FETCH_STACK(-2, lval);                                                \
         cond = js_StrictlyEqual(cx, lval, rval) OP JS_TRUE;                   \
         ADJUST_STACK(-1);                                                     \
-        STORE_STACK(-1, BOOLEAN_TO_JSVAL(cond));                              \
+        STORE_STACK_BOOLEAN(-1, cond);                                        \
     JS_END_MACRO
 
           BEGIN_CASE(JSOP_STRICTEQ)
             STRICT_EQUALITY_OP(==);
           END_CASE(JSOP_STRICTEQ)
 
           BEGIN_CASE(JSOP_STRICTNE)
             STRICT_EQUALITY_OP(!=);
@@ -3723,17 +3984,17 @@ js_Interpret(JSContext *cx)
                         if (!str)
                             goto error;
                         regs.sp[-2] = STRING_TO_JSVAL(str);
                     }
                     str = js_ConcatStrings(cx, str, str2);
                     if (!str)
                         goto error;
                     ADJUST_STACK(-1);
-                    STORE_STACK(-1, STRING_TO_JSVAL(str));
+                    STORE_STACK_STRING(-1, str);
                 } else {
                     VALUE_TO_NUMBER(cx, -2, lval, d);
                     VALUE_TO_NUMBER(cx, -1, rval, d2);
                     d += d2;
                     ADJUST_STACK(-1);
                     STORE_NUMBER(cx, -1, d);
                 }
             }
@@ -3780,30 +4041,31 @@ js_Interpret(JSContext *cx)
             }
           END_CASE(JSOP_DIV)
 
           BEGIN_CASE(JSOP_MOD)
             FETCH_NUMBER(cx, -1, d2);
             FETCH_NUMBER(cx, -2, d);
             ADJUST_STACK(-1);
             if (d2 == 0) {
-                STORE_STACK(-1, DOUBLE_TO_JSVAL(rt->jsNaN));
+                STORE_STACK_CONSTANT(-1, DOUBLE_TO_JSVAL(rt->jsNaN));
             } else {
 #ifdef XP_WIN
               /* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
               if (!(JSDOUBLE_IS_FINITE(d) && JSDOUBLE_IS_INFINITE(d2)))
 #endif
                 d = fmod(d, d2);
                 STORE_NUMBER(cx, -1, d);
             }
           END_CASE(JSOP_MOD)
 
           BEGIN_CASE(JSOP_NOT)
             POP_BOOLEAN(cx, rval, cond);
-            PUSH_STACK(BOOLEAN_TO_JSVAL(!cond));
+            cond = !cond;
+            PUSH_STACK_BOOLEAN(cond);
           END_CASE(JSOP_NOT)
 
           BEGIN_CASE(JSOP_BITNOT)
             FETCH_INT(cx, -1, i);
             i = ~i;
             STORE_INT(cx, -1, i);
           END_CASE(JSOP_BITNOT)
 
@@ -3876,17 +4138,17 @@ js_Interpret(JSContext *cx)
 
           BEGIN_CASE(JSOP_DELNAME)
             LOAD_ATOM(0);
             id = ATOM_TO_JSID(atom);
             if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
                 goto error;
 
             /* ECMA says to return true if name is undefined or inherited. */
-            PUSH_STACK(JSVAL_TRUE);
+            PUSH_STACK_CONSTANT(JSVAL_TRUE);
             if (prop) {
                 OBJ_DROP_PROPERTY(cx, obj2, prop);
                 if (!OBJ_DELETE_PROPERTY(cx, obj, id, &regs.sp[-1]))
                     goto error;
             }
           END_CASE(JSOP_DELNAME)
 
           BEGIN_CASE(JSOP_DELPROP)
@@ -3902,21 +4164,21 @@ js_Interpret(JSContext *cx)
             STORE_STACK(-1, rval);
           END_CASE(JSOP_DELELEM)
 
           BEGIN_CASE(JSOP_TYPEOFEXPR)
           BEGIN_CASE(JSOP_TYPEOF)
             FETCH_STACK(-1, rval);
             type = JS_TypeOfValue(cx, rval);
             atom = rt->atomState.typeAtoms[type];
-            STORE_STACK(-1, ATOM_KEY(atom));
+            STORE_STACK_CONSTANT(-1, ATOM_KEY(atom));
           END_CASE(JSOP_TYPEOF)
 
           BEGIN_CASE(JSOP_VOID)
-            STORE_STACK(-1, JSVAL_VOID);
+            STORE_STACK_CONSTANT(-1, JSVAL_VOID);
           END_CASE(JSOP_VOID)
 
           BEGIN_CASE(JSOP_INCELEM)
           BEGIN_CASE(JSOP_DECELEM)
           BEGIN_CASE(JSOP_ELEMINC)
           BEGIN_CASE(JSOP_ELEMDEC)
             /*
              * Delay fetching of id until we have the object to ensure
@@ -3956,17 +4218,17 @@ js_Interpret(JSContext *cx)
           {
             const JSCodeSpec *cs;
             jsval v;
 
             /*
              * We need a root to store the value to leave on the stack until
              * we have done with OBJ_SET_PROPERTY.
              */
-            PUSH_STACK(JSVAL_NULL);
+            PUSH_STACK_CONSTANT(JSVAL_NULL);
             if (!OBJ_GET_PROPERTY(cx, obj, id, &regs.sp[-1]))
                 goto error;
 
             cs = &js_CodeSpec[op];
             JS_ASSERT(cs->ndefs == 1);
             JS_ASSERT((cs->format & JOF_TMPSLOT_MASK) == JOF_TMPSLOT2);
             v = regs.sp[-1];
             if (JS_LIKELY(CAN_DO_FAST_INC_DEC(v))) {
@@ -3987,17 +4249,17 @@ js_Interpret(JSContext *cx)
 
                 /*
                  * We must set regs.sp[-1] to v for both post and pre increments
                  * as the setter overwrites regs.sp[-1].
                  */
                 regs.sp[-1] = v;
             } else {
                 /* We need an extra root for the result. */
-                PUSH_STACK(JSVAL_NULL);
+                PUSH_STACK_CONSTANT(JSVAL_NULL);
                 if (!js_DoIncDec(cx, cs, &regs.sp[-2], &regs.sp[-1]))
                     goto error;
                 fp->flags |= JSFRAME_ASSIGNING;
                 ok = OBJ_SET_PROPERTY(cx, obj, id, &regs.sp[-1]);
                 fp->flags &= ~JSFRAME_ASSIGNING;
                 if (!ok)
                     goto error;
                 ADJUST_STACK(-1);
@@ -4068,17 +4330,18 @@ js_Interpret(JSContext *cx)
             JS_ASSERT(slot < fp->fun->u.i.nvars);
             METER_SLOT_OP(op, slot);
             vp = fp->vars + slot;
 
           do_int_fast_incop:
             rval = *vp;
             if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) {
                 *vp = rval + incr;
-                PUSH_STACK(rval + incr2);
+                rtmp = rval + incr2;
+                PUSH_STACK(rtmp);
             } else {
                 PUSH_STACK(rval);
                 if (!js_DoIncDec(cx, &js_CodeSpec[op], &regs.sp[-1], vp))
                     goto error;
             }
             len = JSOP_INCARG_LENGTH;
             JS_ASSERT(len == js_CodeSpec[op].length);
             DO_NEXT_OP(len);
@@ -4114,21 +4377,22 @@ js_Interpret(JSContext *cx)
             lval = fp->vars[slot];
             if (JSVAL_IS_NULL(lval)) {
                 op = op2;
                 DO_OP();
             }
             slot = JSVAL_TO_INT(lval);
             rval = OBJ_GET_SLOT(cx, fp->varobj, slot);
             if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) {
-                PUSH_STACK(rval + incr2);
+                rtmp = rval + incr2;
+                PUSH_STACK(rtmp);
                 rval += incr;
             } else {
                 PUSH_STACK(rval);
-                PUSH_STACK(JSVAL_NULL); /* extra root */
+                PUSH_STACK_CONSTANT(JSVAL_NULL); /* extra root */
                 if (!js_DoIncDec(cx, &js_CodeSpec[op], &regs.sp[-2], &regs.sp[-1]))
                     goto error;
                 rval = regs.sp[-1];
                 --regs.sp;
             }
             OBJ_SET_SLOT(cx, fp->varobj, slot, rval);
             len = JSOP_INCGVAR_LENGTH;  /* all gvar incops are same length */
             JS_ASSERT(len == js_CodeSpec[op].length);
@@ -4145,23 +4409,23 @@ js_Interpret(JSContext *cx)
                 goto error;                                                   \
             fp->thisp = obj;                                                  \
             fp->flags |= JSFRAME_COMPUTED_THIS;                               \
         }                                                                     \
     JS_END_MACRO
 
           BEGIN_CASE(JSOP_THIS)
             COMPUTE_THIS(cx, fp, obj);
-            PUSH_STACK(OBJECT_TO_JSVAL(obj));
+            PUSH_STACK_OBJECT(obj);
           END_CASE(JSOP_THIS)
 
           BEGIN_CASE(JSOP_GETTHISPROP)
             i = 0;
             COMPUTE_THIS(cx, fp, obj);
-            PUSH_STACK(JSVAL_NULL);
+            PUSH_STACK_CONSTANT(JSVAL_NULL);
             goto do_getprop_with_obj;
 
 #undef COMPUTE_THIS
 
           BEGIN_CASE(JSOP_GETARGPROP)
             i = ARGNO_LEN;
             slot = GET_ARGNO(regs.pc);
             JS_ASSERT(slot < fp->fun->nargs);
@@ -4312,17 +4576,17 @@ js_Interpret(JSContext *cx)
                 LOAD_ATOM(0);
             }
 
             /*
              * Cache miss: use the immediate atom that was loaded for us under
              * PROPERTY_CACHE_TEST.
              */
             id = ATOM_TO_JSID(atom);
-            PUSH_STACK(JSVAL_NULL);
+            PUSH_STACK_CONSTANT(JSVAL_NULL);
             if (!JSVAL_IS_PRIMITIVE(lval)) {
 #if JS_HAS_XML_SUPPORT
                 /* Special-case XML object method lookup, per ECMA-357. */
                 if (OBJECT_IS_XML(cx, obj)) {
                     JSXMLObjectOps *ops;
 
                     ops = (JSXMLObjectOps *) obj->map->ops;
                     obj = ops->getMethod(cx, obj, id, &rval);
@@ -4330,17 +4594,17 @@ js_Interpret(JSContext *cx)
                         goto error;
                 } else
 #endif
                 if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)
                     ? !js_GetPropertyHelper(cx, aobj, id, &rval, &entry)
                     : !OBJ_GET_PROPERTY(cx, obj, id, &rval)) {
                     goto error;
                 }
-                STORE_STACK(-1, OBJECT_TO_JSVAL(obj));
+                STORE_STACK_OBJECT(-1, obj);
                 STORE_STACK(-2, rval);
             } else {
                 JS_ASSERT(obj->map->ops->getProperty == js_GetProperty);
                 if (!js_GetPropertyHelper(cx, obj, id, &rval, &entry))
                     goto error;
                 STORE_STACK(-1, lval);
                 STORE_STACK(-2, rval);
             }
@@ -4628,17 +4892,17 @@ js_Interpret(JSContext *cx)
                 regs.sp[-2] = regs.sp[-1];
                 regs.sp[-1] = OBJECT_TO_JSVAL(obj);
                 if (!js_OnUnknownMethod(cx, regs.sp - 2))
                     goto error;
             } else
 #endif
             {
                 STORE_STACK(-2, rval);
-                STORE_STACK(-1, OBJECT_TO_JSVAL(obj));
+                STORE_STACK_OBJECT(-1, obj);
             }
           END_CASE(JSOP_CALLELEM)
 
           BEGIN_CASE(JSOP_SETELEM)
             FETCH_STACK(-1, rval);
             FETCH_OBJECT(cx, -3, lval, obj);
             FETCH_ELEMENT_ID(obj, -2, id);
             if (OBJ_IS_DENSE_ARRAY(cx, obj) && JSID_IS_INT(id)) {
@@ -4872,17 +5136,17 @@ js_Interpret(JSContext *cx)
                         /*
                          * If we can't fit missing args and local roots in
                          * this frame's operand stack, take the slow path.
                          */
                         nargs = fun->u.n.minargs - argc;
                         if (regs.sp + nargs > fp->spbase + script->depth)
                             goto do_invoke;
                         do {
-                            PUSH_STACK(JSVAL_VOID);
+                            PUSH_STACK_CONSTANT(JSVAL_VOID);
                         } while (--nargs != 0);
                     }
 
                     JS_ASSERT(JSVAL_IS_OBJECT(vp[1]) ||
                               PRIMITIVE_THIS_TEST(fun, vp[1]));
 
                     ok = ((JSFastNative) fun->u.n.native)(cx, argc, vp);
 #ifdef INCLUDE_MOZILLA_DTRACE
@@ -5014,17 +5278,17 @@ js_Interpret(JSContext *cx)
             if (js_FindPropertyHelper(cx, id, &obj, &obj2, &prop, &entry) < 0)
                 goto error;
             if (!prop) {
                 /* Kludge to allow (typeof foo == "undefined") tests. */
                 endpc = script->code + script->length;
                 for (pc2 = regs.pc + JSOP_NAME_LENGTH; pc2 < endpc; pc2++) {
                     op2 = (JSOp)*pc2;
                     if (op2 == JSOP_TYPEOF) {
-                        PUSH_STACK(JSVAL_VOID);
+                        PUSH_STACK_CONSTANT(JSVAL_VOID);
                         len = JSOP_NAME_LENGTH;
                         DO_NEXT_OP(len);
                     }
                     if (op2 != JSOP_GROUP)
                         break;
                 }
                 goto atom_not_defined;
             }
@@ -5040,42 +5304,42 @@ js_Interpret(JSContext *cx)
           do_native_get:
                 NATIVE_GET(cx, obj, obj2, sprop, &rval);
                 OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *) sprop);
             }
 
           do_push_rval:
             PUSH_STACK(rval);
             if (op == JSOP_CALLNAME)
-                PUSH_STACK(OBJECT_TO_JSVAL(obj));
+                PUSH_STACK_OBJECT(obj);
           }
           END_CASE(JSOP_NAME)
 
           BEGIN_CASE(JSOP_UINT16)
             i = (jsint) GET_UINT16(regs.pc);
             rval = INT_TO_JSVAL(i);
-            PUSH_STACK(rval);
+            PUSH_STACK_CONSTANT(rval);
           END_CASE(JSOP_UINT16)
 
           BEGIN_CASE(JSOP_UINT24)
             i = (jsint) GET_UINT24(regs.pc);
             rval = INT_TO_JSVAL(i);
-            PUSH_STACK(rval);
+            PUSH_STACK_CONSTANT(rval);
           END_CASE(JSOP_UINT24)
 
           BEGIN_CASE(JSOP_INT8)
             i = GET_INT8(regs.pc);
             rval = INT_TO_JSVAL(i);
-            PUSH_STACK(rval);
+            PUSH_STACK_CONSTANT(rval);
           END_CASE(JSOP_INT8)
 
           BEGIN_CASE(JSOP_INT32)
             i = GET_INT32(regs.pc);
             rval = INT_TO_JSVAL(i);
-            PUSH_STACK(rval);
+            PUSH_STACK_CONSTANT(rval);
           END_CASE(JSOP_INT32)
 
           BEGIN_CASE(JSOP_INDEXBASE)
             /*
              * Here atoms can exceed script->atomMap.length as we use atoms
              * as a segment register for object literals as well.
              */
             atoms += GET_INDEXBASE(regs.pc);
@@ -5090,22 +5354,22 @@ js_Interpret(JSContext *cx)
           BEGIN_CASE(JSOP_RESETBASE0)
           BEGIN_CASE(JSOP_RESETBASE)
             atoms = script->atomMap.vector;
           END_CASE(JSOP_RESETBASE)
 
           BEGIN_CASE(JSOP_DOUBLE)
           BEGIN_CASE(JSOP_STRING)
             LOAD_ATOM(0);
-            PUSH_STACK(ATOM_KEY(atom));
+            PUSH_STACK_CONSTANT(ATOM_KEY(atom));
           END_CASE(JSOP_DOUBLE)
 
           BEGIN_CASE(JSOP_OBJECT)
             LOAD_OBJECT(0);
-            PUSH_STACK(OBJECT_TO_JSVAL(obj));
+            PUSH_STACK_OBJECT(obj);
           END_CASE(JSOP_OBJECT)
 
           BEGIN_CASE(JSOP_REGEXP)
           {
             JSObject *funobj;
 
             /*
              * Push a regexp object for the atom mapped by the bytecode at pc,
@@ -5209,33 +5473,33 @@ js_Interpret(JSContext *cx)
                 }
             }
 
             PUSH_STACK(rval);
           }
           END_CASE(JSOP_REGEXP)
 
           BEGIN_CASE(JSOP_ZERO)
-            PUSH_STACK(JSVAL_ZERO);
+            PUSH_STACK_CONSTANT(JSVAL_ZERO);
           END_CASE(JSOP_ZERO)
 
           BEGIN_CASE(JSOP_ONE)
-            PUSH_STACK(JSVAL_ONE);
+            PUSH_STACK_CONSTANT(JSVAL_ONE);
           END_CASE(JSOP_ONE)
 
           BEGIN_CASE(JSOP_NULL)
-            PUSH_STACK(JSVAL_NULL);
+            PUSH_STACK_CONSTANT(JSVAL_NULL);
           END_CASE(JSOP_NULL)
 
           BEGIN_CASE(JSOP_FALSE)
-            PUSH_STACK(JSVAL_FALSE);
+            PUSH_STACK_CONSTANT(JSVAL_FALSE);
           END_CASE(JSOP_FALSE)
 
           BEGIN_CASE(JSOP_TRUE)
-            PUSH_STACK(JSVAL_TRUE);
+            PUSH_STACK_CONSTANT(JSVAL_TRUE);
           END_CASE(JSOP_TRUE)
 
           BEGIN_CASE(JSOP_TABLESWITCH)
             pc2 = regs.pc;
             len = GET_JUMP_OFFSET(pc2);
 
             /*
              * ECMAv2+ forbids conversion of discriminant, so we will skip to
@@ -5479,17 +5743,17 @@ js_Interpret(JSContext *cx)
 
           BEGIN_CASE(JSOP_GETARG)
           BEGIN_CASE(JSOP_CALLARG)
             slot = GET_ARGNO(regs.pc);
             JS_ASSERT(slot < fp->fun->nargs);
             METER_SLOT_OP(op, slot);
             PUSH_STACK(fp->argv[slot]);
             if (op == JSOP_CALLARG)
-                PUSH_STACK(JSVAL_NULL);
+                PUSH_STACK_CONSTANT(JSVAL_NULL);
           END_CASE(JSOP_GETARG)
 
           BEGIN_CASE(JSOP_SETARG)
             slot = GET_ARGNO(regs.pc);
             JS_ASSERT(slot < fp->fun->nargs);
             METER_SLOT_OP(op, slot);
             vp = &fp->argv[slot];
             GC_POKE(cx, *vp);
@@ -5498,17 +5762,17 @@ js_Interpret(JSContext *cx)
 
           BEGIN_CASE(JSOP_GETVAR)
           BEGIN_CASE(JSOP_CALLVAR)
             slot = GET_VARNO(regs.pc);
             JS_ASSERT(slot < fp->fun->u.i.nvars);
             METER_SLOT_OP(op, slot);
             PUSH_STACK(fp->vars[slot]);
             if (op == JSOP_CALLVAR)
-                PUSH_STACK(JSVAL_NULL);
+                PUSH_STACK_CONSTANT(JSVAL_NULL);
           END_CASE(JSOP_GETVAR)
 
           BEGIN_CASE(JSOP_SETVAR)
             slot = GET_VARNO(regs.pc);
             JS_ASSERT(slot < fp->fun->u.i.nvars);
             METER_SLOT_OP(op, slot);
             vp = &fp->vars[slot];
             GC_POKE(cx, *vp);
@@ -5525,17 +5789,17 @@ js_Interpret(JSContext *cx)
                 op = (op == JSOP_GETGVAR) ? JSOP_NAME : JSOP_CALLNAME;
                 DO_OP();
             }
             slot = JSVAL_TO_INT(lval);
             obj = fp->varobj;
             rval = OBJ_GET_SLOT(cx, obj, slot);
             PUSH_STACK(rval);
             if (op == JSOP_CALLGVAR)
-                PUSH_STACK(OBJECT_TO_JSVAL(obj));
+                PUSH_STACK_OBJECT(obj);
           END_CASE(JSOP_GETGVAR)
 
           BEGIN_CASE(JSOP_SETGVAR)
             slot = GET_VARNO(regs.pc);
             JS_ASSERT(slot < fp->nvars);
             METER_SLOT_OP(op, slot);
             FETCH_STACK(-1, rval);
             lval = fp->vars[slot];
@@ -5768,17 +6032,17 @@ js_Interpret(JSContext *cx)
             if (!parent)
                 goto error;
             obj = FUN_OBJECT(fun);
             if (OBJ_GET_PARENT(cx, obj) != parent) {
                 obj = js_CloneFunctionObject(cx, fun, parent);
                 if (!obj)
                     goto error;
             }
-            PUSH_STACK(OBJECT_TO_JSVAL(obj));
+            PUSH_STACK_OBJECT(obj);
           END_CASE(JSOP_ANONFUNOBJ)
 
           BEGIN_CASE(JSOP_NAMEDFUNOBJ)
             LOAD_FUNCTION(0);
 
             /*
              * ECMA ed. 3 FunctionExpression: function Identifier [etc.].
              *
@@ -5845,17 +6109,17 @@ js_Interpret(JSContext *cx)
                 cx->weakRoots.newborn[GCX_OBJECT] = NULL;
                 goto error;
             }
 
             /*
              * 5. Remove Result(1) from the front of the scope chain [no-op].
              * 6. Return Result(3).
              */
-            PUSH_STACK(OBJECT_TO_JSVAL(obj));
+            PUSH_STACK_OBJECT(obj);
           END_CASE(JSOP_NAMEDFUNOBJ)
 
           BEGIN_CASE(JSOP_CLOSURE)
             /*
              * A top-level function inside eval or ECMA ed. 3 extension: a
              * named function expression statement in a compound statement
              * (not at the top statement level of global code, or at the top
              * level of a function body).
@@ -5986,17 +6250,17 @@ js_Interpret(JSContext *cx)
           BEGIN_CASE(JSOP_NEWINIT)
             i = GET_INT8(regs.pc);
             JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
             obj = (i == JSProto_Array)
                   ? js_NewArrayObject(cx, 0, NULL)
                   : js_NewObject(cx, &js_ObjectClass, NULL, NULL, 0);
             if (!obj)
                 goto error;
-            PUSH_STACK(OBJECT_TO_JSVAL(obj));
+            PUSH_STACK_OBJECT(obj);
             fp->sharpDepth++;
             LOAD_INTERRUPT_HANDLER(cx);
           END_CASE(JSOP_NEWINIT)
 
           BEGIN_CASE(JSOP_ENDINIT)
             if (--fp->sharpDepth == 0)
                 fp->sharpArray = NULL;
 
@@ -6201,27 +6465,27 @@ js_Interpret(JSContext *cx)
                                      JSMSG_BAD_SHARP_USE, numBuf);
                 goto error;
             }
             PUSH_STACK(rval);
           END_CASE(JSOP_USESHARP)
 #endif /* JS_HAS_SHARP_VARS */
 
           BEGIN_CASE(JSOP_GOSUB)
-            PUSH_STACK(JSVAL_FALSE);
+            PUSH_STACK_CONSTANT(JSVAL_FALSE);
             i = PTRDIFF(regs.pc, script->main, jsbytecode) + JSOP_GOSUB_LENGTH;
-            PUSH_STACK(INT_TO_JSVAL(i));
+            PUSH_STACK_CONSTANT(INT_TO_JSVAL(i));
             len = GET_JUMP_OFFSET(regs.pc);
           END_VARLEN_CASE
 
           BEGIN_CASE(JSOP_GOSUBX)
-            PUSH_STACK(JSVAL_FALSE);
+            PUSH_STACK_CONSTANT(JSVAL_FALSE);
             i = PTRDIFF(regs.pc, script->main, jsbytecode) + JSOP_GOSUBX_LENGTH;
             len = GET_JUMPX_OFFSET(regs.pc);
-            PUSH_STACK(INT_TO_JSVAL(i));
+            PUSH_STACK_CONSTANT(INT_TO_JSVAL(i));
           END_VARLEN_CASE
 
           BEGIN_CASE(JSOP_RETSUB)
             POP_STACK(rval);
             POP_STACK(lval);
             JS_ASSERT(JSVAL_IS_BOOLEAN(lval));
             if (JSVAL_TO_BOOLEAN(lval)) {
                 /*
@@ -6277,17 +6541,17 @@ js_Interpret(JSContext *cx)
                                     -1, rval, NULL);
                 goto error;
             }
             FETCH_STACK(-2, lval);
             cond = JS_FALSE;
             if (!obj->map->ops->hasInstance(cx, obj, lval, &cond))
                 goto error;
             ADJUST_STACK(-1);
-            STORE_STACK(-1, BOOLEAN_TO_JSVAL(cond));
+            STORE_STACK_BOOLEAN(-1, cond);
           END_CASE(JSOP_INSTANCEOF)
 
 #if JS_HAS_DEBUGGER_KEYWORD
           BEGIN_CASE(JSOP_DEBUGGER)
           {
             JSTrapHandler handler = cx->debugHooks->debuggerHandler;
             if (handler) {
                 switch (handler(cx, script, regs.pc, &rval,
@@ -6322,74 +6586,74 @@ js_Interpret(JSContext *cx)
           BEGIN_CASE(JSOP_ANYNAME)
             if (!js_GetAnyName(cx, &rval))
                 goto error;
             PUSH_STACK(rval);
           END_CASE(JSOP_ANYNAME)
 
           BEGIN_CASE(JSOP_QNAMEPART)
             LOAD_ATOM(0);
-            PUSH_STACK(ATOM_KEY(atom));
+            PUSH_STACK_CONSTANT(ATOM_KEY(atom));
           END_CASE(JSOP_QNAMEPART)
 
           BEGIN_CASE(JSOP_QNAMECONST)
             LOAD_ATOM(0);
             rval = ATOM_KEY(atom);
             FETCH_STACK(-1, lval);
             obj = js_ConstructXMLQNameObject(cx, lval, rval);
             if (!obj)
                 goto error;
-            STORE_STACK(-1, OBJECT_TO_JSVAL(obj));
+            STORE_STACK_CONSTANT(-1, OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_QNAMECONST)
 
           BEGIN_CASE(JSOP_QNAME)
             FETCH_STACK(-1, rval);
             FETCH_STACK(-2, lval);
             obj = js_ConstructXMLQNameObject(cx, lval, rval);
             if (!obj)
                 goto error;
             ADJUST_STACK(-1);
-            STORE_STACK(-1, OBJECT_TO_JSVAL(obj));
+            STORE_STACK_OBJECT(-1, obj);
           END_CASE(JSOP_QNAME)
 
           BEGIN_CASE(JSOP_TOATTRNAME)
             FETCH_STACK(-1, rval);
             if (!js_ToAttributeName(cx, &rval))
                 goto error;
             STORE_STACK(-1, rval);
           END_CASE(JSOP_TOATTRNAME)
 
           BEGIN_CASE(JSOP_TOATTRVAL)
             FETCH_STACK(-1, rval);
             JS_ASSERT(JSVAL_IS_STRING(rval));
             str = js_EscapeAttributeValue(cx, JSVAL_TO_STRING(rval), JS_FALSE);
             if (!str)
                 goto error;
-            STORE_STACK(-1, STRING_TO_JSVAL(str));
+            STORE_STACK_STRING(-1, str);
           END_CASE(JSOP_TOATTRVAL)
 
           BEGIN_CASE(JSOP_ADDATTRNAME)
           BEGIN_CASE(JSOP_ADDATTRVAL)
             FETCH_STACK(-1, rval);
             FETCH_STACK(-2, lval);
             str = JSVAL_TO_STRING(lval);
             str2 = JSVAL_TO_STRING(rval);
             str = js_AddAttributePart(cx, op == JSOP_ADDATTRNAME, str, str2);
             if (!str)
                 goto error;
             ADJUST_STACK(-1);
-            STORE_STACK(-1, STRING_TO_JSVAL(str));
+            STORE_STACK_STRING(-1, str);
           END_CASE(JSOP_ADDATTRNAME)
 
           BEGIN_CASE(JSOP_BINDXMLNAME)
             FETCH_STACK(-1, lval);
             if (!js_FindXMLProperty(cx, lval, &obj, &id))
                 goto error;
-            STORE_STACK(-1, OBJECT_TO_JSVAL(obj));
-            PUSH_STACK(ID_TO_VALUE(id));
+            STORE_STACK_OBJECT(-1, obj);
+            PUSH_STACK_ID(id);
           END_CASE(JSOP_BINDXMLNAME)
 
           BEGIN_CASE(JSOP_SETXMLNAME)
             FETCH_STACK(-3, lval);
             obj = JSVAL_TO_OBJECT(lval);
             FETCH_STACK(-1, rval);
             FETCH_ELEMENT_ID(obj, -2, id);
             if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
@@ -6402,17 +6666,17 @@ js_Interpret(JSContext *cx)
           BEGIN_CASE(JSOP_XMLNAME)
             FETCH_STACK(-1, lval);
             if (!js_FindXMLProperty(cx, lval, &obj, &id))
                 goto error;
             if (!OBJ_GET_PROPERTY(cx, obj, id, &rval))
                 goto error;
             STORE_STACK(-1, rval);
             if (op == JSOP_CALLXMLNAME)
-                PUSH_STACK(OBJECT_TO_JSVAL(obj));
+                PUSH_STACK_OBJECT(obj);
           END_CASE(JSOP_XMLNAME)
 
           BEGIN_CASE(JSOP_DESCENDANTS)
           BEGIN_CASE(JSOP_DELDESC)
             FETCH_OBJECT(cx, -2, lval, obj);
             FETCH_STACK(-1, rval);
             if (!js_GetXMLDescendants(cx, obj, rval, &rval))
                 goto error;
@@ -6429,17 +6693,17 @@ js_Interpret(JSContext *cx)
           END_CASE(JSOP_DESCENDANTS)
 
           BEGIN_CASE(JSOP_FILTER)
             /*
              * We push the hole value before jumping to [enditer] so we can
              * detect the first iteration and direct js_StepXMLListFilter to
              * initialize filter's state.
              */
-            PUSH_STACK(JSVAL_HOLE);
+            PUSH_STACK_CONSTANT(JSVAL_HOLE);
             len = GET_JUMP_OFFSET(regs.pc);
             JS_ASSERT(len > 0);
           END_VARLEN_CASE
 
           BEGIN_CASE(JSOP_ENDFILTER)
             cond = (regs.sp[-1] != JSVAL_HOLE);
             if (cond) {
                 /* Exit the "with" block left from the previous iteration. */
@@ -6464,86 +6728,86 @@ js_Interpret(JSContext *cx)
             ADJUST_STACK(-1);
           END_CASE(JSOP_ENDFILTER);
 
           BEGIN_CASE(JSOP_TOXML)
             FETCH_STACK(-1, rval);
             obj = js_ValueToXMLObject(cx, rval);
             if (!obj)
                 goto error;
-            STORE_STACK(-1, OBJECT_TO_JSVAL(obj));
+            STORE_STACK_OBJECT(-1, obj);
           END_CASE(JSOP_TOXML)
 
           BEGIN_CASE(JSOP_TOXMLLIST)
             FETCH_STACK(-1, rval);
             obj = js_ValueToXMLListObject(cx, rval);
             if (!obj)
                 goto error;
-            STORE_STACK(-1, OBJECT_TO_JSVAL(obj));
+            STORE_STACK_OBJECT(-1, obj);
           END_CASE(JSOP_TOXMLLIST)
 
           BEGIN_CASE(JSOP_XMLTAGEXPR)
             FETCH_STACK(-1, rval);
             str = js_ValueToString(cx, rval);
             if (!str)
                 goto error;
-            STORE_STACK(-1, STRING_TO_JSVAL(str));
+            STORE_STACK_STRING(-1, str);
           END_CASE(JSOP_XMLTAGEXPR)
 
           BEGIN_CASE(JSOP_XMLELTEXPR)
             FETCH_STACK(-1, rval);
             if (VALUE_IS_XML(cx, rval)) {
                 str = js_ValueToXMLString(cx, rval);
             } else {
                 str = js_ValueToString(cx, rval);
                 if (str)
                     str = js_EscapeElementValue(cx, str);
             }
             if (!str)
                 goto error;
-            STORE_STACK(-1, STRING_TO_JSVAL(str));
+            STORE_STACK_STRING(-1, str);
           END_CASE(JSOP_XMLELTEXPR)
 
           BEGIN_CASE(JSOP_XMLOBJECT)
             LOAD_OBJECT(0);
             obj = js_CloneXMLObject(cx, obj);
             if (!obj)
                 goto error;
-            PUSH_STACK(OBJECT_TO_JSVAL(obj));
+            PUSH_STACK_OBJECT(obj);
           END_CASE(JSOP_XMLOBJECT)
 
           BEGIN_CASE(JSOP_XMLCDATA)
             LOAD_ATOM(0);
             str = ATOM_TO_STRING(atom);
             obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_TEXT, NULL, str);
             if (!obj)
                 goto error;
-            PUSH_STACK(OBJECT_TO_JSVAL(obj));
+            PUSH_STACK_OBJECT(obj);
           END_CASE(JSOP_XMLCDATA)
 
           BEGIN_CASE(JSOP_XMLCOMMENT)
             LOAD_ATOM(0);
             str = ATOM_TO_STRING(atom);
             obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_COMMENT, NULL, str);
             if (!obj)
                 goto error;
-            PUSH_STACK(OBJECT_TO_JSVAL(obj));
+            PUSH_STACK_OBJECT(obj);
           END_CASE(JSOP_XMLCOMMENT)
 
           BEGIN_CASE(JSOP_XMLPI)
             LOAD_ATOM(0);
             str = ATOM_TO_STRING(atom);
             FETCH_STACK(-1, rval);
             str2 = JSVAL_TO_STRING(rval);
             obj = js_NewXMLSpecialObject(cx,
                                          JSXML_CLASS_PROCESSING_INSTRUCTION,
                                          str, str2);
             if (!obj)
                 goto error;
-            STORE_STACK(-1, OBJECT_TO_JSVAL(obj));
+            STORE_STACK_OBJECT(-1, obj);
           END_CASE(JSOP_XMLPI)
 
           BEGIN_CASE(JSOP_GETFUNNS)
             if (!js_GetFunctionNamespace(cx, &rval))
                 goto error;
             PUSH_STACK(rval);
           END_CASE(JSOP_GETFUNNS)
 #endif /* JS_HAS_XML_SUPPORT */
@@ -6551,17 +6815,17 @@ js_Interpret(JSContext *cx)
           BEGIN_CASE(JSOP_ENTERBLOCK)
             LOAD_OBJECT(0);
             JS_ASSERT(!OBJ_IS_CLONED_BLOCK(obj));
             JS_ASSERT(fp->spbase + OBJ_BLOCK_DEPTH(cx, obj) == regs.sp);
             vp = regs.sp + OBJ_BLOCK_COUNT(cx, obj);
             JS_ASSERT(regs.sp < vp);
             JS_ASSERT(vp <= fp->spbase + script->depth);
             while (regs.sp < vp) {
-                STORE_STACK(0, JSVAL_VOID);
+                STORE_STACK_CONSTANT(0, JSVAL_VOID);
                 regs.sp++;
             }
 
             /*
              * If this frame had to reflect the compile-time block chain into
              * the runtime scope chain, we can't optimize block scopes out of
              * runtime any longer, because an outer block that parents obj has
              * been cloned onto the scope chain.  To avoid re-cloning such a
@@ -6622,17 +6886,17 @@ js_Interpret(JSContext *cx)
           END_CASE(JSOP_LEAVEBLOCK)
 
           BEGIN_CASE(JSOP_GETLOCAL)
           BEGIN_CASE(JSOP_CALLLOCAL)
             slot = GET_UINT16(regs.pc);
             JS_ASSERT(slot < script->depth);
             PUSH_STACK(fp->spbase[slot]);
             if (op == JSOP_CALLLOCAL)
-                PUSH_STACK(JSVAL_NULL);
+                PUSH_STACK_CONSTANT(JSVAL_NULL);
           END_CASE(JSOP_GETLOCAL)
 
           BEGIN_CASE(JSOP_SETLOCAL)
             slot = GET_UINT16(regs.pc);
             JS_ASSERT(slot < script->depth);
             vp = &fp->spbase[slot];
             GC_POKE(cx, *vp);
             FETCH_STACK(-1, *vp);
@@ -6867,17 +7131,17 @@ js_Interpret(JSContext *cx)
                 len = 0;
                 DO_NEXT_OP(len);
 
               case JSTN_FINALLY:
                 /*
                  * Push (true, exception) pair for finally to indicate that
                  * [retsub] should rethrow the exception.
                  */
-                PUSH_STACK(JSVAL_TRUE);
+                PUSH_STACK_CONSTANT(JSVAL_TRUE);
                 PUSH_STACK(cx->exception);
                 cx->throwing = JS_FALSE;
                 len = 0;
                 DO_NEXT_OP(len);
 
               case JSTN_ITER:
                 /*
                  * This is similar to JSOP_ENDITER in the interpreter loop