Bug 507458 - clear the waters a bit regarding JSVAL_BOOLEAN
authorLuke Wagner <lw@mozilla.com>
Wed, 12 Aug 2009 16:39:23 -0700
changeset 31521 0452549eecafc278cba383673b36246b8b0a4ab7
parent 31520 b42225bc6813350e6b7f8952361c0aa8d2cd44db
child 31522 6437414105abfff12b37767a969b4928824d1515
push id8556
push userrsayre@mozilla.com
push dateThu, 13 Aug 2009 21:38:45 +0000
treeherdermozilla-central@9734564871cb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs507458
milestone1.9.2a2pre
Bug 507458 - clear the waters a bit regarding JSVAL_BOOLEAN
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsatom.cpp
js/src/jsbool.h
js/src/jsbuiltins.cpp
js/src/jsinterp.cpp
js/src/jsobj.cpp
js/src/jstracer.cpp
js/src/jsxdrapi.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -759,19 +759,19 @@ JS_NewRuntime(uint32 maxbytes)
          * assertions, but since it isn't, this is the best we can do.
          */
         JS_ASSERT(JSVAL_NULL == OBJECT_TO_JSVAL(NULL));
         JS_ASSERT(JSVAL_ZERO == INT_TO_JSVAL(0));
         JS_ASSERT(JSVAL_ONE == INT_TO_JSVAL(1));
         JS_ASSERT(JSVAL_FALSE == BOOLEAN_TO_JSVAL(JS_FALSE));
         JS_ASSERT(JSVAL_TRUE == BOOLEAN_TO_JSVAL(JS_TRUE));
 
-        JS_ASSERT(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID) == 2);
-        JS_ASSERT(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_HOLE) == (2 | (JSVAL_HOLE_FLAG >> JSVAL_TAGBITS)));
-        JS_ASSERT(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_ARETURN) == 8);
+        JS_ASSERT(JSVAL_TO_SPECIAL(JSVAL_VOID) == 2);
+        JS_ASSERT(JSVAL_TO_SPECIAL(JSVAL_HOLE) == (2 | (JSVAL_HOLE_FLAG >> JSVAL_TAGBITS)));
+        JS_ASSERT(JSVAL_TO_SPECIAL(JSVAL_ARETURN) == 8);
 
         js_NewRuntimeWasCalled = JS_TRUE;
     }
 #endif /* DEBUG */
 
     rt = (JSRuntime *) js_malloc(sizeof(JSRuntime));
     if (!rt)
         return NULL;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -50,29 +50,23 @@
 #include "jsutil.h"
 
 JS_BEGIN_EXTERN_C
 
 /*
  * Type tags stored in the low bits of a jsval.
  */
 typedef enum jsvaltag {
-    JSVAL_OBJECT  =         0x0,     /* untagged reference to object */
-    JSVAL_INT     =         0x1,     /* tagged 31-bit integer value */
-    JSVAL_DOUBLE  =         0x2,     /* tagged reference to double */
-    JSVAL_STRING  =         0x4,     /* tagged reference to string */
-    JSVAL_BOOLEAN =         0x6      /* tagged boolean value */
+    JSVAL_OBJECT  =             0x0,     /* untagged reference to object */
+    JSVAL_INT     =             0x1,     /* tagged 31-bit integer value */
+    JSVAL_DOUBLE  =             0x2,     /* tagged reference to double */
+    JSVAL_STRING  =             0x4,     /* tagged reference to string */
+    JSVAL_SPECIAL =             0x6      /* tagged boolean or private value */
 } jsvaltag;
 
-#define JSVAL_OBJECT ((jsvaltag)0x0)
-#define JSVAL_INT ((jsvaltag)0x1)
-#define JSVAL_DOUBLE ((jsvaltag)0x2)
-#define JSVAL_STRING ((jsvaltag)0x4)
-#define JSVAL_BOOLEAN ((jsvaltag)0x6)
-
 /* Type tag bitfield length and derived macros. */
 #define JSVAL_TAGBITS           3
 #define JSVAL_TAGMASK           JS_BITMASK(JSVAL_TAGBITS)
 #define JSVAL_ALIGN             JS_BIT(JSVAL_TAGBITS)
 
 /* Not a function, because we have static asserts that use it */
 #define JSVAL_TAG(v)            ((jsvaltag)((v) & JSVAL_TAGMASK))
 
@@ -87,32 +81,31 @@ JSVAL_CLRTAG(jsval v)
 
 /*
  * Well-known JS values.  The extern'd variables are initialized when the
  * first JSContext is created by JS_NewContext (see below).
  */
 #define JSVAL_NULL              ((jsval) 0)
 #define JSVAL_ZERO              INT_TO_JSVAL(0)
 #define JSVAL_ONE               INT_TO_JSVAL(1)
-#define JSVAL_FALSE             PSEUDO_BOOLEAN_TO_JSVAL(JS_FALSE)
-#define JSVAL_TRUE              PSEUDO_BOOLEAN_TO_JSVAL(JS_TRUE)
-#define JSVAL_VOID              PSEUDO_BOOLEAN_TO_JSVAL(2)
+#define JSVAL_FALSE             SPECIAL_TO_JSVAL(JS_FALSE)
+#define JSVAL_TRUE              SPECIAL_TO_JSVAL(JS_TRUE)
+#define JSVAL_VOID              SPECIAL_TO_JSVAL(2)
 
 /*
- * A pseudo-boolean is a 29-bit (for 32-bit jsval) or 61-bit (for 64-bit jsval)
- * value other than 0 or 1 encoded as a jsval whose tag is JSVAL_BOOLEAN.
+ * A "special" value is a 29-bit (for 32-bit jsval) or 61-bit (for 64-bit jsval)
+ * value whose tag is JSVAL_SPECIAL.  These values include the booleans 0 and 1.
  *
- * JSVAL_VOID happens to be defined as a jsval encoding a pseudo-boolean, but
- * embedders MUST NOT rely on this. All other possible pseudo-boolean values
- * are implementation-reserved and MUST NOT be constructed by any embedding of
- * SpiderMonkey.
+ * JSVAL_VOID is a non-boolean special value, but embedders MUST NOT rely on
+ * this. All other possible special values are implementation-reserved
+ * and MUST NOT be constructed by any embedding of SpiderMonkey.
  */
-#define JSVAL_TO_PSEUDO_BOOLEAN(v) ((JSBool) ((v) >> JSVAL_TAGBITS))
-#define PSEUDO_BOOLEAN_TO_JSVAL(b)                                            \
-    JSVAL_SETTAG((jsval) (b) << JSVAL_TAGBITS, JSVAL_BOOLEAN)
+#define JSVAL_TO_SPECIAL(v) ((JSBool) ((v) >> JSVAL_TAGBITS))
+#define SPECIAL_TO_JSVAL(b)                                                   \
+    JSVAL_SETTAG((jsval) (b) << JSVAL_TAGBITS, JSVAL_SPECIAL)
 
 /* Predicates for type testing. */
 static JS_ALWAYS_INLINE JSBool
 JSVAL_IS_OBJECT(jsval v)
 {
     return JSVAL_TAG(v) == JSVAL_OBJECT;
 }
 
@@ -136,19 +129,25 @@ JSVAL_IS_NUMBER(jsval v)
 
 static JS_ALWAYS_INLINE JSBool
 JSVAL_IS_STRING(jsval v)
 {
     return JSVAL_TAG(v) == JSVAL_STRING;
 }
 
 static JS_ALWAYS_INLINE JSBool
+JSVAL_IS_SPECIAL(jsval v)
+{
+    return JSVAL_TAG(v) == JSVAL_SPECIAL;
+}
+
+static JS_ALWAYS_INLINE JSBool
 JSVAL_IS_BOOLEAN(jsval v)
 {
-    return (v & ~((jsval)1 << JSVAL_TAGBITS)) == JSVAL_BOOLEAN;
+    return (v & ~((jsval)1 << JSVAL_TAGBITS)) == JSVAL_SPECIAL;
 }
 
 static JS_ALWAYS_INLINE JSBool
 JSVAL_IS_NULL(jsval v)
 {
     return v == JSVAL_NULL;
 }
 
@@ -163,17 +162,17 @@ JSVAL_IS_PRIMITIVE(jsval v)
 {
     return !JSVAL_IS_OBJECT(v) || JSVAL_IS_NULL(v);
 }
 
 /* Objects, strings, and doubles are GC'ed. */
 static JS_ALWAYS_INLINE JSBool
 JSVAL_IS_GCTHING(jsval v)
 {
-    return !(v & JSVAL_INT) && JSVAL_TAG(v) != JSVAL_BOOLEAN;
+    return !(v & JSVAL_INT) && JSVAL_TAG(v) != JSVAL_SPECIAL;
 }
 
 static JS_ALWAYS_INLINE void *
 JSVAL_TO_GCTHING(jsval v)
 {
     JS_ASSERT(JSVAL_IS_GCTHING(v));
     return (void *) JSVAL_CLRTAG(v);
 }
@@ -254,24 +253,24 @@ INT_TO_JSVAL(jsint i)
     return INT_TO_JSVAL_CONSTEXPR(i);
 }
 
 /* Convert between boolean and jsval, asserting that inputs are valid. */
 static JS_ALWAYS_INLINE JSBool
 JSVAL_TO_BOOLEAN(jsval v)
 {
     JS_ASSERT(v == JSVAL_TRUE || v == JSVAL_FALSE);
-    return JSVAL_TO_PSEUDO_BOOLEAN(v);
+    return JSVAL_TO_SPECIAL(v);
 }
 
 static JS_ALWAYS_INLINE jsval
 BOOLEAN_TO_JSVAL(JSBool b)
 {
     JS_ASSERT(b == JS_TRUE || b == JS_FALSE);
-    return PSEUDO_BOOLEAN_TO_JSVAL(b);
+    return SPECIAL_TO_JSVAL(b);
 }
 
 /* A private data pointer (2-byte-aligned) can be stored as an int jsval. */
 #define JSVAL_TO_PRIVATE(v)     ((void *)((v) & ~JSVAL_INT))
 #define PRIVATE_TO_JSVAL(p)     ((jsval)(p) | JSVAL_INT)
 
 /* Property attributes, set in JSPropertySpec and passed to API functions. */
 #define JSPROP_ENUMERATE        0x01    /* property is visible to for/in loop */
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1036,33 +1036,33 @@ array_deleteProperty(JSContext *cx, JSOb
  * slowarray_enumerate.
  *
  * Array mutations can turn a fast array into a slow one after the enumeration
  * starts. When this happens, slowarray_enumerate receives a state created
  * when the array was fast. To distinguish such fast state from a slow state,
  * which is an int-tagged pointer that js_Enumerate creates, we set not one
  * but two lowest bits when tagging a JSIndexIterState pointer -- see
  * INDEX_ITER_TAG usage below. Thus, when slowarray_enumerate receives a state
- * tagged with JSVAL_BOOLEAN or with two lowest bits set, it knows that this
+ * tagged with JSVAL_SPECIAL or with two lowest bits set, it knows that this
  * is a fast state so it calls array_enumerate to continue enumerating the
  * indexes present in the original fast array.
  */
 
 #define PACKED_UINT_PAIR_BITS           14
 #define PACKED_UINT_PAIR_MASK           JS_BITMASK(PACKED_UINT_PAIR_BITS)
 
-#define UINT_PAIR_TO_BOOLEAN_JSVAL(i,j)                                       \
+#define UINT_PAIR_TO_SPECIAL_JSVAL(i,j)                                \
     (JS_ASSERT((uint32) (i) <= PACKED_UINT_PAIR_MASK),                        \
      JS_ASSERT((uint32) (j) <= PACKED_UINT_PAIR_MASK),                        \
      ((jsval) (i) << (PACKED_UINT_PAIR_BITS + JSVAL_TAGBITS)) |               \
      ((jsval) (j) << (JSVAL_TAGBITS)) |                                       \
-     (jsval) JSVAL_BOOLEAN)
-
-#define BOOLEAN_JSVAL_TO_UINT_PAIR(v,i,j)                                     \
-    (JS_ASSERT(JSVAL_TAG(v) == JSVAL_BOOLEAN),                                \
+     (jsval) JSVAL_SPECIAL)
+
+#define SPECIAL_JSVAL_TO_UINT_PAIR(v,i,j)                              \
+    (JS_ASSERT(JSVAL_IS_SPECIAL(v)),                                   \
      (i) = (uint32) ((v) >> (PACKED_UINT_PAIR_BITS + JSVAL_TAGBITS)),         \
      (j) = (uint32) ((v) >> JSVAL_TAGBITS) & PACKED_UINT_PAIR_MASK,           \
      JS_ASSERT((i) <= PACKED_UINT_PAIR_MASK))
 
 JS_STATIC_ASSERT(PACKED_UINT_PAIR_BITS * 2 + JSVAL_TAGBITS <= JS_BITS_PER_WORD);
 
 typedef struct JSIndexIterState {
     uint32          index;
@@ -1106,37 +1106,37 @@ array_enumerate(JSContext *cx, JSObject 
                     memset(ii->holes, 0, JS_BITMAP_SIZE(capacity));
                 }
                 JS_SET_BIT(ii->holes, i);
             }
         }
         if (!ii) {
             /* Array has no holes. */
             if (capacity <= PACKED_UINT_PAIR_MASK) {
-                *statep = UINT_PAIR_TO_BOOLEAN_JSVAL(0, capacity);
+                *statep = UINT_PAIR_TO_SPECIAL_JSVAL(0, capacity);
                 break;
             }
             ii = (JSIndexIterState *)
                  cx->malloc(offsetof(JSIndexIterState, holes));
             if (!ii)
                 return JS_FALSE;
             ii->hasHoles = JS_FALSE;
         }
         ii->index = 0;
         ii->length = capacity;
         *statep = (jsval) ii | INDEX_ITER_TAG;
         JS_ASSERT(*statep & JSVAL_INT);
         break;
 
       case JSENUMERATE_NEXT:
-        if (JSVAL_TAG(*statep) == JSVAL_BOOLEAN) {
-            BOOLEAN_JSVAL_TO_UINT_PAIR(*statep, i, capacity);
+        if (JSVAL_IS_SPECIAL(*statep)) {
+            SPECIAL_JSVAL_TO_UINT_PAIR(*statep, i, capacity);
             if (i != capacity) {
                 *idp = INT_TO_JSID(i);
-                *statep = UINT_PAIR_TO_BOOLEAN_JSVAL(i + 1, capacity);
+                *statep = UINT_PAIR_TO_SPECIAL_JSVAL(i + 1, capacity);
                 break;
             }
         } else {
             JS_ASSERT((*statep & INDEX_ITER_TAG) == INDEX_ITER_TAG);
             ii = (JSIndexIterState *) (*statep & ~INDEX_ITER_TAG);
             i = ii->index;
             if (i != ii->length) {
                 /* Skip holes if any. */
@@ -1148,17 +1148,17 @@ array_enumerate(JSContext *cx, JSObject 
                     ii->index = i + 1;
                     return js_IndexToId(cx, i, idp);
                 }
             }
         }
         /* FALL THROUGH */
 
       case JSENUMERATE_DESTROY:
-        if (JSVAL_TAG(*statep) != JSVAL_BOOLEAN) {
+        if (!JSVAL_IS_SPECIAL(*statep)) {
             JS_ASSERT((*statep & INDEX_ITER_TAG) == INDEX_ITER_TAG);
             ii = (JSIndexIterState *) (*statep & ~INDEX_ITER_TAG);
             cx->free(ii);
         }
         *statep = JSVAL_NULL;
         break;
     }
     return JS_TRUE;
@@ -1167,17 +1167,17 @@ array_enumerate(JSContext *cx, JSObject 
 static JSBool
 slowarray_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
                     jsval *statep, jsid *idp)
 {
     JSBool ok;
 
     /* Are we continuing an enumeration that started when we were dense? */
     if (enum_op != JSENUMERATE_INIT) {
-        if (JSVAL_TAG(*statep) == JSVAL_BOOLEAN ||
+        if (JSVAL_IS_SPECIAL(*statep) ||
             (*statep & INDEX_ITER_TAG) == INDEX_ITER_TAG) {
             return array_enumerate(cx, obj, enum_op, statep, idp);
         }
         JS_ASSERT((*statep & INDEX_ITER_TAG) == JSVAL_INT);
     }
     ok = js_Enumerate(cx, obj, enum_op, statep, idp);
     JS_ASSERT(*statep == JSVAL_NULL || (*statep & INDEX_ITER_TAG) == JSVAL_INT);
     return ok;
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -93,17 +93,17 @@ js_AtomToPrintableString(JSContext *cx, 
 
 /*
  * String constants for common atoms defined in JSAtomState starting from
  * JSAtomState.emptyAtom until JSAtomState.lazy.
  *
  * The elements of the array after the first empty string define strings
  * corresponding to the two boolean literals, false and true, followed by the
  * JSType enumerators from jspubtd.h starting with "undefined" for JSTYPE_VOID
- * (which is pseudo-boolean 2) and continuing as initialized below. The static
+ * (which is special-value 2) and continuing as initialized below. The static
  * asserts check these relations.
  */
 JS_STATIC_ASSERT(JSTYPE_LIMIT == 8);
 JS_STATIC_ASSERT(JSTYPE_VOID == 0);
 
 const char *const js_common_atom_names[] = {
     "",                         /* emptyAtom                    */
     js_false_str,               /* booleanAtoms[0]              */
--- a/js/src/jsbool.h
+++ b/js/src/jsbool.h
@@ -43,39 +43,32 @@
  * JS boolean interface.
  */
 
 #include "jsapi.h"
 
 JS_BEGIN_EXTERN_C
 
 /*
- * Pseudo-booleans, not visible to script but used internally by the engine.
+ * Special values, not visible to script but used internally by the engine.
  *
  * JSVAL_HOLE is a useful value for identifying a hole in an array.  It's also
  * used in the interpreter to represent "no exception pending".  In general it
  * can be used to represent "no value".
  *
  * A JSVAL_HOLE can be cheaply converted to undefined without affecting any
- * other boolean (or pseudo boolean) by masking out JSVAL_HOLE_MASK.
+ * other boolean (or special value) by masking out JSVAL_HOLE_FLAG.
  *
  * JSVAL_ARETURN is used to throw asynchronous return for generator.close().
  *
- * NB: PSEUDO_BOOLEAN_TO_JSVAL(2) is JSVAL_VOID (see jsapi.h).
+ * NB: SPECIAL_TO_JSVAL(2) is JSVAL_VOID (see jsapi.h).
  */
 #define JSVAL_HOLE_FLAG jsval(4 << JSVAL_TAGBITS)
 #define JSVAL_HOLE      (JSVAL_VOID | JSVAL_HOLE_FLAG)
-#define JSVAL_ARETURN   PSEUDO_BOOLEAN_TO_JSVAL(8)
-
-static JS_ALWAYS_INLINE JSBool
-JSVAL_TO_PUBLIC_PSEUDO_BOOLEAN(jsval v)
-{
-    JS_ASSERT(v == JSVAL_TRUE || v == JSVAL_FALSE || v == JSVAL_VOID);
-    return JSVAL_TO_PSEUDO_BOOLEAN(v);
-}
+#define JSVAL_ARETURN   SPECIAL_TO_JSVAL(8)
 
 extern JSClass js_BooleanClass;
 
 extern JSObject *
 js_InitBooleanClass(JSContext *cx, JSObject *obj);
 
 extern JSString *
 js_BooleanToString(JSContext *cx, JSBool b);
--- a/js/src/jsbuiltins.cpp
+++ b/js/src/jsbuiltins.cpp
@@ -292,26 +292,26 @@ js_AddProperty(JSContext* cx, JSObject* 
 JS_DEFINE_CALLINFO_3(extern, BOOL, js_AddProperty, CONTEXT, OBJECT, SCOPEPROP, 0, 0)
 
 static JSBool
 HasProperty(JSContext* cx, JSObject* obj, jsid id)
 {
     // Check that we know how the lookup op will behave.
     for (JSObject* pobj = obj; pobj; pobj = OBJ_GET_PROTO(cx, pobj)) {
         if (pobj->map->ops->lookupProperty != js_LookupProperty)
-            return JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID);
+            return JSVAL_TO_SPECIAL(JSVAL_VOID);
         JSClass* clasp = OBJ_GET_CLASS(cx, pobj);
         if (clasp->resolve != JS_ResolveStub && clasp != &js_StringClass)
-            return JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID);
+            return JSVAL_TO_SPECIAL(JSVAL_VOID);
     }
 
     JSObject* obj2;
     JSProperty* prop;
     if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) < 0)
-        return JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID);
+        return JSVAL_TO_SPECIAL(JSVAL_VOID);
     if (prop)
         obj2->dropProperty(cx, prop);
     return prop != NULL;
 }
 
 JSBool FASTCALL
 js_HasNamedProperty(JSContext* cx, JSObject* obj, JSString* idstr)
 {
@@ -352,27 +352,27 @@ js_TypeOfObject(JSContext* cx, JSObject*
     return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type]);
 }
 JS_DEFINE_CALLINFO_2(extern, STRING, js_TypeOfObject, CONTEXT, OBJECT, 1, 1)
 
 JSString* FASTCALL
 js_TypeOfBoolean(JSContext* cx, int32 unboxed)
 {
     /* Watch out for pseudo-booleans. */
-    jsval boxed = PSEUDO_BOOLEAN_TO_JSVAL(unboxed);
+    jsval boxed = SPECIAL_TO_JSVAL(unboxed);
     JS_ASSERT(JSVAL_IS_VOID(boxed) || JSVAL_IS_BOOLEAN(boxed));
     JSType type = JS_TypeOfValue(cx, boxed);
     return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type]);
 }
 JS_DEFINE_CALLINFO_2(extern, STRING, js_TypeOfBoolean, CONTEXT, INT32, 1, 1)
 
 jsdouble FASTCALL
 js_BooleanOrUndefinedToNumber(JSContext* cx, int32 unboxed)
 {
-    if (unboxed == JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID))
+    if (unboxed == JSVAL_TO_SPECIAL(JSVAL_VOID))
         return js_NaN;
     JS_ASSERT(unboxed == JS_TRUE || unboxed == JS_FALSE);
     return unboxed;
 }
 JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_BooleanOrUndefinedToNumber, CONTEXT, INT32, 1, 1)
 
 JSString* FASTCALL
 js_BooleanOrUndefinedToString(JSContext *cx, int32 unboxed)
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -1061,17 +1061,17 @@ NoSuchMethod(JSContext *cx, uintN argc, 
 
 /*
  * We check if the function accepts a primitive value as |this|. For that we
  * use a table that maps value's tag into the corresponding function flag.
  */
 JS_STATIC_ASSERT(JSVAL_INT == 1);
 JS_STATIC_ASSERT(JSVAL_DOUBLE == 2);
 JS_STATIC_ASSERT(JSVAL_STRING == 4);
-JS_STATIC_ASSERT(JSVAL_BOOLEAN == 6);
+JS_STATIC_ASSERT(JSVAL_SPECIAL == 6);
 
 const uint16 js_PrimitiveTestFlags[] = {
     JSFUN_THISP_NUMBER,     /* INT     */
     JSFUN_THISP_NUMBER,     /* DOUBLE  */
     JSFUN_THISP_NUMBER,     /* INT     */
     JSFUN_THISP_STRING,     /* STRING  */
     JSFUN_THISP_NUMBER,     /* INT     */
     JSFUN_THISP_BOOLEAN,    /* BOOLEAN */
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -5401,17 +5401,17 @@ js_PrimitiveToObject(JSContext *cx, jsva
 {
     JSClass *clasp;
     JSObject *obj;
 
     /* Table to map primitive value's tag into the corresponding class. */
     JS_STATIC_ASSERT(JSVAL_INT == 1);
     JS_STATIC_ASSERT(JSVAL_DOUBLE == 2);
     JS_STATIC_ASSERT(JSVAL_STRING == 4);
-    JS_STATIC_ASSERT(JSVAL_BOOLEAN == 6);
+    JS_STATIC_ASSERT(JSVAL_SPECIAL == 6);
     static JSClass *const PrimitiveClasses[] = {
         &js_NumberClass,    /* INT     */
         &js_NumberClass,    /* DOUBLE  */
         &js_NumberClass,    /* INT     */
         &js_StringClass,    /* STRING  */
         &js_NumberClass,    /* INT     */
         &js_BooleanClass,   /* BOOLEAN */
         &js_NumberClass     /* INT     */
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -90,18 +90,18 @@ using namespace nanojit;
         ABORT_TRACE("xml detected");                                          \
     JS_END_MACRO
 #else
 #define ABORT_IF_XML(v) ((void) 0)
 #endif
 
 /*
  * Never use JSVAL_IS_BOOLEAN because it restricts the value (true, false) and
- * the type. What you want to use is JSVAL_TAG(x) == JSVAL_BOOLEAN and then
- * handle the undefined case properly (bug 457363).
+ * the type. What you want to use is JSVAL_IS_SPECIAL(x) and then handle the
+ * undefined case properly (bug 457363).
  */
 #undef JSVAL_IS_BOOLEAN
 #define JSVAL_IS_BOOLEAN(x) JS_STATIC_ASSERT(0)
 
 JS_STATIC_ASSERT(sizeof(JSTraceType) == 1);
 
 /* Map to translate a type tag into a printable representation. */
 static const char typeChar[] = "OIDXSNBF";
@@ -250,17 +250,17 @@ js_InitJITStatsClass(JSContext *cx, JSOb
 #else
 #define AUDIT(x) ((void)0)
 #endif /* JS_JIT_SPEW */
 
 #define INS_CONST(c)        addName(lir->insImm(c), #c)
 #define INS_CONSTPTR(p)     addName(lir->insImmPtr(p), #p)
 #define INS_CONSTFUNPTR(p)  addName(lir->insImmPtr(JS_FUNC_TO_DATA_PTR(void*, p)), #p)
 #define INS_CONSTWORD(v)    addName(lir->insImmPtr((void *) v), #v)
-#define INS_VOID()          INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID))
+#define INS_VOID()          INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID))
 
 static GC gc = GC();
 static avmplus::AvmCore s_core = avmplus::AvmCore();
 static avmplus::AvmCore* core = &s_core;
 
 /* Allocator SPI implementation. */
 
 void*
@@ -562,20 +562,20 @@ GetPromotedType(jsval v)
     if (JSVAL_IS_OBJECT(v)) {
         if (JSVAL_IS_NULL(v))
             return TT_NULL;
         if (HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(v)))
             return TT_FUNCTION;
         return TT_OBJECT;
     }
     uint8_t tag = JSVAL_TAG(v);
-    JS_ASSERT(tag == JSVAL_DOUBLE || tag == JSVAL_STRING || tag == JSVAL_BOOLEAN);
+    JS_ASSERT(tag == JSVAL_DOUBLE || tag == JSVAL_STRING || tag == JSVAL_SPECIAL);
     JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_DOUBLE) == JSVAL_DOUBLE);
     JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_STRING) == JSVAL_STRING);
-    JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_PSEUDOBOOLEAN) == JSVAL_BOOLEAN);
+    JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_PSEUDOBOOLEAN) == JSVAL_SPECIAL);
     return JSTraceType(tag);
 }
 
 /* Return TT_INT32 for all whole numbers that fit into signed 32-bit and the tag otherwise. */
 static inline JSTraceType
 getCoercedType(jsval v)
 {
     if (isInt32(v))
@@ -583,20 +583,20 @@ getCoercedType(jsval v)
     if (JSVAL_IS_OBJECT(v)) {
         if (JSVAL_IS_NULL(v))
             return TT_NULL;
         if (HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(v)))
             return TT_FUNCTION;
         return TT_OBJECT;
     }
     uint8_t tag = JSVAL_TAG(v);
-    JS_ASSERT(tag == JSVAL_DOUBLE || tag == JSVAL_STRING || tag == JSVAL_BOOLEAN);
+    JS_ASSERT(tag == JSVAL_DOUBLE || tag == JSVAL_STRING || tag == JSVAL_SPECIAL);
     JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_DOUBLE) == JSVAL_DOUBLE);
     JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_STRING) == JSVAL_STRING);
-    JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_PSEUDOBOOLEAN) == JSVAL_BOOLEAN);
+    JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_PSEUDOBOOLEAN) == JSVAL_SPECIAL);
     return JSTraceType(tag);
 }
 
 /* Constant seed and accumulate step borrowed from the DJB hash. */
 
 const uintptr_t ORACLE_MASK = ORACLE_SIZE - 1;
 JS_STATIC_ASSERT((ORACLE_MASK & ORACLE_SIZE) == 0);
 
@@ -1950,18 +1950,18 @@ ValueToNative(JSContext* cx, jsval v, JS
       case TT_NULL:
         JS_ASSERT(tag == JSVAL_OBJECT);
         *(JSObject**)slot = NULL;
         debug_only_print0(LC_TMTracer, "null ");
         return;
 
       case TT_PSEUDOBOOLEAN:
         /* Watch out for pseudo-booleans. */
-        JS_ASSERT(tag == JSVAL_BOOLEAN);
-        *(JSBool*)slot = JSVAL_TO_PSEUDO_BOOLEAN(v);
+        JS_ASSERT(tag == JSVAL_SPECIAL);
+        *(JSBool*)slot = JSVAL_TO_SPECIAL(v);
         debug_only_printf(LC_TMTracer, "pseudoboolean<%d> ", *(JSBool*)slot);
         return;
 
       case TT_FUNCTION: {
         JS_ASSERT(tag == JSVAL_OBJECT);
         JSObject* obj = JSVAL_TO_OBJECT(v);
         *(JSObject**)slot = obj;
 #ifdef DEBUG
@@ -2107,17 +2107,17 @@ NativeToValue(JSContext* cx, jsval& v, J
       case TT_NULL:
         JS_ASSERT(*(JSObject**)slot == NULL);
         v = JSVAL_NULL;
         debug_only_printf(LC_TMTracer, "null<%p> ", (void*)(*(JSObject**)slot));
         break;
 
       case TT_PSEUDOBOOLEAN:
         /* Watch out for pseudo-booleans. */
-        v = PSEUDO_BOOLEAN_TO_JSVAL(*(JSBool*)slot);
+        v = SPECIAL_TO_JSVAL(*(JSBool*)slot);
         debug_only_printf(LC_TMTracer, "boolean<%d> ", *(JSBool*)slot);
         break;
 
       case TT_FUNCTION: {
         JS_ASSERT(HAS_FUNCTION_CLASS(*(JSObject**)slot));
         v = OBJECT_TO_JSVAL(*(JSObject**)slot);
 #ifdef DEBUG
         JSFunction* fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v));
@@ -3045,19 +3045,19 @@ TraceRecorder::determineSlotType(jsval* 
     } else if (JSVAL_IS_OBJECT(*vp)) {
         if (JSVAL_IS_NULL(*vp))
             m = TT_NULL;
         else if (HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(*vp)))
             m = TT_FUNCTION;
         else
             m = TT_OBJECT;
     } else {
-        JS_ASSERT(JSVAL_TAG(*vp) == JSVAL_STRING || JSVAL_TAG(*vp) == JSVAL_BOOLEAN);
+        JS_ASSERT(JSVAL_TAG(*vp) == JSVAL_STRING || JSVAL_IS_SPECIAL(*vp));
         JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_STRING) == JSVAL_STRING);
-        JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_PSEUDOBOOLEAN) == JSVAL_BOOLEAN);
+        JS_STATIC_ASSERT(static_cast<jsvaltag>(TT_PSEUDOBOOLEAN) == JSVAL_SPECIAL);
         m = JSTraceType(JSVAL_TAG(*vp));
     }
     JS_ASSERT(m != TT_INT32 || isInt32(*vp));
     return m;
 }
 
 class DetermineTypesVisitor : public SlotVisitorBase
 {
@@ -5098,17 +5098,17 @@ IsEntryTypeCompatible(jsval* vp, JSTrace
         debug_only_printf(LC_TMTracer, "string != tag%u ", tag);
         return false;
       case TT_NULL:
         if (JSVAL_IS_NULL(*vp))
             return true;
         debug_only_printf(LC_TMTracer, "null != tag%u ", tag);
         return false;
       case TT_PSEUDOBOOLEAN:
-        if (tag == JSVAL_BOOLEAN)
+        if (tag == JSVAL_SPECIAL)
             return true;
         debug_only_printf(LC_TMTracer, "bool != tag%u ", tag);
         return false;
       default:
         JS_ASSERT(*m == TT_FUNCTION);
         if (tag == JSVAL_OBJECT && !JSVAL_IS_NULL(*vp) &&
             HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(*vp))) {
             return true;
@@ -7091,17 +7091,17 @@ TraceRecorder::stringify(jsval& v)
     LIns* v_ins = get(&v);
     if (JSVAL_IS_STRING(v))
         return v_ins;
 
     LIns* args[] = { v_ins, cx_ins };
     const CallInfo* ci;
     if (JSVAL_IS_NUMBER(v)) {
         ci = &js_NumberToString_ci;
-    } else if (JSVAL_TAG(v) == JSVAL_BOOLEAN) {
+    } else if (JSVAL_IS_SPECIAL(v)) {
         ci = &js_BooleanOrUndefinedToString_ci;
     } else {
         /*
          * Callers must deal with non-primitive (non-null object) values by
          * calling an imacro. We don't try to guess about which imacro, with
          * what valueOf hint, here.
          */
         JS_ASSERT(JSVAL_IS_NULL(v));
@@ -7138,19 +7138,19 @@ TraceRecorder::ifop()
     LIns* x;
 
     if (JSVAL_IS_NULL(v)) {
         cond = false;
         x = lir->insImm(0);
     } else if (!JSVAL_IS_PRIMITIVE(v)) {
         cond = true;
         x = lir->insImm(1);
-    } else if (JSVAL_TAG(v) == JSVAL_BOOLEAN) {
+    } else if (JSVAL_IS_SPECIAL(v)) {
         /* Test for boolean is true, negate later if we are testing for false. */
-        cond = JSVAL_TO_PSEUDO_BOOLEAN(v) == JS_TRUE;
+        cond = JSVAL_TO_SPECIAL(v) == JS_TRUE;
         x = lir->ins2i(LIR_eq, v_ins, 1);
     } else if (isNumber(v)) {
         jsdouble d = asNumber(v);
         cond = !JSDOUBLE_IS_NaN(d) && d;
         x = lir->ins2(LIR_and,
                       lir->ins2(LIR_feq, v_ins, v_ins),
                       lir->ins_eq0(lir->ins2(LIR_feq, v_ins, lir->insImmq(0))));
     } else if (JSVAL_IS_STRING(v)) {
@@ -7233,16 +7233,24 @@ TraceRecorder::tableswitch()
     exit->switchInfo = si;
     LIns* guardIns = lir->insGuard(LIR_xtbl, diff, createGuardRecord(exit));
     fragment->lastIns = guardIns;
     compile(&JS_TRACE_MONITOR(cx));
     return JSRS_STOP;
 }
 #endif
 
+static JS_ALWAYS_INLINE int32_t
+UnboxBooleanOrUndefined(jsval v)
+{
+    /* Although this says 'special', we really only expect 3 special values: */
+    JS_ASSERT(v == JSVAL_TRUE || v == JSVAL_FALSE || v == JSVAL_VOID);
+    return JSVAL_TO_SPECIAL(v);
+}
+
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::switchop()
 {
     jsval& v = stackval(-1);
     LIns* v_ins = get(&v);
 
     /* No need to guard if the condition is constant. */
     if (v_ins->isconst() || v_ins->isconstq())
@@ -7254,19 +7262,19 @@ TraceRecorder::switchop()
                       "guard(switch on numeric)"),
               BRANCH_EXIT);
     } else if (JSVAL_IS_STRING(v)) {
         LIns* args[] = { v_ins, INS_CONSTPTR(JSVAL_TO_STRING(v)) };
         guard(true,
               addName(lir->ins_eq0(lir->ins_eq0(lir->insCall(&js_EqualStrings_ci, args))),
                       "guard(switch on string)"),
               BRANCH_EXIT);
-    } else if (JSVAL_TAG(v) == JSVAL_BOOLEAN) {
+    } else if (JSVAL_IS_SPECIAL(v)) {
         guard(true,
-              addName(lir->ins2(LIR_eq, v_ins, lir->insImm(JSVAL_TO_PUBLIC_PSEUDO_BOOLEAN(v))),
+              addName(lir->ins2(LIR_eq, v_ins, lir->insImm(UnboxBooleanOrUndefined(v))),
                       "guard(switch on boolean)"),
               BRANCH_EXIT);
     } else {
         ABORT_TRACE("switch on object or null");
     }
     return JSRS_CONTINUE;
 }
 
@@ -7459,63 +7467,63 @@ TraceRecorder::equalityHelper(jsval l, j
      * confusing objects and null.  Note carefully the spec-mandated recursion
      * in the final else clause, which terminates because Number == T recurs
      * only if T is Object, but that must recur again to convert Object to
      * primitive, and ToPrimitive throws if the object cannot be converted to
      * a primitive value (which would terminate recursion).
      */
 
     if (GetPromotedType(l) == GetPromotedType(r)) {
-        if (JSVAL_TAG(l) == JSVAL_OBJECT || JSVAL_TAG(l) == JSVAL_BOOLEAN) {
+        if (JSVAL_TAG(l) == JSVAL_OBJECT || JSVAL_IS_SPECIAL(l)) {
             cond = (l == r);
         } else if (JSVAL_IS_STRING(l)) {
             args[0] = r_ins, args[1] = l_ins;
             l_ins = lir->insCall(&js_EqualStrings_ci, args);
             r_ins = lir->insImm(1);
             cond = js_EqualStrings(JSVAL_TO_STRING(l), JSVAL_TO_STRING(r));
         } else {
             JS_ASSERT(isNumber(l) && isNumber(r));
             cond = (asNumber(l) == asNumber(r));
             fp = true;
         }
-    } else if (JSVAL_IS_NULL(l) && JSVAL_TAG(r) == JSVAL_BOOLEAN) {
-        l_ins = lir->insImm(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID));
+    } else if (JSVAL_IS_NULL(l) && JSVAL_IS_SPECIAL(r)) {
+        l_ins = lir->insImm(JSVAL_TO_SPECIAL(JSVAL_VOID));
         cond = (r == JSVAL_VOID);
-    } else if (JSVAL_TAG(l) == JSVAL_BOOLEAN && JSVAL_IS_NULL(r)) {
-        r_ins = lir->insImm(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID));
+    } else if (JSVAL_IS_SPECIAL(l) && JSVAL_IS_NULL(r)) {
+        r_ins = lir->insImm(JSVAL_TO_SPECIAL(JSVAL_VOID));
         cond = (l == JSVAL_VOID);
     } else if (isNumber(l) && JSVAL_IS_STRING(r)) {
         args[0] = r_ins, args[1] = cx_ins;
         r_ins = lir->insCall(&js_StringToNumber_ci, args);
         cond = (asNumber(l) == js_StringToNumber(cx, JSVAL_TO_STRING(r)));
         fp = true;
     } else if (JSVAL_IS_STRING(l) && isNumber(r)) {
         args[0] = l_ins, args[1] = cx_ins;
         l_ins = lir->insCall(&js_StringToNumber_ci, args);
         cond = (js_StringToNumber(cx, JSVAL_TO_STRING(l)) == asNumber(r));
         fp = true;
     } else {
-        if (JSVAL_TAG(l) == JSVAL_BOOLEAN) {
+        if (JSVAL_IS_SPECIAL(l)) {
             bool isVoid = JSVAL_IS_VOID(l);
             guard(isVoid,
-                  lir->ins2(LIR_eq, l_ins, INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID))),
+                  lir->ins2(LIR_eq, l_ins, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID))),
                   BRANCH_EXIT);
             if (!isVoid) {
                 args[0] = l_ins, args[1] = cx_ins;
                 l_ins = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args);
                 l = (l == JSVAL_VOID)
                     ? DOUBLE_TO_JSVAL(cx->runtime->jsNaN)
                     : INT_TO_JSVAL(l == JSVAL_TRUE);
                 return equalityHelper(l, r, l_ins, r_ins, negate,
                                       tryBranchAfterCond, rval);
             }
-        } else if (JSVAL_TAG(r) == JSVAL_BOOLEAN) {
+        } else if (JSVAL_IS_SPECIAL(r)) {
             bool isVoid = JSVAL_IS_VOID(r);
             guard(isVoid,
-                  lir->ins2(LIR_eq, r_ins, INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID))),
+                  lir->ins2(LIR_eq, r_ins, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID))),
                   BRANCH_EXIT);
             if (!isVoid) {
                 args[0] = r_ins, args[1] = cx_ins;
                 r_ins = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args);
                 r = (r == JSVAL_VOID)
                     ? DOUBLE_TO_JSVAL(cx->runtime->jsNaN)
                     : INT_TO_JSVAL(r == JSVAL_TRUE);
                 return equalityHelper(l, r, l_ins, r_ins, negate,
@@ -7611,17 +7619,17 @@ TraceRecorder::relational(LOpcode op, bo
         cond = EvalCmp(op, JSVAL_TO_STRING(l), JSVAL_TO_STRING(r));
         goto do_comparison;
     }
 
     /* 11.8.5 steps 4-5. */
     if (!JSVAL_IS_NUMBER(l)) {
         LIns* args[] = { l_ins, cx_ins };
         switch (JSVAL_TAG(l)) {
-          case JSVAL_BOOLEAN:
+          case JSVAL_SPECIAL:
             l_ins = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args);
             break;
           case JSVAL_STRING:
             l_ins = lir->insCall(&js_StringToNumber_ci, args);
             break;
           case JSVAL_OBJECT:
             if (JSVAL_IS_NULL(l)) {
                 l_ins = lir->insImmf(0.0);
@@ -7634,17 +7642,17 @@ TraceRecorder::relational(LOpcode op, bo
             JS_NOT_REACHED("JSVAL_IS_NUMBER if int/double, objects should "
                            "have been handled at start of method");
             ABORT_TRACE("safety belt");
         }
     }
     if (!JSVAL_IS_NUMBER(r)) {
         LIns* args[] = { r_ins, cx_ins };
         switch (JSVAL_TAG(r)) {
-          case JSVAL_BOOLEAN:
+          case JSVAL_SPECIAL:
             r_ins = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args);
             break;
           case JSVAL_STRING:
             r_ins = lir->insCall(&js_StringToNumber_ci, args);
             break;
           case JSVAL_OBJECT:
             if (JSVAL_IS_NULL(r)) {
                 r_ins = lir->insImmf(0.0);
@@ -7771,26 +7779,26 @@ TraceRecorder::binary(LOpcode op)
         if (JSVAL_IS_STRING(r)) {
             args[0] = b;
             args[1] = cx_ins;
             b = lir->insCall(&js_StringToNumber_ci, args);
             rnum = js_StringToNumber(cx, JSVAL_TO_STRING(r));
             rightIsNumber = true;
         }
     }
-    if (JSVAL_TAG(l) == JSVAL_BOOLEAN) {
+    if (JSVAL_IS_SPECIAL(l)) {
         LIns* args[] = { a, cx_ins };
         a = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args);
-        lnum = js_BooleanOrUndefinedToNumber(cx, JSVAL_TO_PSEUDO_BOOLEAN(l));
+        lnum = js_BooleanOrUndefinedToNumber(cx, JSVAL_TO_SPECIAL(l));
         leftIsNumber = true;
     }
-    if (JSVAL_TAG(r) == JSVAL_BOOLEAN) {
+    if (JSVAL_IS_SPECIAL(r)) {
         LIns* args[] = { b, cx_ins };
         b = lir->insCall(&js_BooleanOrUndefinedToNumber_ci, args);
-        rnum = js_BooleanOrUndefinedToNumber(cx, JSVAL_TO_PSEUDO_BOOLEAN(r));
+        rnum = js_BooleanOrUndefinedToNumber(cx, JSVAL_TO_SPECIAL(r));
         rightIsNumber = true;
     }
     if (leftIsNumber && rightIsNumber) {
         if (intop) {
             LIns *args[] = { a };
             a = lir->insCall(op == LIR_ush ? &js_DoubleToUint32_ci : &js_DoubleToInt32_ci, args);
             b = f2i(b);
         }
@@ -8095,33 +8103,33 @@ TraceRecorder::native_get(LIns* obj_ins,
                           LIns*& dslots_ins, LIns*& v_ins)
 {
     if (!SPROP_HAS_STUB_GETTER(sprop))
         return JSRS_STOP;
 
     if (sprop->slot != SPROP_INVALID_SLOT)
         v_ins = stobj_get_slot(pobj_ins, sprop->slot, dslots_ins);
     else
-        v_ins = INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID));
+        v_ins = INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID));
     return JSRS_CONTINUE;
 }
 
 JS_REQUIRES_STACK void
 TraceRecorder::box_jsval(jsval v, LIns*& v_ins)
 {
     if (isNumber(v)) {
         LIns* args[] = { v_ins, cx_ins };
         v_ins = lir->insCall(&js_BoxDouble_ci, args);
         guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)),
               OOM_EXIT);
         return;
     }
     switch (JSVAL_TAG(v)) {
-      case JSVAL_BOOLEAN:
-        v_ins = lir->ins2i(LIR_pior, lir->ins2i(LIR_pilsh, v_ins, JSVAL_TAGBITS), JSVAL_BOOLEAN);
+      case JSVAL_SPECIAL:
+        v_ins = lir->ins2i(LIR_pior, lir->ins2i(LIR_pilsh, v_ins, JSVAL_TAGBITS), JSVAL_SPECIAL);
         return;
       case JSVAL_OBJECT:
         return;
       default:
         JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING);
         v_ins = lir->ins2(LIR_pior, v_ins, INS_CONST(JSVAL_STRING));
         return;
     }
@@ -8140,21 +8148,21 @@ TraceRecorder::unbox_jsval(jsval v, LIns
                                                           INS_CONST(JSVAL_TAGMASK)),
                                                 JSVAL_DOUBLE))),
               exit);
         LIns* args[] = { v_ins };
         v_ins = lir->insCall(&js_UnboxDouble_ci, args);
         return;
     }
     switch (JSVAL_TAG(v)) {
-      case JSVAL_BOOLEAN:
+      case JSVAL_SPECIAL:
         guard(true,
               lir->ins2i(LIR_eq,
                          lir->ins2(LIR_piand, v_ins, INS_CONST(JSVAL_TAGMASK)),
-                         JSVAL_BOOLEAN),
+                         JSVAL_SPECIAL),
               exit);
         v_ins = lir->ins2i(LIR_ush, v_ins, JSVAL_TAGBITS);
         return;
       case JSVAL_OBJECT:
         if (JSVAL_IS_NULL(v)) {
             // JSVAL_NULL maps to type TT_NULL, so insist that v_ins == 0 here.
             guard(true, lir->ins_eq0(v_ins), exit);
         } else {
@@ -8459,17 +8467,17 @@ TraceRecorder::record_LeaveFrame()
     atoms = FrameAtomBase(cx, cx->fp);
     set(&stackval(-1), rval_ins, true);
     return JSRS_CONTINUE;
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::record_JSOP_PUSH()
 {
-    stack(0, INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID)));
+    stack(0, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID)));
     return JSRS_CONTINUE;
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::record_JSOP_POPV()
 {
     jsval& rval = stackval(-1);
     LIns *rval_ins = get(&rval);
@@ -8757,17 +8765,17 @@ TraceRecorder::record_JSOP_MOD()
 {
     return binary(LIR_fmod);
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::record_JSOP_NOT()
 {
     jsval& v = stackval(-1);
-    if (JSVAL_TAG(v) == JSVAL_BOOLEAN) {
+    if (JSVAL_IS_SPECIAL(v)) {
         set(&v, lir->ins_eq0(lir->ins2i(LIR_eq, get(&v), 1)));
         return JSRS_CONTINUE;
     }
     if (isNumber(v)) {
         LIns* v_ins = get(&v);
         set(&v, lir->ins2(LIR_or, lir->ins2(LIR_feq, v_ins, lir->insImmq(0)),
                                   lir->ins_eq0(lir->ins2(LIR_feq, v_ins, v_ins))));
         return JSRS_CONTINUE;
@@ -8827,17 +8835,17 @@ TraceRecorder::record_JSOP_NEG()
         return JSRS_CONTINUE;
     }
 
     if (JSVAL_IS_NULL(v)) {
         set(&v, lir->insImmf(-0.0));
         return JSRS_CONTINUE;
     }
 
-    JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING || JSVAL_TAG(v) == JSVAL_BOOLEAN);
+    JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING || JSVAL_IS_SPECIAL(v));
 
     LIns* args[] = { get(&v), cx_ins };
     set(&v, lir->ins1(LIR_fneg,
                       lir->insCall(JSVAL_IS_STRING(v)
                                    ? &js_StringToNumber_ci
                                    : &js_BooleanOrUndefinedToNumber_ci,
                                    args)));
     return JSRS_CONTINUE;
@@ -8856,17 +8864,17 @@ TraceRecorder::record_JSOP_POS()
     if (isNumber(v))
         return JSRS_CONTINUE;
 
     if (JSVAL_IS_NULL(v)) {
         set(&v, lir->insImmq(0));
         return JSRS_CONTINUE;
     }
 
-    JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING || JSVAL_TAG(v) == JSVAL_BOOLEAN);
+    JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING || JSVAL_IS_SPECIAL(v));
 
     LIns* args[] = { get(&v), cx_ins };
     set(&v, lir->insCall(JSVAL_IS_STRING(v)
                          ? &js_StringToNumber_ci
                          : &js_BooleanOrUndefinedToNumber_ci,
                          args));
     return JSRS_CONTINUE;
 }
@@ -9090,17 +9098,17 @@ TraceRecorder::emitNativeCall(JSTraceabl
       case FAIL_NULL:
         guard(false, lir->ins_eq0(res_ins), OOM_EXIT);
         break;
       case FAIL_NEG:
         res_ins = lir->ins1(LIR_i2f, res_ins);
         guard(false, lir->ins2(LIR_flt, res_ins, lir->insImmq(0)), OOM_EXIT);
         break;
       case FAIL_VOID:
-        guard(false, lir->ins2i(LIR_eq, res_ins, JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID)), OOM_EXIT);
+        guard(false, lir->ins2i(LIR_eq, res_ins, JSVAL_TO_SPECIAL(JSVAL_VOID)), OOM_EXIT);
         break;
       case FAIL_COOKIE:
         guard(false, lir->ins2(LIR_eq, res_ins, INS_CONST(JSVAL_ERROR_COOKIE)), OOM_EXIT);
         break;
       default:;
     }
 
     set(&stackval(0 - (2 + argc)), res_ins);
@@ -9496,34 +9504,34 @@ TraceRecorder::record_JSOP_TYPEOF()
     if (JSVAL_IS_STRING(r)) {
         type = INS_CONSTPTR(ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_STRING]));
     } else if (isNumber(r)) {
         type = INS_CONSTPTR(ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]));
     } else if (VALUE_IS_FUNCTION(cx, r)) {
         type = INS_CONSTPTR(ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_FUNCTION]));
     } else {
         LIns* args[] = { get(&r), cx_ins };
-        if (JSVAL_TAG(r) == JSVAL_BOOLEAN) {
+        if (JSVAL_IS_SPECIAL(r)) {
             // We specialize identically for boolean and undefined. We must not have a hole here.
             // Pass the unboxed type here, since TypeOfBoolean knows how to handle it.
             JS_ASSERT(r == JSVAL_TRUE || r == JSVAL_FALSE || r == JSVAL_VOID);
             type = lir->insCall(&js_TypeOfBoolean_ci, args);
         } else {
             JS_ASSERT(JSVAL_TAG(r) == JSVAL_OBJECT);
             type = lir->insCall(&js_TypeOfObject_ci, args);
         }
     }
     set(&r, type);
     return JSRS_CONTINUE;
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::record_JSOP_VOID()
 {
-    stack(-1, INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID)));
+    stack(-1, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID)));
     return JSRS_CONTINUE;
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::record_JSOP_INCNAME()
 {
     return incName(1);
 }
@@ -10880,17 +10888,17 @@ TraceRecorder::prop(JSObject* obj, LIns*
                                           "shape");
                 guard(true,
                       addName(lir->ins2i(LIR_eq, shape_ins, OBJ_SHAPE(obj)), "guard(shape)"),
                       exit);
             } else if (!guardDenseArray(obj, obj_ins, BRANCH_EXIT))
                 ABORT_TRACE("non-native object involved in undefined property access");
         } while (guardHasPrototype(obj, obj_ins, &obj, &obj_ins, exit));
 
-        v_ins = INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID));
+        v_ins = INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID));
         slot = SPROP_INVALID_SLOT;
         return JSRS_CONTINUE;
     }
 
     uint32 setflags = (cs.format & (JOF_INCDEC | JOF_FOR));
     JS_ASSERT(!(cs.format & JOF_SET));
 
     /* Don't trace getter or setter calls, our caller wants a direct slot. */
@@ -10911,17 +10919,17 @@ TraceRecorder::prop(JSObject* obj, LIns*
                 LIns* args[] = { INS_CONSTPTR(sprop), obj_ins, cx_ins };
                 v_ins = lir->insCall(&js_CallGetter_ci, args);
                 guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)), OOM_EXIT);
 
                 /*
                  * BIG FAT WARNING: This snapshot cannot be a BRANCH_EXIT, since
                  * the value to the top of the stack is not the value we unbox.
                  */
-                unbox_jsval((sprop->shortid == REGEXP_SOURCE) ? JSVAL_STRING : JSVAL_BOOLEAN,
+                unbox_jsval((sprop->shortid == REGEXP_SOURCE) ? JSVAL_STRING : JSVAL_SPECIAL,
                             v_ins,
                             snapshot(MISMATCH_EXIT));
                 return JSRS_CONTINUE;
             }
             if (setflags == 0 &&
                 sprop->getter == js_StringClass.getProperty &&
                 sprop->id == ATOM_KEY(cx->runtime->atomState.lengthAtom)) {
                 if (!guardClass(obj, obj_ins, &js_StringClass, snapshot(MISMATCH_EXIT)))
@@ -11014,17 +11022,17 @@ TraceRecorder::denseArrayElement(jsval& 
             br1->setTarget(label);
         br2->setTarget(label);
         br3->setTarget(label);
         br4->setTarget(label);
 
         CHECK_STATUS(guardPrototypeHasNoIndexedProperties(obj, obj_ins, MISMATCH_EXIT));
 
         // Return undefined and indicate that we didn't actually read this (addr_ins).
-        v_ins = lir->insImm(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID));
+        v_ins = lir->insImm(JSVAL_TO_SPECIAL(JSVAL_VOID));
         addr_ins = NULL;
         return JSRS_CONTINUE;
     }
 
     /* Guard against negative index */
     if (MAX_DSLOTS_LENGTH > JS_BITMASK(30) && !idx_ins->isconst()) {
         JS_ASSERT(sizeof(jsval) == 8); // Only 64-bit machines support large enough arrays for this.
         guard(false,
@@ -11051,23 +11059,23 @@ TraceRecorder::denseArrayElement(jsval& 
 
     /* Load the value and guard on its type to unbox it. */
     vp = &obj->dslots[jsuint(idx)];
     addr_ins = lir->ins2(LIR_piadd, dslots_ins,
                          lir->ins2i(LIR_pilsh, idx_ins, (sizeof(jsval) == 4) ? 2 : 3));
     v_ins = lir->insLoad(LIR_ldp, addr_ins, 0);
     unbox_jsval(*vp, v_ins, exit);
 
-    if (JSVAL_TAG(*vp) == JSVAL_BOOLEAN) {
+    if (JSVAL_IS_SPECIAL(*vp)) {
         /*
          * If we read a hole from the array, convert it to undefined and guard
          * that there are no indexed properties along the prototype chain.
          */
         LIns* br = lir->insBranch(LIR_jf,
-                                  lir->ins2i(LIR_eq, v_ins, JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_HOLE)),
+                                  lir->ins2i(LIR_eq, v_ins, JSVAL_TO_SPECIAL(JSVAL_HOLE)),
                                   NULL);
         CHECK_STATUS(guardPrototypeHasNoIndexedProperties(obj, obj_ins, MISMATCH_EXIT));
         br->setTarget(lir->ins0(LIR_label));
 
         /* Don't let the hole value escape. Turn it into an undefined. */
         v_ins = lir->ins2i(LIR_and, v_ins, ~(JSVAL_HOLE_FLAG >> JSVAL_TAGBITS));
     }
     return JSRS_CONTINUE;
@@ -11573,17 +11581,17 @@ TraceRecorder::record_JSOP_IN()
         if (!js_ValueToStringId(cx, lval, &id))
             ABORT_TRACE_ERROR("left operand of JSOP_IN didn't convert to a string-id");
         LIns* args[] = { get(&lval), obj_ins, cx_ins };
         x = lir->insCall(&js_HasNamedProperty_ci, args);
     } else {
         ABORT_TRACE("string or integer expected");
     }
 
-    guard(false, lir->ins2i(LIR_eq, x, JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID)), OOM_EXIT);
+    guard(false, lir->ins2i(LIR_eq, x, JSVAL_TO_SPECIAL(JSVAL_VOID)), OOM_EXIT);
     x = lir->ins2i(LIR_eq, x, 1);
 
     JSObject* obj2;
     JSProperty* prop;
     if (!obj->lookupProperty(cx, id, &obj2, &prop))
         ABORT_TRACE_ERROR("obj->lookupProperty failed in JSOP_IN");
     bool cond = prop != NULL;
     if (prop)
@@ -12271,20 +12279,20 @@ TraceRecorder::record_JSOP_CALLPROP()
         jsint i;
         debug_only_stmt(const char* protoname = NULL;)
         if (JSVAL_IS_STRING(l)) {
             i = JSProto_String;
             debug_only_stmt(protoname = "String.prototype";)
         } else if (JSVAL_IS_NUMBER(l)) {
             i = JSProto_Number;
             debug_only_stmt(protoname = "Number.prototype";)
-        } else if (JSVAL_TAG(l) == JSVAL_BOOLEAN) {
+        } else if (JSVAL_IS_SPECIAL(l)) {
             if (l == JSVAL_VOID)
                 ABORT_TRACE("callprop on void");
-            guard(false, lir->ins2i(LIR_eq, get(&l), JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID)), MISMATCH_EXIT);
+            guard(false, lir->ins2i(LIR_eq, get(&l), JSVAL_TO_SPECIAL(JSVAL_VOID)), MISMATCH_EXIT);
             i = JSProto_Boolean;
             debug_only_stmt(protoname = "Boolean.prototype";)
         } else {
             JS_ASSERT(JSVAL_IS_NULL(l) || JSVAL_IS_VOID(l));
             ABORT_TRACE("callprop on null or void");
         }
 
         if (!js_GetClassPrototype(cx, NULL, INT_TO_JSID(i), &obj))
@@ -12376,17 +12384,17 @@ TraceRecorder::record_JSOP_STOP()
      *
      * NB: we do not support script rval (eval, API users who want the result
      * of the last expression-statement, debugger API calls).
      */
     if (fp->flags & JSFRAME_CONSTRUCTING) {
         JS_ASSERT(OBJECT_TO_JSVAL(fp->thisp) == fp->argv[-1]);
         rval_ins = get(&fp->argv[-1]);
     } else {
-        rval_ins = INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID));
+        rval_ins = INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID));
     }
     clearFrameSlotsFromCache();
     return JSRS_CONTINUE;
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::record_JSOP_GETXPROP()
 {
@@ -12415,17 +12423,17 @@ TraceRecorder::record_JSOP_TYPEOFEXPR()
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::record_JSOP_ENTERBLOCK()
 {
     JSObject* obj;
     JS_GET_SCRIPT_OBJECT(cx->fp->script, getFullIndex(0), obj);
 
-    LIns* void_ins = INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID));
+    LIns* void_ins = INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID));
     for (int i = 0, n = OBJ_BLOCK_COUNT(cx, obj); i < n; i++)
         stack(i, void_ins);
     return JSRS_CONTINUE;
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::record_JSOP_LEAVEBLOCK()
 {
@@ -12758,17 +12766,17 @@ TraceRecorder::record_JSOP_NEWARRAY()
 
     stack(-int(len), v_ins);
     return JSRS_CONTINUE;
 }
 
 JS_REQUIRES_STACK JSRecordingStatus
 TraceRecorder::record_JSOP_HOLE()
 {
-    stack(0, INS_CONST(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_HOLE)));
+    stack(0, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_HOLE)));
     return JSRS_CONTINUE;
 }
 
 JSRecordingStatus
 TraceRecorder::record_JSOP_LOOP()
 {
     return JSRS_CONTINUE;
 }
--- a/js/src/jsxdrapi.cpp
+++ b/js/src/jsxdrapi.cpp
@@ -552,17 +552,17 @@ XDRValueBody(JSXDRState *xdr, uint32 typ
         if (xdr->mode == JSXDR_ENCODE)
             obj = JSVAL_TO_OBJECT(*vp);
         if (!js_XDRObject(xdr, &obj))
             return JS_FALSE;
         if (xdr->mode == JSXDR_DECODE)
             *vp = OBJECT_TO_JSVAL(obj);
         break;
       }
-      case JSVAL_BOOLEAN: {
+      case JSVAL_SPECIAL: {
         uint32 b;
         if (xdr->mode == JSXDR_ENCODE)
             b = (uint32) JSVAL_TO_BOOLEAN(*vp);
         if (!JS_XDRUint32(xdr, &b))
             return JS_FALSE;
         if (xdr->mode == JSXDR_DECODE)
             *vp = BOOLEAN_TO_JSVAL(!!b);
         break;