Bug 837773 - Move JS::Value into Value.h. r=jorendorff
authorJeff Walden <jwalden@mit.edu>
Fri, 01 Feb 2013 16:15:49 -0800
changeset 120966 f13e3cac0c1b058fa6880a50f618e288941dda85
parent 120965 7f1ecab23f6f67254c5fb9ea5c1c0384cbeedaf4
child 120967 06fe741ec9538e7de9fc43a8a730b8d5a1782e78
push id24269
push useremorley@mozilla.com
push dateWed, 06 Feb 2013 14:27:17 +0000
treeherdermozilla-central@04e13fc9dbff [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs837773
milestone21.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 837773 - Move JS::Value into Value.h. r=jorendorff
js/public/Value.h
js/src/jsapi.h
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -5,19 +5,33 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* JS::Value implementation. */
 
 #ifndef js_Value_h___
 #define js_Value_h___
 
+#include "mozilla/Attributes.h"
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/Likely.h"
+
+#include <limits> /* for std::numeric_limits */
+
+#include "gc/Root.h"
 #include "js/Anchor.h"
 #include "js/Utility.h"
 
+namespace JS { class Value; }
+
+/* JS::Value can store a full int32_t. */
+#define JSVAL_INT_BITS          32
+#define JSVAL_INT_MIN           ((int32_t)0x80000000)
+#define JSVAL_INT_MAX           ((int32_t)0x7fffffff)
+
 /*
  * Try to get jsvals 64-bit aligned. We could almost assert that all values are
  * aligned, but MSVC and GCC occasionally break alignment.
  */
 #if defined(__GNUC__) || defined(__xlc__) || defined(__xlC__)
 # define JSVAL_ALIGNMENT        __attribute__((aligned (8)))
 #elif defined(_MSC_VER)
   /*
@@ -323,524 +337,1315 @@ JS_STATIC_ASSERT(sizeof(jsval_layout) ==
 #if JS_BITS_PER_WORD == 32
 
 /*
  * N.B. GCC, in some but not all cases, chooses to emit signed comparison of
  * JSValueTag even though its underlying type has been forced to be uint32_t.
  * Thus, all comparisons should explicitly cast operands to uint32_t.
  */
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 BUILD_JSVAL(JSValueTag tag, uint32_t payload)
 {
     jsval_layout l;
     l.asBits = (((uint64_t)(uint32_t)tag) << 32) | payload;
     return l;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_DOUBLE_IMPL(jsval_layout l)
 {
     return (uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_CLEAR;
 }
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 DOUBLE_TO_JSVAL_IMPL(double d)
 {
     jsval_layout l;
     l.asDouble = d;
-    JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
+    MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
     return l;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_INT32_IMPL(jsval_layout l)
 {
     return l.s.tag == JSVAL_TAG_INT32;
 }
 
-static JS_ALWAYS_INLINE int32_t
+static MOZ_ALWAYS_INLINE int32_t
 JSVAL_TO_INT32_IMPL(jsval_layout l)
 {
     return l.s.payload.i32;
 }
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 INT32_TO_JSVAL_IMPL(int32_t i)
 {
     jsval_layout l;
     l.s.tag = JSVAL_TAG_INT32;
     l.s.payload.i32 = i;
     return l;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_NUMBER_IMPL(jsval_layout l)
 {
     JSValueTag tag = l.s.tag;
-    JS_ASSERT(tag != JSVAL_TAG_CLEAR);
+    MOZ_ASSERT(tag != JSVAL_TAG_CLEAR);
     return (uint32_t)tag <= (uint32_t)JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_UNDEFINED_IMPL(jsval_layout l)
 {
     return l.s.tag == JSVAL_TAG_UNDEFINED;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_STRING_IMPL(jsval_layout l)
 {
     return l.s.tag == JSVAL_TAG_STRING;
 }
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 STRING_TO_JSVAL_IMPL(JSString *str)
 {
     jsval_layout l;
-    JS_ASSERT(str);
+    MOZ_ASSERT(str);
     l.s.tag = JSVAL_TAG_STRING;
     l.s.payload.str = str;
     return l;
 }
 
-static JS_ALWAYS_INLINE JSString *
+static MOZ_ALWAYS_INLINE JSString *
 JSVAL_TO_STRING_IMPL(jsval_layout l)
 {
     return l.s.payload.str;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_BOOLEAN_IMPL(jsval_layout l)
 {
     return l.s.tag == JSVAL_TAG_BOOLEAN;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_TO_BOOLEAN_IMPL(jsval_layout l)
 {
     return l.s.payload.boo;
 }
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 BOOLEAN_TO_JSVAL_IMPL(JSBool b)
 {
     jsval_layout l;
-    JS_ASSERT(b == JS_TRUE || b == JS_FALSE);
+    MOZ_ASSERT(b == JS_TRUE || b == JS_FALSE);
     l.s.tag = JSVAL_TAG_BOOLEAN;
     l.s.payload.boo = b;
     return l;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_MAGIC_IMPL(jsval_layout l)
 {
     return l.s.tag == JSVAL_TAG_MAGIC;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_OBJECT_IMPL(jsval_layout l)
 {
     return l.s.tag == JSVAL_TAG_OBJECT;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l)
 {
     return (uint32_t)l.s.tag < (uint32_t)JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l)
 {
-    JS_ASSERT((uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_OBJECT);
+    MOZ_ASSERT((uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_OBJECT);
     return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET;
 }
 
-static JS_ALWAYS_INLINE JSObject *
+static MOZ_ALWAYS_INLINE JSObject *
 JSVAL_TO_OBJECT_IMPL(jsval_layout l)
 {
     return l.s.payload.obj;
 }
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 OBJECT_TO_JSVAL_IMPL(JSObject *obj)
 {
     jsval_layout l;
-    JS_ASSERT(obj);
+    MOZ_ASSERT(obj);
     l.s.tag = JSVAL_TAG_OBJECT;
     l.s.payload.obj = obj;
     return l;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_NULL_IMPL(jsval_layout l)
 {
     return l.s.tag == JSVAL_TAG_NULL;
 }
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr)
 {
     jsval_layout l;
-    JS_ASSERT(((uint32_t)ptr & 1) == 0);
+    MOZ_ASSERT(((uint32_t)ptr & 1) == 0);
     l.s.tag = (JSValueTag)0;
     l.s.payload.ptr = ptr;
-    JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
+    MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
     return l;
 }
 
-static JS_ALWAYS_INLINE void *
+static MOZ_ALWAYS_INLINE void *
 JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l)
 {
     return l.s.payload.ptr;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_GCTHING_IMPL(jsval_layout l)
 {
     /* gcc sometimes generates signed < without explicit casts. */
     return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET;
 }
 
-static JS_ALWAYS_INLINE void *
+static MOZ_ALWAYS_INLINE void *
 JSVAL_TO_GCTHING_IMPL(jsval_layout l)
 {
     return l.s.payload.ptr;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_TRACEABLE_IMPL(jsval_layout l)
 {
     return l.s.tag == JSVAL_TAG_STRING || l.s.tag == JSVAL_TAG_OBJECT;
 }
 
-static JS_ALWAYS_INLINE uint32_t
+static MOZ_ALWAYS_INLINE uint32_t
 JSVAL_TRACE_KIND_IMPL(jsval_layout l)
 {
     return (uint32_t)(JSBool)JSVAL_IS_STRING_IMPL(l);
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32)
 {
     return l.s.tag == JSVAL_TAG_INT32 && l.s.payload.i32 == i32;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b)
 {
     return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == b);
 }
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
 {
     jsval_layout l;
     l.s.tag = JSVAL_TAG_MAGIC;
     l.s.payload.why = why;
     return l;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs)
 {
     JSValueTag ltag = lhs.s.tag, rtag = rhs.s.tag;
     return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR);
 }
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 PRIVATE_UINT32_TO_JSVAL_IMPL(uint32_t ui)
 {
     jsval_layout l;
     l.s.tag = (JSValueTag)0;
     l.s.payload.u32 = ui;
-    JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
+    MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
     return l;
 }
 
-static JS_ALWAYS_INLINE uint32_t
+static MOZ_ALWAYS_INLINE uint32_t
 JSVAL_TO_PRIVATE_UINT32_IMPL(jsval_layout l)
 {
     return l.s.payload.u32;
 }
 
-static JS_ALWAYS_INLINE JSValueType
+static MOZ_ALWAYS_INLINE JSValueType
 JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l)
 {
     uint32_t type = l.s.tag & 0xF;
-    JS_ASSERT(type > JSVAL_TYPE_DOUBLE);
+    MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE);
     return (JSValueType)type;
 }
 
 #elif JS_BITS_PER_WORD == 64
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 BUILD_JSVAL(JSValueTag tag, uint64_t payload)
 {
     jsval_layout l;
     l.asBits = (((uint64_t)(uint32_t)tag) << JSVAL_TAG_SHIFT) | payload;
     return l;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_DOUBLE_IMPL(jsval_layout l)
 {
     return l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE;
 }
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 DOUBLE_TO_JSVAL_IMPL(double d)
 {
     jsval_layout l;
     l.asDouble = d;
-    JS_ASSERT(l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE);
+    MOZ_ASSERT(l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE);
     return l;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_INT32_IMPL(jsval_layout l)
 {
     return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_INT32;
 }
 
-static JS_ALWAYS_INLINE int32_t
+static MOZ_ALWAYS_INLINE int32_t
 JSVAL_TO_INT32_IMPL(jsval_layout l)
 {
     return (int32_t)l.asBits;
 }
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 INT32_TO_JSVAL_IMPL(int32_t i32)
 {
     jsval_layout l;
     l.asBits = ((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32;
     return l;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_NUMBER_IMPL(jsval_layout l)
 {
     return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_UNDEFINED_IMPL(jsval_layout l)
 {
     return l.asBits == JSVAL_SHIFTED_TAG_UNDEFINED;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_STRING_IMPL(jsval_layout l)
 {
     return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_STRING;
 }
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 STRING_TO_JSVAL_IMPL(JSString *str)
 {
     jsval_layout l;
     uint64_t strBits = (uint64_t)str;
-    JS_ASSERT(str);
-    JS_ASSERT((strBits >> JSVAL_TAG_SHIFT) == 0);
+    MOZ_ASSERT(str);
+    MOZ_ASSERT((strBits >> JSVAL_TAG_SHIFT) == 0);
     l.asBits = strBits | JSVAL_SHIFTED_TAG_STRING;
     return l;
 }
 
-static JS_ALWAYS_INLINE JSString *
+static MOZ_ALWAYS_INLINE JSString *
 JSVAL_TO_STRING_IMPL(jsval_layout l)
 {
     return (JSString *)(l.asBits & JSVAL_PAYLOAD_MASK);
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_BOOLEAN_IMPL(jsval_layout l)
 {
     return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_BOOLEAN;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_TO_BOOLEAN_IMPL(jsval_layout l)
 {
     return (JSBool)l.asBits;
 }
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 BOOLEAN_TO_JSVAL_IMPL(JSBool b)
 {
     jsval_layout l;
-    JS_ASSERT(b == JS_TRUE || b == JS_FALSE);
+    MOZ_ASSERT(b == JS_TRUE || b == JS_FALSE);
     l.asBits = ((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN;
     return l;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_MAGIC_IMPL(jsval_layout l)
 {
     return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_MAGIC;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l)
 {
     return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_OBJECT_IMPL(jsval_layout l)
 {
-    JS_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_SHIFTED_TAG_OBJECT);
+    MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_SHIFTED_TAG_OBJECT);
     return l.asBits >= JSVAL_SHIFTED_TAG_OBJECT;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l)
 {
-    JS_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT);
+    MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT);
     return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET;
 }
 
-static JS_ALWAYS_INLINE JSObject *
+static MOZ_ALWAYS_INLINE JSObject *
 JSVAL_TO_OBJECT_IMPL(jsval_layout l)
 {
     uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK;
-    JS_ASSERT((ptrBits & 0x7) == 0);
+    MOZ_ASSERT((ptrBits & 0x7) == 0);
     return (JSObject *)ptrBits;
 }
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 OBJECT_TO_JSVAL_IMPL(JSObject *obj)
 {
     jsval_layout l;
     uint64_t objBits = (uint64_t)obj;
-    JS_ASSERT(obj);
-    JS_ASSERT((objBits >> JSVAL_TAG_SHIFT) == 0);
+    MOZ_ASSERT(obj);
+    MOZ_ASSERT((objBits >> JSVAL_TAG_SHIFT) == 0);
     l.asBits = objBits | JSVAL_SHIFTED_TAG_OBJECT;
     return l;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_NULL_IMPL(jsval_layout l)
 {
     return l.asBits == JSVAL_SHIFTED_TAG_NULL;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_GCTHING_IMPL(jsval_layout l)
 {
     return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET;
 }
 
-static JS_ALWAYS_INLINE void *
+static MOZ_ALWAYS_INLINE void *
 JSVAL_TO_GCTHING_IMPL(jsval_layout l)
 {
     uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK;
-    JS_ASSERT((ptrBits & 0x7) == 0);
+    MOZ_ASSERT((ptrBits & 0x7) == 0);
     return (void *)ptrBits;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_TRACEABLE_IMPL(jsval_layout l)
 {
     return JSVAL_IS_GCTHING_IMPL(l) && !JSVAL_IS_NULL_IMPL(l);
 }
 
-static JS_ALWAYS_INLINE uint32_t
+static MOZ_ALWAYS_INLINE uint32_t
 JSVAL_TRACE_KIND_IMPL(jsval_layout l)
 {
     return (uint32_t)(JSBool)!(JSVAL_IS_OBJECT_IMPL(l));
 }
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr)
 {
     jsval_layout l;
     uint64_t ptrBits = (uint64_t)ptr;
-    JS_ASSERT((ptrBits & 1) == 0);
+    MOZ_ASSERT((ptrBits & 1) == 0);
     l.asBits = ptrBits >> 1;
-    JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
+    MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
     return l;
 }
 
-static JS_ALWAYS_INLINE void *
+static MOZ_ALWAYS_INLINE void *
 JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l)
 {
-    JS_ASSERT((l.asBits & 0x8000000000000000LL) == 0);
+    MOZ_ASSERT((l.asBits & 0x8000000000000000LL) == 0);
     return (void *)(l.asBits << 1);
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32)
 {
     return l.asBits == (((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32);
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b)
 {
     return l.asBits == (((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN);
 }
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
 {
     jsval_layout l;
     l.asBits = ((uint64_t)(uint32_t)why) | JSVAL_SHIFTED_TAG_MAGIC;
     return l;
 }
 
-static JS_ALWAYS_INLINE JSBool
+static MOZ_ALWAYS_INLINE JSBool
 JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs)
 {
     uint64_t lbits = lhs.asBits, rbits = rhs.asBits;
     return (lbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE && rbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE) ||
            (((lbits ^ rbits) & 0xFFFF800000000000LL) == 0);
 }
 
-static JS_ALWAYS_INLINE jsval_layout
+static MOZ_ALWAYS_INLINE jsval_layout
 PRIVATE_UINT32_TO_JSVAL_IMPL(uint32_t ui)
 {
     jsval_layout l;
     l.asBits = (uint64_t)ui;
-    JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
+    MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
     return l;
 }
 
-static JS_ALWAYS_INLINE uint32_t
+static MOZ_ALWAYS_INLINE uint32_t
 JSVAL_TO_PRIVATE_UINT32_IMPL(jsval_layout l)
 {
-    JS_ASSERT((l.asBits >> 32) == 0);
+    MOZ_ASSERT((l.asBits >> 32) == 0);
     return (uint32_t)l.asBits;
 }
 
-static JS_ALWAYS_INLINE JSValueType
+static MOZ_ALWAYS_INLINE JSValueType
 JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l)
 {
    uint64_t type = (l.asBits >> JSVAL_TAG_SHIFT) & 0xF;
-   JS_ASSERT(type > JSVAL_TYPE_DOUBLE);
+   MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE);
    return (JSValueType)type;
 }
 
 #endif  /* JS_BITS_PER_WORD */
 
-static JS_ALWAYS_INLINE double
+static MOZ_ALWAYS_INLINE double
 JS_CANONICALIZE_NAN(double d)
 {
-    if (JS_UNLIKELY(d != d)) {
+    if (MOZ_UNLIKELY(d != d)) {
         jsval_layout l;
         l.asBits = 0x7FF8000000000000LL;
         return l.asDouble;
     }
     return d;
 }
 
-#ifdef __cplusplus
-static jsval_layout JSVAL_TO_IMPL(JS::Value);
-static JS::Value IMPL_TO_JSVAL(jsval_layout);
+static MOZ_ALWAYS_INLINE jsval_layout JSVAL_TO_IMPL(JS::Value v);
+static MOZ_ALWAYS_INLINE JS::Value IMPL_TO_JSVAL(jsval_layout l);
+
+namespace JS {
+
+/*
+ * JS::Value is the interface for a single JavaScript Engine value.  A few
+ * general notes on JS::Value:
+ *
+ * - JS::Value has setX() and isX() members for X in
+ *
+ *     { Int32, Double, String, Boolean, Undefined, Null, Object, Magic }
+ *
+ *   JS::Value also contains toX() for each of the non-singleton types.
+ *
+ * - Magic is a singleton type whose payload contains a JSWhyMagic "reason" for
+ *   the magic value. By providing JSWhyMagic values when creating and checking
+ *   for magic values, it is possible to assert, at runtime, that only magic
+ *   values with the expected reason flow through a particular value. For
+ *   example, if cx->exception has a magic value, the reason must be
+ *   JS_GENERATOR_CLOSING.
+ *
+ * - The JS::Value operations are preferred.  The JSVAL_* operations remain for
+ *   compatibility; they may be removed at some point.  These operations mostly
+ *   provide similar functionality.  But there are a few key differences.  One
+ *   is that JS::Value gives null a separate type. Thus
+ *
+ *           JSVAL_IS_OBJECT(v) === v.isObjectOrNull()
+ *       !JSVAL_IS_PRIMITIVE(v) === v.isObject()
+ *
+ *   Also, to help prevent mistakenly boxing a nullable JSObject* as an object,
+ *   Value::setObject takes a JSObject&. (Conversely, Value::asObject returns a
+ *   JSObject&.)  A convenience member Value::setObjectOrNull is provided.
+ *
+ * - JSVAL_VOID is the same as the singleton value of the Undefined type.
+ *
+ * - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Thus, on
+ *   32-bit user code should avoid copying jsval/JS::Value as much as possible,
+ *   preferring to pass by const Value &.
+ */
+class Value
+{
+  public:
+    /*
+     * N.B. the default constructor leaves Value unitialized. Adding a default
+     * constructor prevents Value from being stored in a union.
+     */
+
+    /*** Mutators ***/
+
+    MOZ_ALWAYS_INLINE
+    void setNull() {
+        data.asBits = BUILD_JSVAL(JSVAL_TAG_NULL, 0).asBits;
+    }
+
+    MOZ_ALWAYS_INLINE
+    void setUndefined() {
+        data.asBits = BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0).asBits;
+    }
+
+    MOZ_ALWAYS_INLINE
+    void setInt32(int32_t i) {
+        data = INT32_TO_JSVAL_IMPL(i);
+    }
+
+    MOZ_ALWAYS_INLINE
+    int32_t &getInt32Ref() {
+        MOZ_ASSERT(isInt32());
+        return data.s.payload.i32;
+    }
+
+    MOZ_ALWAYS_INLINE
+    void setDouble(double d) {
+        data = DOUBLE_TO_JSVAL_IMPL(d);
+    }
+
+    MOZ_ALWAYS_INLINE
+    double &getDoubleRef() {
+        MOZ_ASSERT(isDouble());
+        return data.asDouble;
+    }
+
+    MOZ_ALWAYS_INLINE
+    void setString(JSString *str) {
+        MOZ_ASSERT(!IsPoisonedPtr(str));
+        data = STRING_TO_JSVAL_IMPL(str);
+    }
+
+    MOZ_ALWAYS_INLINE
+    void setString(const JS::Anchor<JSString *> &str) {
+        setString(str.get());
+    }
+
+    MOZ_ALWAYS_INLINE
+    void setObject(JSObject &obj) {
+        MOZ_ASSERT(!IsPoisonedPtr(&obj));
+        data = OBJECT_TO_JSVAL_IMPL(&obj);
+    }
+
+    MOZ_ALWAYS_INLINE
+    void setBoolean(bool b) {
+        data = BOOLEAN_TO_JSVAL_IMPL(b);
+    }
+
+    MOZ_ALWAYS_INLINE
+    void setMagic(JSWhyMagic why) {
+        data = MAGIC_TO_JSVAL_IMPL(why);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool setNumber(uint32_t ui) {
+        if (ui > JSVAL_INT_MAX) {
+            setDouble((double)ui);
+            return false;
+        } else {
+            setInt32((int32_t)ui);
+            return true;
+        }
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool setNumber(double d) {
+        int32_t i;
+        if (MOZ_DOUBLE_IS_INT32(d, &i)) {
+            setInt32(i);
+            return true;
+        } else {
+            setDouble(d);
+            return false;
+        }
+    }
+
+    MOZ_ALWAYS_INLINE
+    void setObjectOrNull(JSObject *arg) {
+        if (arg)
+            setObject(*arg);
+        else
+            setNull();
+    }
+
+    MOZ_ALWAYS_INLINE
+    void swap(Value &rhs) {
+        uint64_t tmp = rhs.data.asBits;
+        rhs.data.asBits = data.asBits;
+        data.asBits = tmp;
+    }
+
+    /*** Value type queries ***/
+
+    MOZ_ALWAYS_INLINE
+    bool isUndefined() const {
+        return JSVAL_IS_UNDEFINED_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool isNull() const {
+        return JSVAL_IS_NULL_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool isNullOrUndefined() const {
+        return isNull() || isUndefined();
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool isInt32() const {
+        return JSVAL_IS_INT32_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool isInt32(int32_t i32) const {
+        return JSVAL_IS_SPECIFIC_INT32_IMPL(data, i32);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool isDouble() const {
+        return JSVAL_IS_DOUBLE_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool isNumber() const {
+        return JSVAL_IS_NUMBER_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool isString() const {
+        return JSVAL_IS_STRING_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool isObject() const {
+        return JSVAL_IS_OBJECT_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool isPrimitive() const {
+        return JSVAL_IS_PRIMITIVE_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool isObjectOrNull() const {
+        return JSVAL_IS_OBJECT_OR_NULL_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool isGCThing() const {
+        return JSVAL_IS_GCTHING_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool isBoolean() const {
+        return JSVAL_IS_BOOLEAN_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool isTrue() const {
+        return JSVAL_IS_SPECIFIC_BOOLEAN(data, true);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool isFalse() const {
+        return JSVAL_IS_SPECIFIC_BOOLEAN(data, false);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool isMagic() const {
+        return JSVAL_IS_MAGIC_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool isMagic(JSWhyMagic why) const {
+        MOZ_ASSERT_IF(isMagic(), data.s.payload.why == why);
+        return JSVAL_IS_MAGIC_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool isMarkable() const {
+        return JSVAL_IS_TRACEABLE_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    JSGCTraceKind gcKind() const {
+        MOZ_ASSERT(isMarkable());
+        return JSGCTraceKind(JSVAL_TRACE_KIND_IMPL(data));
+    }
+
+    MOZ_ALWAYS_INLINE
+    JSWhyMagic whyMagic() const {
+        MOZ_ASSERT(isMagic());
+        return data.s.payload.why;
+    }
+
+    /*** Comparison ***/
+
+    MOZ_ALWAYS_INLINE
+    bool operator==(const Value &rhs) const {
+        return data.asBits == rhs.data.asBits;
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool operator!=(const Value &rhs) const {
+        return data.asBits != rhs.data.asBits;
+    }
+
+    friend inline bool SameType(const Value &lhs, const Value &rhs);
+
+    /*** Extract the value's typed payload ***/
+
+    MOZ_ALWAYS_INLINE
+    int32_t toInt32() const {
+        MOZ_ASSERT(isInt32());
+        return JSVAL_TO_INT32_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    double toDouble() const {
+        MOZ_ASSERT(isDouble());
+        return data.asDouble;
+    }
+
+    MOZ_ALWAYS_INLINE
+    double toNumber() const {
+        MOZ_ASSERT(isNumber());
+        return isDouble() ? toDouble() : double(toInt32());
+    }
+
+    MOZ_ALWAYS_INLINE
+    JSString *toString() const {
+        MOZ_ASSERT(isString());
+        return JSVAL_TO_STRING_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    JSObject &toObject() const {
+        MOZ_ASSERT(isObject());
+        return *JSVAL_TO_OBJECT_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    JSObject *toObjectOrNull() const {
+        MOZ_ASSERT(isObjectOrNull());
+        return JSVAL_TO_OBJECT_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    void *toGCThing() const {
+        MOZ_ASSERT(isGCThing());
+        return JSVAL_TO_GCTHING_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    bool toBoolean() const {
+        MOZ_ASSERT(isBoolean());
+        return JSVAL_TO_BOOLEAN_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    uint32_t payloadAsRawUint32() const {
+        MOZ_ASSERT(!isDouble());
+        return data.s.payload.u32;
+    }
+
+    MOZ_ALWAYS_INLINE
+    uint64_t asRawBits() const {
+        return data.asBits;
+    }
+
+    MOZ_ALWAYS_INLINE
+    JSValueType extractNonDoubleType() const {
+        return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data);
+    }
+
+    /*
+     * Private API
+     *
+     * Private setters/getters allow the caller to read/write arbitrary types
+     * that fit in the 64-bit payload. It is the caller's responsibility, after
+     * storing to a value with setPrivateX to read only using getPrivateX.
+     * Privates values are given a type type which ensures they are not marked.
+     */
+
+    MOZ_ALWAYS_INLINE
+    void setPrivate(void *ptr) {
+        data = PRIVATE_PTR_TO_JSVAL_IMPL(ptr);
+    }
+
+    MOZ_ALWAYS_INLINE
+    void *toPrivate() const {
+        MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(data));
+        return JSVAL_TO_PRIVATE_PTR_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    void setPrivateUint32(uint32_t ui) {
+        data = PRIVATE_UINT32_TO_JSVAL_IMPL(ui);
+    }
+
+    MOZ_ALWAYS_INLINE
+    uint32_t toPrivateUint32() const {
+        MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(data));
+        return JSVAL_TO_PRIVATE_UINT32_IMPL(data);
+    }
+
+    MOZ_ALWAYS_INLINE
+    uint32_t &getPrivateUint32Ref() {
+        MOZ_ASSERT(isDouble());
+        return data.s.payload.u32;
+    }
+
+    /*
+     * An unmarked value is just a void* cast as a Value. Thus, the Value is
+     * not safe for GC and must not be marked. This API avoids raw casts
+     * and the ensuing strict-aliasing warnings.
+     */
+
+    MOZ_ALWAYS_INLINE
+    void setUnmarkedPtr(void *ptr) {
+        data.asPtr = ptr;
+    }
+
+    MOZ_ALWAYS_INLINE
+    void *toUnmarkedPtr() const {
+        return data.asPtr;
+    }
+
+    const size_t *payloadWord() const {
+#if JS_BITS_PER_WORD == 32
+        return &data.s.payload.word;
+#elif JS_BITS_PER_WORD == 64
+        return &data.asWord;
 #endif
+    }
+
+    const uintptr_t *payloadUIntPtr() const {
+#if JS_BITS_PER_WORD == 32
+        return &data.s.payload.uintptr;
+#elif JS_BITS_PER_WORD == 64
+        return &data.asUIntPtr;
+#endif
+    }
+
+#if !defined(_MSC_VER) && !defined(__sparc)
+  // Value must be POD so that MSVC will pass it by value and not in memory
+  // (bug 689101); the same is true for SPARC as well (bug 737344).  More
+  // precisely, we don't want Value return values compiled as out params.
+  private:
+#endif
+
+    jsval_layout data;
+
+  private:
+    void staticAssertions() {
+        JS_STATIC_ASSERT(sizeof(JSValueType) == 1);
+        JS_STATIC_ASSERT(sizeof(JSValueTag) == 4);
+        JS_STATIC_ASSERT(sizeof(JSBool) == 4);
+        JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4);
+        JS_STATIC_ASSERT(sizeof(Value) == 8);
+    }
+
+    friend jsval_layout (::JSVAL_TO_IMPL)(Value);
+    friend Value (::IMPL_TO_JSVAL)(jsval_layout l);
+};
+
+inline bool
+IsPoisonedValue(const Value &v)
+{
+    if (v.isString())
+        return IsPoisonedPtr(v.toString());
+    if (v.isObject())
+        return IsPoisonedPtr(&v.toObject());
+    return false;
+}
+
+/************************************************************************/
+
+static MOZ_ALWAYS_INLINE Value
+NullValue()
+{
+    Value v;
+    v.setNull();
+    return v;
+}
+
+static MOZ_ALWAYS_INLINE Value
+UndefinedValue()
+{
+    Value v;
+    v.setUndefined();
+    return v;
+}
+
+static MOZ_ALWAYS_INLINE Value
+Int32Value(int32_t i32)
+{
+    Value v;
+    v.setInt32(i32);
+    return v;
+}
+
+static MOZ_ALWAYS_INLINE Value
+DoubleValue(double dbl)
+{
+    Value v;
+    v.setDouble(dbl);
+    return v;
+}
+
+static MOZ_ALWAYS_INLINE Value
+StringValue(JSString *str)
+{
+    Value v;
+    v.setString(str);
+    return v;
+}
+
+static MOZ_ALWAYS_INLINE Value
+BooleanValue(bool boo)
+{
+    Value v;
+    v.setBoolean(boo);
+    return v;
+}
+
+static MOZ_ALWAYS_INLINE Value
+ObjectValue(JSObject &obj)
+{
+    Value v;
+    v.setObject(obj);
+    return v;
+}
+
+static MOZ_ALWAYS_INLINE Value
+ObjectValueCrashOnTouch()
+{
+    Value v;
+    v.setObject(*reinterpret_cast<JSObject *>(0x42));
+    return v;
+}
+
+static MOZ_ALWAYS_INLINE Value
+MagicValue(JSWhyMagic why)
+{
+    Value v;
+    v.setMagic(why);
+    return v;
+}
+
+static MOZ_ALWAYS_INLINE Value
+NumberValue(float f)
+{
+    Value v;
+    v.setNumber(f);
+    return v;
+}
+
+static MOZ_ALWAYS_INLINE Value
+NumberValue(double dbl)
+{
+    Value v;
+    v.setNumber(dbl);
+    return v;
+}
+
+static MOZ_ALWAYS_INLINE Value
+NumberValue(int8_t i)
+{
+    return Int32Value(i);
+}
+
+static MOZ_ALWAYS_INLINE Value
+NumberValue(uint8_t i)
+{
+    return Int32Value(i);
+}
+
+static MOZ_ALWAYS_INLINE Value
+NumberValue(int16_t i)
+{
+    return Int32Value(i);
+}
+
+static MOZ_ALWAYS_INLINE Value
+NumberValue(uint16_t i)
+{
+    return Int32Value(i);
+}
+
+static MOZ_ALWAYS_INLINE Value
+NumberValue(int32_t i)
+{
+    return Int32Value(i);
+}
+
+static MOZ_ALWAYS_INLINE Value
+NumberValue(uint32_t i)
+{
+    Value v;
+    v.setNumber(i);
+    return v;
+}
+
+namespace detail {
+
+template <bool Signed>
+class MakeNumberValue
+{
+  public:
+    template<typename T>
+    static inline Value create(const T t)
+    {
+        Value v;
+        if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX)
+            v.setInt32(int32_t(t));
+        else
+            v.setDouble(double(t));
+        return v;
+    }
+};
+
+template <>
+class MakeNumberValue<false>
+{
+  public:
+    template<typename T>
+    static inline Value create(const T t)
+    {
+        Value v;
+        if (t <= JSVAL_INT_MAX)
+            v.setInt32(int32_t(t));
+        else
+            v.setDouble(double(t));
+        return v;
+    }
+};
+
+} // namespace detail
+
+template <typename T>
+static MOZ_ALWAYS_INLINE Value
+NumberValue(const T t)
+{
+    MOZ_ASSERT(T(double(t)) == t, "value creation would be lossy");
+    return detail::MakeNumberValue<std::numeric_limits<T>::is_signed>::create(t);
+}
+
+static MOZ_ALWAYS_INLINE Value
+ObjectOrNullValue(JSObject *obj)
+{
+    Value v;
+    v.setObjectOrNull(obj);
+    return v;
+}
+
+static MOZ_ALWAYS_INLINE Value
+PrivateValue(void *ptr)
+{
+    Value v;
+    v.setPrivate(ptr);
+    return v;
+}
+
+static MOZ_ALWAYS_INLINE Value
+PrivateUint32Value(uint32_t ui)
+{
+    Value v;
+    v.setPrivateUint32(ui);
+    return v;
+}
+
+MOZ_ALWAYS_INLINE bool
+SameType(const Value &lhs, const Value &rhs)
+{
+    return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data);
+}
+
+} // namespace JS
+
+/************************************************************************/
+
+namespace js {
+
+template <> struct RootMethods<const JS::Value>
+{
+    static JS::Value initial() { return UndefinedValue(); }
+    static ThingRootKind kind() { return THING_ROOT_VALUE; }
+    static bool poisoned(const JS::Value &v) { return IsPoisonedValue(v); }
+};
+
+template <> struct RootMethods<JS::Value>
+{
+    static JS::Value initial() { return UndefinedValue(); }
+    static ThingRootKind kind() { return THING_ROOT_VALUE; }
+    static bool poisoned(const JS::Value &v) { return IsPoisonedValue(v); }
+};
+
+template <class Outer> class MutableValueOperations;
+
+/*
+ * A class designed for CRTP use in implementing the non-mutating parts of the
+ * Value interface in Value-like classes.  Outer must be a class inheriting
+ * ValueOperations<Outer> with a visible extract() method returning the
+ * const Value* abstracted by Outer.
+ */
+template <class Outer>
+class ValueOperations
+{
+    friend class MutableValueOperations<Outer>;
+    const JS::Value * value() const { return static_cast<const Outer*>(this)->extract(); }
+
+  public:
+    bool isUndefined() const { return value()->isUndefined(); }
+    bool isNull() const { return value()->isNull(); }
+    bool isBoolean() const { return value()->isBoolean(); }
+    bool isTrue() const { return value()->isTrue(); }
+    bool isFalse() const { return value()->isFalse(); }
+    bool isNumber() const { return value()->isNumber(); }
+    bool isInt32() const { return value()->isInt32(); }
+    bool isDouble() const { return value()->isDouble(); }
+    bool isString() const { return value()->isString(); }
+    bool isObject() const { return value()->isObject(); }
+    bool isMagic() const { return value()->isMagic(); }
+    bool isMagic(JSWhyMagic why) const { return value()->isMagic(why); }
+    bool isMarkable() const { return value()->isMarkable(); }
+    bool isPrimitive() const { return value()->isPrimitive(); }
+    bool isGCThing() const { return value()->isGCThing(); }
+
+    bool isNullOrUndefined() const { return value()->isNullOrUndefined(); }
+    bool isObjectOrNull() const { return value()->isObjectOrNull(); }
+
+    bool toBoolean() const { return value()->toBoolean(); }
+    double toNumber() const { return value()->toNumber(); }
+    int32_t toInt32() const { return value()->toInt32(); }
+    double toDouble() const { return value()->toDouble(); }
+    JSString *toString() const { return value()->toString(); }
+    JSObject &toObject() const { return value()->toObject(); }
+    JSObject *toObjectOrNull() const { return value()->toObjectOrNull(); }
+    void *toGCThing() const { return value()->toGCThing(); }
+
+    JSValueType extractNonDoubleType() const { return value()->extractNonDoubleType(); }
+
+#ifdef DEBUG
+    JSWhyMagic whyMagic() const { return value()->whyMagic(); }
+#endif
+};
+
+/*
+ * A class designed for CRTP use in implementing the mutating parts of the
+ * Value interface in Value-like classes.  Outer must be a class inheriting
+ * MutableValueOperations<Outer> with visible extractMutable() and extract()
+ * methods returning the const Value* and Value* abstracted by Outer.
+ */
+template <class Outer>
+class MutableValueOperations : public ValueOperations<Outer>
+{
+    JS::Value * value() { return static_cast<Outer*>(this)->extractMutable(); }
+
+  public:
+    void setNull() { value()->setNull(); }
+    void setUndefined() { value()->setUndefined(); }
+    void setInt32(int32_t i) { value()->setInt32(i); }
+    void setDouble(double d) { value()->setDouble(d); }
+    void setString(JSString *str) { value()->setString(str); }
+    void setString(const JS::Anchor<JSString *> &str) { value()->setString(str); }
+    void setObject(JSObject &obj) { value()->setObject(obj); }
+    void setBoolean(bool b) { value()->setBoolean(b); }
+    void setMagic(JSWhyMagic why) { value()->setMagic(why); }
+    bool setNumber(uint32_t ui) { return value()->setNumber(ui); }
+    bool setNumber(double d) { return value()->setNumber(d); }
+    void setObjectOrNull(JSObject *arg) { value()->setObjectOrNull(arg); }
+};
+
+/*
+ * Augment the generic Handle<T> interface when T = Value with type-querying
+ * and value-extracting operations.
+ */
+template <>
+class HandleBase<JS::Value> : public ValueOperations<Handle<JS::Value> >
+{
+    friend class ValueOperations<Handle<JS::Value> >;
+    const JS::Value * extract() const {
+        return static_cast<const Handle<JS::Value>*>(this)->address();
+    }
+};
+
+/*
+ * Augment the generic MutableHandle<T> interface when T = Value with
+ * type-querying, value-extracting, and mutating operations.
+ */
+template <>
+class MutableHandleBase<JS::Value> : public MutableValueOperations<MutableHandle<JS::Value> >
+{
+    friend class ValueOperations<MutableHandle<JS::Value> >;
+    const JS::Value * extract() const {
+        return static_cast<const MutableHandle<JS::Value>*>(this)->address();
+    }
+
+    friend class MutableValueOperations<MutableHandle<JS::Value> >;
+    JS::Value * extractMutable() {
+        return static_cast<MutableHandle<JS::Value>*>(this)->address();
+    }
+};
+
+/*
+ * Augment the generic Rooted<T> interface when T = Value with type-querying,
+ * value-extracting, and mutating operations.
+ */
+template <>
+class RootedBase<JS::Value> : public MutableValueOperations<Rooted<JS::Value> >
+{
+    friend class ValueOperations<Rooted<JS::Value> >;
+    const JS::Value * extract() const {
+        return static_cast<const Rooted<JS::Value>*>(this)->address();
+    }
+
+    friend class MutableValueOperations<Rooted<JS::Value> >;
+    JS::Value * extractMutable() {
+        return static_cast<Rooted<JS::Value>*>(this)->address();
+    }
+};
+
+} // namespace js
+
+MOZ_ALWAYS_INLINE jsval_layout
+JSVAL_TO_IMPL(JS::Value v)
+{
+    return v.data;
+}
+
+MOZ_ALWAYS_INLINE JS::Value
+IMPL_TO_JSVAL(jsval_layout l)
+{
+    JS::Value v;
+    v.data = l;
+    return v;
+}
 
 namespace JS {
 
 #ifndef __GNUC__
 /*
  * The default assignment operator for |struct C| has the signature:
  *
  *   C& C::operator=(const C&)
@@ -854,11 +1659,201 @@ namespace JS {
 template<>
 inline Anchor<Value>::~Anchor()
 {
     volatile uint64_t bits;
     bits = JSVAL_TO_IMPL(hold).asBits;
 }
 #endif
 
+#ifdef DEBUG
+namespace detail {
+
+struct ValueAlignmentTester { char c; JS::Value v; };
+MOZ_STATIC_ASSERT(sizeof(ValueAlignmentTester) == 16,
+                  "JS::Value must be 16-byte-aligned");
+
+struct LayoutAlignmentTester { char c; jsval_layout l; };
+MOZ_STATIC_ASSERT(sizeof(LayoutAlignmentTester) == 16,
+                  "jsval_layout must be 16-byte-aligned");
+
+} // namespace detail
+#endif /* DEBUG */
+
 } // namespace JS
 
+/*
+ * JS::Value and jsval are the same type; jsval is the old name, kept around
+ * for backwards compatibility along with all the JSVAL_* operations below.
+ * jsval_layout is an implementation detail and should not be used externally.
+ */
+typedef JS::Value jsval;
+
+MOZ_STATIC_ASSERT(sizeof(jsval_layout) == sizeof(JS::Value),
+                  "jsval_layout and JS::Value must have identical layouts");
+
+/************************************************************************/
+
+static MOZ_ALWAYS_INLINE JSBool
+JSVAL_IS_NULL(jsval v)
+{
+    return JSVAL_IS_NULL_IMPL(JSVAL_TO_IMPL(v));
+}
+
+static MOZ_ALWAYS_INLINE JSBool
+JSVAL_IS_VOID(jsval v)
+{
+    return JSVAL_IS_UNDEFINED_IMPL(JSVAL_TO_IMPL(v));
+}
+
+static MOZ_ALWAYS_INLINE JSBool
+JSVAL_IS_INT(jsval v)
+{
+    return JSVAL_IS_INT32_IMPL(JSVAL_TO_IMPL(v));
+}
+
+static MOZ_ALWAYS_INLINE int32_t
+JSVAL_TO_INT(jsval v)
+{
+    MOZ_ASSERT(JSVAL_IS_INT(v));
+    return JSVAL_TO_INT32_IMPL(JSVAL_TO_IMPL(v));
+}
+
+static MOZ_ALWAYS_INLINE jsval
+INT_TO_JSVAL(int32_t i)
+{
+    return IMPL_TO_JSVAL(INT32_TO_JSVAL_IMPL(i));
+}
+
+static MOZ_ALWAYS_INLINE JSBool
+JSVAL_IS_DOUBLE(jsval v)
+{
+    return JSVAL_IS_DOUBLE_IMPL(JSVAL_TO_IMPL(v));
+}
+
+static MOZ_ALWAYS_INLINE double
+JSVAL_TO_DOUBLE(jsval v)
+{
+    jsval_layout l;
+    MOZ_ASSERT(JSVAL_IS_DOUBLE(v));
+    l = JSVAL_TO_IMPL(v);
+    return l.asDouble;
+}
+
+static MOZ_ALWAYS_INLINE jsval
+DOUBLE_TO_JSVAL(double d)
+{
+    /*
+     * This is a manually inlined version of:
+     *    d = JS_CANONICALIZE_NAN(d);
+     *    return IMPL_TO_JSVAL(DOUBLE_TO_JSVAL_IMPL(d));
+     * because GCC from XCode 3.1.4 miscompiles the above code.
+     */
+    jsval_layout l;
+    if (MOZ_UNLIKELY(d != d))
+        l.asBits = 0x7FF8000000000000LL;
+    else
+        l.asDouble = d;
+    return IMPL_TO_JSVAL(l);
+}
+
+static MOZ_ALWAYS_INLINE jsval
+UINT_TO_JSVAL(uint32_t i)
+{
+    if (i <= JSVAL_INT_MAX)
+        return INT_TO_JSVAL((int32_t)i);
+    return DOUBLE_TO_JSVAL((double)i);
+}
+
+static MOZ_ALWAYS_INLINE JSBool
+JSVAL_IS_NUMBER(jsval v)
+{
+    return JSVAL_IS_NUMBER_IMPL(JSVAL_TO_IMPL(v));
+}
+
+static MOZ_ALWAYS_INLINE JSBool
+JSVAL_IS_STRING(jsval v)
+{
+    return JSVAL_IS_STRING_IMPL(JSVAL_TO_IMPL(v));
+}
+
+static MOZ_ALWAYS_INLINE JSString *
+JSVAL_TO_STRING(jsval v)
+{
+    MOZ_ASSERT(JSVAL_IS_STRING(v));
+    return JSVAL_TO_STRING_IMPL(JSVAL_TO_IMPL(v));
+}
+
+static MOZ_ALWAYS_INLINE jsval
+STRING_TO_JSVAL(JSString *str)
+{
+    return IMPL_TO_JSVAL(STRING_TO_JSVAL_IMPL(str));
+}
+
+static MOZ_ALWAYS_INLINE JSObject *
+JSVAL_TO_OBJECT(jsval v)
+{
+    MOZ_ASSERT(JSVAL_IS_OBJECT_OR_NULL_IMPL(JSVAL_TO_IMPL(v)));
+    return JSVAL_TO_OBJECT_IMPL(JSVAL_TO_IMPL(v));
+}
+
+static MOZ_ALWAYS_INLINE jsval
+OBJECT_TO_JSVAL(JSObject *obj)
+{
+    if (obj)
+        return IMPL_TO_JSVAL(OBJECT_TO_JSVAL_IMPL(obj));
+    return IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_NULL, 0));
+}
+
+static MOZ_ALWAYS_INLINE JSBool
+JSVAL_IS_BOOLEAN(jsval v)
+{
+    return JSVAL_IS_BOOLEAN_IMPL(JSVAL_TO_IMPL(v));
+}
+
+static MOZ_ALWAYS_INLINE JSBool
+JSVAL_TO_BOOLEAN(jsval v)
+{
+    MOZ_ASSERT(JSVAL_IS_BOOLEAN(v));
+    return JSVAL_TO_BOOLEAN_IMPL(JSVAL_TO_IMPL(v));
+}
+
+static MOZ_ALWAYS_INLINE jsval
+BOOLEAN_TO_JSVAL(JSBool b)
+{
+    return IMPL_TO_JSVAL(BOOLEAN_TO_JSVAL_IMPL(b));
+}
+
+static MOZ_ALWAYS_INLINE JSBool
+JSVAL_IS_PRIMITIVE(jsval v)
+{
+    return JSVAL_IS_PRIMITIVE_IMPL(JSVAL_TO_IMPL(v));
+}
+
+static MOZ_ALWAYS_INLINE JSBool
+JSVAL_IS_GCTHING(jsval v)
+{
+    return JSVAL_IS_GCTHING_IMPL(JSVAL_TO_IMPL(v));
+}
+
+static MOZ_ALWAYS_INLINE void *
+JSVAL_TO_GCTHING(jsval v)
+{
+    MOZ_ASSERT(JSVAL_IS_GCTHING(v));
+    return JSVAL_TO_GCTHING_IMPL(JSVAL_TO_IMPL(v));
+}
+
+/* To be GC-safe, privates are tagged as doubles. */
+
+static MOZ_ALWAYS_INLINE jsval
+PRIVATE_TO_JSVAL(void *ptr)
+{
+    return IMPL_TO_JSVAL(PRIVATE_PTR_TO_JSVAL_IMPL(ptr));
+}
+
+static MOZ_ALWAYS_INLINE void *
+JSVAL_TO_PRIVATE(jsval v)
+{
+    MOZ_ASSERT(JSVAL_IS_DOUBLE(v));
+    return JSVAL_TO_PRIVATE_PTR_IMPL(JSVAL_TO_IMPL(v));
+}
+
 #endif /* js_Value_h___ */
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -12,17 +12,16 @@
 
 #include "mozilla/Attributes.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/RangedPtr.h"
 #include "mozilla/StandardInteger.h"
 #include "mozilla/ThreadLocal.h"
 
-#include <limits> /* for std::numeric_limits */
 #include <stddef.h>
 #include <stdio.h>
 
 #include "js-config.h"
 #include "jsalloc.h"
 #include "jspubtd.h"
 #include "jsutil.h"
 
@@ -31,818 +30,30 @@
 #include "js/CharacterEncoding.h"
 #include "js/HashTable.h"
 #include "js/Utility.h"
 #include "js/Value.h"
 #include "js/Vector.h"
 
 /************************************************************************/
 
-/* JS::Value can store a full int32_t. */
-#define JSVAL_INT_BITS          32
-#define JSVAL_INT_MIN           ((int32_t)0x80000000)
-#define JSVAL_INT_MAX           ((int32_t)0x7fffffff)
-
-/************************************************************************/
-
 namespace JS {
 
 typedef mozilla::RangedPtr<const jschar> CharPtr;
 
 class StableCharPtr : public CharPtr {
   public:
     StableCharPtr(const StableCharPtr &s) : CharPtr(s) {}
     StableCharPtr(const mozilla::RangedPtr<const jschar> &s) : CharPtr(s) {}
     StableCharPtr(const jschar *s, size_t len) : CharPtr(s, len) {}
     StableCharPtr(const jschar *pos, const jschar *start, size_t len)
       : CharPtr(pos, start, len)
     {}
 };
 
-/*
- * JS::Value is the C++ interface for a single JavaScript Engine value.
- * A few general notes on JS::Value:
- *
- * - JS::Value has setX() and isX() members for X in
- *
- *     { Int32, Double, String, Boolean, Undefined, Null, Object, Magic }
- *
- *   JS::Value also contains toX() for each of the non-singleton types.
- *
- * - Magic is a singleton type whose payload contains a JSWhyMagic "reason" for
- *   the magic value. By providing JSWhyMagic values when creating and checking
- *   for magic values, it is possible to assert, at runtime, that only magic
- *   values with the expected reason flow through a particular value. For
- *   example, if cx->exception has a magic value, the reason must be
- *   JS_GENERATOR_CLOSING.
- *
- * - A key difference between JSVAL_* and JS::Value operations is that
- *   JS::Value gives null a separate type. Thus
- *
- *           JSVAL_IS_OBJECT(v) === v.isObjectOrNull()
- *       !JSVAL_IS_PRIMITIVE(v) === v.isObject()
- *
- *   To help prevent mistakenly boxing a nullable JSObject* as an object,
- *   Value::setObject takes a JSObject&. (Conversely, Value::asObject returns a
- *   JSObject&. A convenience member Value::setObjectOrNull is provided.
- *
- * - JSVAL_VOID is the same as the singleton value of the Undefined type.
- *
- * - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Thus, on
- *   32-bit user code should avoid copying jsval/JS::Value as much as possible,
- *   preferring to pass by const Value &.
- */
-class Value
-{
-  public:
-    /*
-     * N.B. the default constructor leaves Value unitialized. Adding a default
-     * constructor prevents Value from being stored in a union.
-     */
-
-    /*** Mutators ***/
-
-    JS_ALWAYS_INLINE
-    void setNull() {
-        data.asBits = BUILD_JSVAL(JSVAL_TAG_NULL, 0).asBits;
-    }
-
-    JS_ALWAYS_INLINE
-    void setUndefined() {
-        data.asBits = BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0).asBits;
-    }
-
-    JS_ALWAYS_INLINE
-    void setInt32(int32_t i) {
-        data = INT32_TO_JSVAL_IMPL(i);
-    }
-
-    JS_ALWAYS_INLINE
-    int32_t &getInt32Ref() {
-        JS_ASSERT(isInt32());
-        return data.s.payload.i32;
-    }
-
-    JS_ALWAYS_INLINE
-    void setDouble(double d) {
-        data = DOUBLE_TO_JSVAL_IMPL(d);
-    }
-
-    JS_ALWAYS_INLINE
-    double &getDoubleRef() {
-        JS_ASSERT(isDouble());
-        return data.asDouble;
-    }
-
-    JS_ALWAYS_INLINE
-    void setString(JSString *str) {
-        JS_ASSERT(!IsPoisonedPtr(str));
-        data = STRING_TO_JSVAL_IMPL(str);
-    }
-
-    JS_ALWAYS_INLINE
-    void setString(const JS::Anchor<JSString *> &str) {
-        setString(str.get());
-    }
-
-    JS_ALWAYS_INLINE
-    void setObject(JSObject &obj) {
-        JS_ASSERT(!IsPoisonedPtr(&obj));
-        data = OBJECT_TO_JSVAL_IMPL(&obj);
-    }
-
-    JS_ALWAYS_INLINE
-    void setBoolean(bool b) {
-        data = BOOLEAN_TO_JSVAL_IMPL(b);
-    }
-
-    JS_ALWAYS_INLINE
-    void setMagic(JSWhyMagic why) {
-        data = MAGIC_TO_JSVAL_IMPL(why);
-    }
-
-    JS_ALWAYS_INLINE
-    bool setNumber(uint32_t ui) {
-        if (ui > JSVAL_INT_MAX) {
-            setDouble((double)ui);
-            return false;
-        } else {
-            setInt32((int32_t)ui);
-            return true;
-        }
-    }
-
-    JS_ALWAYS_INLINE
-    bool setNumber(double d) {
-        int32_t i;
-        if (MOZ_DOUBLE_IS_INT32(d, &i)) {
-            setInt32(i);
-            return true;
-        } else {
-            setDouble(d);
-            return false;
-        }
-    }
-
-    JS_ALWAYS_INLINE
-    void setObjectOrNull(JSObject *arg) {
-        if (arg)
-            setObject(*arg);
-        else
-            setNull();
-    }
-
-    JS_ALWAYS_INLINE
-    void swap(Value &rhs) {
-        uint64_t tmp = rhs.data.asBits;
-        rhs.data.asBits = data.asBits;
-        data.asBits = tmp;
-    }
-
-    /*** Value type queries ***/
-
-    JS_ALWAYS_INLINE
-    bool isUndefined() const {
-        return JSVAL_IS_UNDEFINED_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    bool isNull() const {
-        return JSVAL_IS_NULL_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    bool isNullOrUndefined() const {
-        return isNull() || isUndefined();
-    }
-
-    JS_ALWAYS_INLINE
-    bool isInt32() const {
-        return JSVAL_IS_INT32_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    bool isInt32(int32_t i32) const {
-        return JSVAL_IS_SPECIFIC_INT32_IMPL(data, i32);
-    }
-
-    JS_ALWAYS_INLINE
-    bool isDouble() const {
-        return JSVAL_IS_DOUBLE_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    bool isNumber() const {
-        return JSVAL_IS_NUMBER_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    bool isString() const {
-        return JSVAL_IS_STRING_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    bool isObject() const {
-        return JSVAL_IS_OBJECT_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    bool isPrimitive() const {
-        return JSVAL_IS_PRIMITIVE_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    bool isObjectOrNull() const {
-        return JSVAL_IS_OBJECT_OR_NULL_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    bool isGCThing() const {
-        return JSVAL_IS_GCTHING_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    bool isBoolean() const {
-        return JSVAL_IS_BOOLEAN_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    bool isTrue() const {
-        return JSVAL_IS_SPECIFIC_BOOLEAN(data, true);
-    }
-
-    JS_ALWAYS_INLINE
-    bool isFalse() const {
-        return JSVAL_IS_SPECIFIC_BOOLEAN(data, false);
-    }
-
-    JS_ALWAYS_INLINE
-    bool isMagic() const {
-        return JSVAL_IS_MAGIC_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    bool isMagic(JSWhyMagic why) const {
-        JS_ASSERT_IF(isMagic(), data.s.payload.why == why);
-        return JSVAL_IS_MAGIC_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    bool isMarkable() const {
-        return JSVAL_IS_TRACEABLE_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    JSGCTraceKind gcKind() const {
-        JS_ASSERT(isMarkable());
-        return JSGCTraceKind(JSVAL_TRACE_KIND_IMPL(data));
-    }
-
-    JS_ALWAYS_INLINE
-    JSWhyMagic whyMagic() const {
-        JS_ASSERT(isMagic());
-        return data.s.payload.why;
-    }
-
-    /*** Comparison ***/
-
-    JS_ALWAYS_INLINE
-    bool operator==(const Value &rhs) const {
-        return data.asBits == rhs.data.asBits;
-    }
-
-    JS_ALWAYS_INLINE
-    bool operator!=(const Value &rhs) const {
-        return data.asBits != rhs.data.asBits;
-    }
-
-    friend inline bool SameType(const Value &lhs, const Value &rhs);
-
-    /*** Extract the value's typed payload ***/
-
-    JS_ALWAYS_INLINE
-    int32_t toInt32() const {
-        JS_ASSERT(isInt32());
-        return JSVAL_TO_INT32_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    double toDouble() const {
-        JS_ASSERT(isDouble());
-        return data.asDouble;
-    }
-
-    JS_ALWAYS_INLINE
-    double toNumber() const {
-        JS_ASSERT(isNumber());
-        return isDouble() ? toDouble() : double(toInt32());
-    }
-
-    JS_ALWAYS_INLINE
-    JSString *toString() const {
-        JS_ASSERT(isString());
-        return JSVAL_TO_STRING_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    JSObject &toObject() const {
-        JS_ASSERT(isObject());
-        return *JSVAL_TO_OBJECT_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    JSObject *toObjectOrNull() const {
-        JS_ASSERT(isObjectOrNull());
-        return JSVAL_TO_OBJECT_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    void *toGCThing() const {
-        JS_ASSERT(isGCThing());
-        return JSVAL_TO_GCTHING_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    bool toBoolean() const {
-        JS_ASSERT(isBoolean());
-        return JSVAL_TO_BOOLEAN_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    uint32_t payloadAsRawUint32() const {
-        JS_ASSERT(!isDouble());
-        return data.s.payload.u32;
-    }
-
-    JS_ALWAYS_INLINE
-    uint64_t asRawBits() const {
-        return data.asBits;
-    }
-
-    JS_ALWAYS_INLINE
-    JSValueType extractNonDoubleType() const {
-        return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data);
-    }
-
-    /*
-     * Private API
-     *
-     * Private setters/getters allow the caller to read/write arbitrary types
-     * that fit in the 64-bit payload. It is the caller's responsibility, after
-     * storing to a value with setPrivateX to read only using getPrivateX.
-     * Privates values are given a type type which ensures they are not marked.
-     */
-
-    JS_ALWAYS_INLINE
-    void setPrivate(void *ptr) {
-        data = PRIVATE_PTR_TO_JSVAL_IMPL(ptr);
-    }
-
-    JS_ALWAYS_INLINE
-    void *toPrivate() const {
-        JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(data));
-        return JSVAL_TO_PRIVATE_PTR_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    void setPrivateUint32(uint32_t ui) {
-        data = PRIVATE_UINT32_TO_JSVAL_IMPL(ui);
-    }
-
-    JS_ALWAYS_INLINE
-    uint32_t toPrivateUint32() const {
-        JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(data));
-        return JSVAL_TO_PRIVATE_UINT32_IMPL(data);
-    }
-
-    JS_ALWAYS_INLINE
-    uint32_t &getPrivateUint32Ref() {
-        JS_ASSERT(isDouble());
-        return data.s.payload.u32;
-    }
-
-    /*
-     * An unmarked value is just a void* cast as a Value. Thus, the Value is
-     * not safe for GC and must not be marked. This API avoids raw casts
-     * and the ensuing strict-aliasing warnings.
-     */
-
-    JS_ALWAYS_INLINE
-    void setUnmarkedPtr(void *ptr) {
-        data.asPtr = ptr;
-    }
-
-    JS_ALWAYS_INLINE
-    void *toUnmarkedPtr() const {
-        return data.asPtr;
-    }
-
-    const size_t *payloadWord() const {
-#if JS_BITS_PER_WORD == 32
-        return &data.s.payload.word;
-#elif JS_BITS_PER_WORD == 64
-        return &data.asWord;
-#endif
-    }
-
-    const uintptr_t *payloadUIntPtr() const {
-#if JS_BITS_PER_WORD == 32
-        return &data.s.payload.uintptr;
-#elif JS_BITS_PER_WORD == 64
-        return &data.asUIntPtr;
-#endif
-    }
-
-#if !defined(_MSC_VER) && !defined(__sparc)
-  /* To make jsval binary compatible when linking across C and C++ with MSVC,
-   * JS::Value needs to be POD. Otherwise, jsval will be passed in memory
-   * in C++ but by value in C (bug 689101).
-   * Same issue for SPARC ABI. (bug 737344).
-   */
-  private:
-#endif
-
-    jsval_layout data;
-
-  private:
-    void staticAssertions() {
-        JS_STATIC_ASSERT(sizeof(JSValueType) == 1);
-        JS_STATIC_ASSERT(sizeof(JSValueTag) == 4);
-        JS_STATIC_ASSERT(sizeof(JSBool) == 4);
-        JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4);
-        JS_STATIC_ASSERT(sizeof(Value) == 8);
-    }
-
-    friend jsval_layout (::JSVAL_TO_IMPL)(Value);
-    friend Value (::IMPL_TO_JSVAL)(jsval_layout l);
-};
-
-inline bool
-IsPoisonedValue(const Value &v)
-{
-    if (v.isString())
-        return IsPoisonedPtr(v.toString());
-    if (v.isObject())
-        return IsPoisonedPtr(&v.toObject());
-    return false;
-}
-
-/************************************************************************/
-
-static JS_ALWAYS_INLINE Value
-NullValue()
-{
-    Value v;
-    v.setNull();
-    return v;
-}
-
-static JS_ALWAYS_INLINE Value
-UndefinedValue()
-{
-    Value v;
-    v.setUndefined();
-    return v;
-}
-
-static JS_ALWAYS_INLINE Value
-Int32Value(int32_t i32)
-{
-    Value v;
-    v.setInt32(i32);
-    return v;
-}
-
-static JS_ALWAYS_INLINE Value
-DoubleValue(double dbl)
-{
-    Value v;
-    v.setDouble(dbl);
-    return v;
-}
-
-static JS_ALWAYS_INLINE Value
-StringValue(JSString *str)
-{
-    Value v;
-    v.setString(str);
-    return v;
-}
-
-static JS_ALWAYS_INLINE Value
-BooleanValue(bool boo)
-{
-    Value v;
-    v.setBoolean(boo);
-    return v;
-}
-
-static JS_ALWAYS_INLINE Value
-ObjectValue(JSObject &obj)
-{
-    Value v;
-    v.setObject(obj);
-    return v;
-}
-
-static JS_ALWAYS_INLINE Value
-ObjectValueCrashOnTouch()
-{
-    Value v;
-    v.setObject(*reinterpret_cast<JSObject *>(0x42));
-    return v;
-}
-
-static JS_ALWAYS_INLINE Value
-MagicValue(JSWhyMagic why)
-{
-    Value v;
-    v.setMagic(why);
-    return v;
-}
-
-static JS_ALWAYS_INLINE Value
-NumberValue(float f)
-{
-    Value v;
-    v.setNumber(f);
-    return v;
-}
-
-static JS_ALWAYS_INLINE Value
-NumberValue(double dbl)
-{
-    Value v;
-    v.setNumber(dbl);
-    return v;
-}
-
-static JS_ALWAYS_INLINE Value
-NumberValue(int8_t i)
-{
-    return Int32Value(i);
-}
-
-static JS_ALWAYS_INLINE Value
-NumberValue(uint8_t i)
-{
-    return Int32Value(i);
-}
-
-static JS_ALWAYS_INLINE Value
-NumberValue(int16_t i)
-{
-    return Int32Value(i);
-}
-
-static JS_ALWAYS_INLINE Value
-NumberValue(uint16_t i)
-{
-    return Int32Value(i);
-}
-
-static JS_ALWAYS_INLINE Value
-NumberValue(int32_t i)
-{
-    return Int32Value(i);
-}
-
-static JS_ALWAYS_INLINE Value
-NumberValue(uint32_t i)
-{
-    Value v;
-    v.setNumber(i);
-    return v;
-}
-
-namespace detail {
-
-template <bool Signed>
-class MakeNumberValue
-{
-  public:
-    template<typename T>
-    static inline Value create(const T t)
-    {
-        Value v;
-        if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX)
-            v.setInt32(int32_t(t));
-        else
-            v.setDouble(double(t));
-        return v;
-    }
-};
-
-template <>
-class MakeNumberValue<false>
-{
-  public:
-    template<typename T>
-    static inline Value create(const T t)
-    {
-        Value v;
-        if (t <= JSVAL_INT_MAX)
-            v.setInt32(int32_t(t));
-        else
-            v.setDouble(double(t));
-        return v;
-    }
-};
-
-} /* namespace detail */
-
-template <typename T>
-static JS_ALWAYS_INLINE Value
-NumberValue(const T t)
-{
-    MOZ_ASSERT(T(double(t)) == t, "value creation would be lossy");
-    return detail::MakeNumberValue<std::numeric_limits<T>::is_signed>::create(t);
-}
-
-static JS_ALWAYS_INLINE Value
-ObjectOrNullValue(JSObject *obj)
-{
-    Value v;
-    v.setObjectOrNull(obj);
-    return v;
-}
-
-static JS_ALWAYS_INLINE Value
-PrivateValue(void *ptr)
-{
-    Value v;
-    v.setPrivate(ptr);
-    return v;
-}
-
-static JS_ALWAYS_INLINE Value
-PrivateUint32Value(uint32_t ui)
-{
-    Value v;
-    v.setPrivateUint32(ui);
-    return v;
-}
-
-JS_ALWAYS_INLINE bool
-SameType(const Value &lhs, const Value &rhs)
-{
-    return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data);
-}
-
-} /* namespace JS */
-
-/************************************************************************/
-
-namespace js {
-
-template <> struct RootMethods<const JS::Value>
-{
-    static JS::Value initial() { return UndefinedValue(); }
-    static ThingRootKind kind() { return THING_ROOT_VALUE; }
-    static bool poisoned(const JS::Value &v) { return IsPoisonedValue(v); }
-};
-
-template <> struct RootMethods<JS::Value>
-{
-    static JS::Value initial() { return UndefinedValue(); }
-    static ThingRootKind kind() { return THING_ROOT_VALUE; }
-    static bool poisoned(const JS::Value &v) { return IsPoisonedValue(v); }
-};
-
-template <class Outer> class MutableValueOperations;
-
-/*
- * A class designed for CRTP use in implementing the non-mutating parts of the
- * Value interface in Value-like classes.  Outer must be a class inheriting
- * ValueOperations<Outer> with a visible extract() method returning the
- * const Value* abstracted by Outer.
- */
-template <class Outer>
-class ValueOperations
-{
-    friend class MutableValueOperations<Outer>;
-    const JS::Value * value() const { return static_cast<const Outer*>(this)->extract(); }
-
-  public:
-    bool isUndefined() const { return value()->isUndefined(); }
-    bool isNull() const { return value()->isNull(); }
-    bool isBoolean() const { return value()->isBoolean(); }
-    bool isTrue() const { return value()->isTrue(); }
-    bool isFalse() const { return value()->isFalse(); }
-    bool isNumber() const { return value()->isNumber(); }
-    bool isInt32() const { return value()->isInt32(); }
-    bool isDouble() const { return value()->isDouble(); }
-    bool isString() const { return value()->isString(); }
-    bool isObject() const { return value()->isObject(); }
-    bool isMagic() const { return value()->isMagic(); }
-    bool isMagic(JSWhyMagic why) const { return value()->isMagic(why); }
-    bool isMarkable() const { return value()->isMarkable(); }
-    bool isPrimitive() const { return value()->isPrimitive(); }
-    bool isGCThing() const { return value()->isGCThing(); }
-
-    bool isNullOrUndefined() const { return value()->isNullOrUndefined(); }
-    bool isObjectOrNull() const { return value()->isObjectOrNull(); }
-
-    bool toBoolean() const { return value()->toBoolean(); }
-    double toNumber() const { return value()->toNumber(); }
-    int32_t toInt32() const { return value()->toInt32(); }
-    double toDouble() const { return value()->toDouble(); }
-    JSString *toString() const { return value()->toString(); }
-    JSObject &toObject() const { return value()->toObject(); }
-    JSObject *toObjectOrNull() const { return value()->toObjectOrNull(); }
-    void *toGCThing() const { return value()->toGCThing(); }
-
-    JSValueType extractNonDoubleType() const { return value()->extractNonDoubleType(); }
-
-#ifdef DEBUG
-    JSWhyMagic whyMagic() const { return value()->whyMagic(); }
-#endif
-};
-
-/*
- * A class designed for CRTP use in implementing the mutating parts of the
- * Value interface in Value-like classes.  Outer must be a class inheriting
- * MutableValueOperations<Outer> with visible extractMutable() and extract()
- * methods returning the const Value* and Value* abstracted by Outer.
- */
-template <class Outer>
-class MutableValueOperations : public ValueOperations<Outer>
-{
-    JS::Value * value() { return static_cast<Outer*>(this)->extractMutable(); }
-
-  public:
-    void setNull() { value()->setNull(); }
-    void setUndefined() { value()->setUndefined(); }
-    void setInt32(int32_t i) { value()->setInt32(i); }
-    void setDouble(double d) { value()->setDouble(d); }
-    void setString(JSString *str) { value()->setString(str); }
-    void setString(const JS::Anchor<JSString *> &str) { value()->setString(str); }
-    void setObject(JSObject &obj) { value()->setObject(obj); }
-    void setBoolean(bool b) { value()->setBoolean(b); }
-    void setMagic(JSWhyMagic why) { value()->setMagic(why); }
-    bool setNumber(uint32_t ui) { return value()->setNumber(ui); }
-    bool setNumber(double d) { return value()->setNumber(d); }
-    void setObjectOrNull(JSObject *arg) { value()->setObjectOrNull(arg); }
-};
-
-/*
- * Augment the generic Handle<T> interface when T = Value with type-querying
- * and value-extracting operations.
- */
-template <>
-class HandleBase<JS::Value> : public ValueOperations<Handle<JS::Value> >
-{
-    friend class ValueOperations<Handle<JS::Value> >;
-    const JS::Value * extract() const {
-        return static_cast<const Handle<JS::Value>*>(this)->address();
-    }
-};
-
-/*
- * Augment the generic MutableHandle<T> interface when T = Value with
- * type-querying, value-extracting, and mutating operations.
- */
-template <>
-class MutableHandleBase<JS::Value> : public MutableValueOperations<MutableHandle<JS::Value> >
-{
-    friend class ValueOperations<MutableHandle<JS::Value> >;
-    const JS::Value * extract() const {
-        return static_cast<const MutableHandle<JS::Value>*>(this)->address();
-    }
-
-    friend class MutableValueOperations<MutableHandle<JS::Value> >;
-    JS::Value * extractMutable() {
-        return static_cast<MutableHandle<JS::Value>*>(this)->address();
-    }
-};
-
-/*
- * Augment the generic Rooted<T> interface when T = Value with type-querying,
- * value-extracting, and mutating operations.
- */
-template <>
-class RootedBase<JS::Value> : public MutableValueOperations<Rooted<JS::Value> >
-{
-    friend class ValueOperations<Rooted<JS::Value> >;
-    const JS::Value * extract() const {
-        return static_cast<const Rooted<JS::Value>*>(this)->address();
-    }
-
-    friend class MutableValueOperations<Rooted<JS::Value> >;
-    JS::Value * extractMutable() {
-        return static_cast<Rooted<JS::Value>*>(this)->address();
-    }
-};
-
-} /* namespace js */
-
-/************************************************************************/
-
-namespace JS {
-
 #if defined JS_THREADSAFE && defined DEBUG
 
 class JS_PUBLIC_API(AutoCheckRequestDepth)
 {
     JSContext *cx;
   public:
     AutoCheckRequestDepth(JSContext *cx);
     ~AutoCheckRequestDepth();
@@ -1545,51 +756,16 @@ CallNonGenericMethod(JSContext *cx, IsAc
 
     return detail::CallMethodIfWrapped(cx, Test, Impl, args);
 }
 
 }  /* namespace JS */
 
 /************************************************************************/
 
-/*
- * JS::Value and jsval are the same type; jsval is the old name, kept around
- * for backwards compatibility along with all the JSVAL_* operations below.
- * jsval_layout is an implementation detail and should not be used externally.
- */
-typedef JS::Value jsval;
-
-static JS_ALWAYS_INLINE jsval_layout
-JSVAL_TO_IMPL(jsval v)
-{
-    return v.data;
-}
-
-static JS_ALWAYS_INLINE jsval
-IMPL_TO_JSVAL(jsval_layout l)
-{
-    JS::Value v;
-    v.data = l;
-    return v;
-}
-
-#ifdef DEBUG
-struct JSValueAlignmentTester { char c; JS::Value v; };
-JS_STATIC_ASSERT(sizeof(JSValueAlignmentTester) == 16);
-#endif /* DEBUG */
-
-#ifdef DEBUG
-typedef struct { char c; jsval_layout l; } JSLayoutAlignmentTester;
-JS_STATIC_ASSERT(sizeof(JSLayoutAlignmentTester) == 16);
-#endif /* DEBUG */
-
-JS_STATIC_ASSERT(sizeof(jsval_layout) == sizeof(jsval));
-
-/************************************************************************/
-
 typedef JS::Handle<JSObject*> JSHandleObject;
 typedef JS::Handle<JSString*> JSHandleString;
 typedef JS::Handle<JS::Value> JSHandleValue;
 typedef JS::Handle<jsid> JSHandleId;
 
 typedef JS::MutableHandle<JSObject*>   JSMutableHandleObject;
 typedef JS::MutableHandle<JSFunction*> JSMutableHandleFunction;
 typedef JS::MutableHandle<JSScript*>   JSMutableHandleScript;
@@ -2016,202 +1192,28 @@ typedef JSBool (*WriteStructuredCloneOp)
  * To follow HTML5, the application must throw a DATA_CLONE_ERR DOMException
  * with error set to one of the JS_SCERR_* values.
  */
 typedef void (*StructuredCloneErrorOp)(JSContext *cx, uint32_t errorid);
 
 /************************************************************************/
 
 /*
- * Silence warning about returning JS::Value (aka jsval) from functions with C
- * linkage. For C JSAPI clients, jsval will be jsval_layout, which should be
- * ABI compatible.
- */
-#ifdef _MSC_VER
-# pragma warning(disable:4190)
-#endif
-
-/************************************************************************/
-
-/*
- * JS constants. For efficiency, prefer predicates (e.g., JSVAL_IS_NULL).
- * N.B. These constants are initialized at startup.
+ * JS constants. For efficiency, prefer predicates (e.g. v.isNull()) and
+ * constructing values from scratch (e.g. Int32Value(0)).  These constants are
+ * stored in memory and initialized at startup, so testing against them and
+ * using them requires memory loads and will be correspondingly slow.
  */
 extern JS_PUBLIC_DATA(const jsval) JSVAL_NULL;
 extern JS_PUBLIC_DATA(const jsval) JSVAL_ZERO;
 extern JS_PUBLIC_DATA(const jsval) JSVAL_ONE;
 extern JS_PUBLIC_DATA(const jsval) JSVAL_FALSE;
 extern JS_PUBLIC_DATA(const jsval) JSVAL_TRUE;
 extern JS_PUBLIC_DATA(const jsval) JSVAL_VOID;
 
-/************************************************************************/
-
-static JS_ALWAYS_INLINE JSBool
-JSVAL_IS_NULL(jsval v)
-{
-    return JSVAL_IS_NULL_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static JS_ALWAYS_INLINE JSBool
-JSVAL_IS_VOID(jsval v)
-{
-    return JSVAL_IS_UNDEFINED_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static JS_ALWAYS_INLINE JSBool
-JSVAL_IS_INT(jsval v)
-{
-    return JSVAL_IS_INT32_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static JS_ALWAYS_INLINE int32_t
-JSVAL_TO_INT(jsval v)
-{
-    JS_ASSERT(JSVAL_IS_INT(v));
-    return JSVAL_TO_INT32_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static JS_ALWAYS_INLINE jsval
-INT_TO_JSVAL(int32_t i)
-{
-    return IMPL_TO_JSVAL(INT32_TO_JSVAL_IMPL(i));
-}
-
-static JS_ALWAYS_INLINE JSBool
-JSVAL_IS_DOUBLE(jsval v)
-{
-    return JSVAL_IS_DOUBLE_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static JS_ALWAYS_INLINE double
-JSVAL_TO_DOUBLE(jsval v)
-{
-    jsval_layout l;
-    JS_ASSERT(JSVAL_IS_DOUBLE(v));
-    l = JSVAL_TO_IMPL(v);
-    return l.asDouble;
-}
-
-static JS_ALWAYS_INLINE jsval
-DOUBLE_TO_JSVAL(double d)
-{
-    /* This is a manually inlined version of:
-     *    d = JS_CANONICALIZE_NAN(d);
-     *    return IMPL_TO_JSVAL(DOUBLE_TO_JSVAL_IMPL(d));
-     * because GCC from XCode 3.1.4 miscompiles the above code. */
-    jsval_layout l;
-    if (JS_UNLIKELY(d != d)) {
-        l.asBits = 0x7FF8000000000000LL;
-    } else {
-        l.asDouble = d;
-    }
-    return IMPL_TO_JSVAL(l);
-}
-
-static JS_ALWAYS_INLINE jsval
-UINT_TO_JSVAL(uint32_t i)
-{
-    if (i <= JSVAL_INT_MAX)
-        return INT_TO_JSVAL((int32_t)i);
-    return DOUBLE_TO_JSVAL((double)i);
-}
-
-static JS_ALWAYS_INLINE JSBool
-JSVAL_IS_NUMBER(jsval v)
-{
-    return JSVAL_IS_NUMBER_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static JS_ALWAYS_INLINE JSBool
-JSVAL_IS_STRING(jsval v)
-{
-    return JSVAL_IS_STRING_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static JS_ALWAYS_INLINE JSString *
-JSVAL_TO_STRING(jsval v)
-{
-    JS_ASSERT(JSVAL_IS_STRING(v));
-    return JSVAL_TO_STRING_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static JS_ALWAYS_INLINE jsval
-STRING_TO_JSVAL(JSString *str)
-{
-    return IMPL_TO_JSVAL(STRING_TO_JSVAL_IMPL(str));
-}
-
-static JS_ALWAYS_INLINE JSObject *
-JSVAL_TO_OBJECT(jsval v)
-{
-    JS_ASSERT(JSVAL_IS_OBJECT_OR_NULL_IMPL(JSVAL_TO_IMPL(v)));
-    return JSVAL_TO_OBJECT_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static JS_ALWAYS_INLINE jsval
-OBJECT_TO_JSVAL(JSObject *obj)
-{
-    if (obj)
-        return IMPL_TO_JSVAL(OBJECT_TO_JSVAL_IMPL(obj));
-    return JSVAL_NULL;
-}
-
-static JS_ALWAYS_INLINE JSBool
-JSVAL_IS_BOOLEAN(jsval v)
-{
-    return JSVAL_IS_BOOLEAN_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static JS_ALWAYS_INLINE JSBool
-JSVAL_TO_BOOLEAN(jsval v)
-{
-    JS_ASSERT(JSVAL_IS_BOOLEAN(v));
-    return JSVAL_TO_BOOLEAN_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static JS_ALWAYS_INLINE jsval
-BOOLEAN_TO_JSVAL(JSBool b)
-{
-    return IMPL_TO_JSVAL(BOOLEAN_TO_JSVAL_IMPL(b));
-}
-
-static JS_ALWAYS_INLINE JSBool
-JSVAL_IS_PRIMITIVE(jsval v)
-{
-    return JSVAL_IS_PRIMITIVE_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static JS_ALWAYS_INLINE JSBool
-JSVAL_IS_GCTHING(jsval v)
-{
-    return JSVAL_IS_GCTHING_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static JS_ALWAYS_INLINE void *
-JSVAL_TO_GCTHING(jsval v)
-{
-    JS_ASSERT(JSVAL_IS_GCTHING(v));
-    return JSVAL_TO_GCTHING_IMPL(JSVAL_TO_IMPL(v));
-}
-
-/* To be GC-safe, privates are tagged as doubles. */
-
-static JS_ALWAYS_INLINE jsval
-PRIVATE_TO_JSVAL(void *ptr)
-{
-    return IMPL_TO_JSVAL(PRIVATE_PTR_TO_JSVAL_IMPL(ptr));
-}
-
-static JS_ALWAYS_INLINE void *
-JSVAL_TO_PRIVATE(jsval v)
-{
-    JS_ASSERT(JSVAL_IS_DOUBLE(v));
-    return JSVAL_TO_PRIVATE_PTR_IMPL(JSVAL_TO_IMPL(v));
-}
-
 static JS_ALWAYS_INLINE jsval
 JS_NumberValue(double d)
 {
     int32_t i;
     d = JS_CANONICALIZE_NAN(d);
     if (MOZ_DOUBLE_IS_INT32(d, &i))
         return INT_TO_JSVAL(i);
     return DOUBLE_TO_JSVAL(d);