Bug 552574 - de-mystify js_ValueToNumber API (r=igor)
authorLuke Wagner <lw@mozilla.com>
Wed, 07 Apr 2010 13:18:50 -0700
changeset 40828 2205abaf380c0593c8a805f3cbcbecb9e6e297bb
parent 40827 687d1e4c213ef0fc1d22e28deeb4a0643e807cbf
child 40829 23e71fa6bd6e058498c18f6f7a9a8875fc245115
push idunknown
push userunknown
push dateunknown
reviewersigor
bugs552574
milestone1.9.3a4pre
Bug 552574 - de-mystify js_ValueToNumber API (r=igor)
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsdate.cpp
js/src/jsdtoa.cpp
js/src/jsexn.cpp
js/src/jsfun.cpp
js/src/jsinterp.cpp
js/src/jsmath.cpp
js/src/jsnum.cpp
js/src/jsnum.h
js/src/jsops.cpp
js/src/jsstr.cpp
js/src/jstracer.cpp
js/src/jstypedarray.cpp
js/src/shell/js.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -434,64 +434,59 @@ JS_ValueToSource(JSContext *cx, jsval v)
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
 {
     CHECK_REQUEST(cx);
 
     AutoValueRooter tvr(cx, v);
-    *dp = js_ValueToNumber(cx, tvr.addr());
-    return !JSVAL_IS_NULL(tvr.value());
+    return ValueToNumber(cx, v, dp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DoubleIsInt32(jsdouble d, jsint *ip)
 {
     return JSDOUBLE_IS_INT(d, *ip);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
 {
     CHECK_REQUEST(cx);
 
     AutoValueRooter tvr(cx, v);
-    *ip = js_ValueToECMAInt32(cx, tvr.addr());
-    return !JSVAL_IS_NULL(tvr.value());
+    return ValueToECMAInt32(cx, v, (int32_t *)ip);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
 {
     CHECK_REQUEST(cx);
 
     AutoValueRooter tvr(cx, v);
-    *ip = js_ValueToECMAUint32(cx, tvr.addr());
-    return !JSVAL_IS_NULL(tvr.value());
+    return ValueToECMAUint32(cx, v, (uint32_t *)ip);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
 {
     CHECK_REQUEST(cx);
 
     AutoValueRooter tvr(cx, v);
-    *ip = js_ValueToInt32(cx, tvr.addr());
-    return !JSVAL_IS_NULL(tvr.value());
+    return ValueToInt32(cx, v, (int32_t *)ip);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
 {
     CHECK_REQUEST(cx);
 
     AutoValueRooter tvr(cx, v);
-    *ip = js_ValueToUint16(cx, tvr.addr());
-    return !JSVAL_IS_NULL(tvr.value());
+    return ValueToUint16(cx, v, (uint16_t *)ip);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
 {
     CHECK_REQUEST(cx);
     *bp = js_ValueToBoolean(v);
     return JS_TRUE;
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -191,28 +191,27 @@ js_IdIsIndex(jsval id, jsuint *indexp)
     }
     return JS_FALSE;
 }
 
 static jsuint
 ValueIsLength(JSContext *cx, jsval* vp)
 {
     jsint i;
-    jsdouble d;
     jsuint length;
 
     if (JSVAL_IS_INT(*vp)) {
         i = JSVAL_TO_INT(*vp);
         if (i < 0)
             goto error;
         return (jsuint) i;
     }
 
-    d = js_ValueToNumber(cx, vp);
-    if (JSVAL_IS_NULL(*vp))
+    jsdouble d;
+    if (!ValueToNumber(cx, *vp, &d))
         goto error;
 
     if (JSDOUBLE_IS_NaN(d))
         goto error;
     length = (jsuint) d;
     if (d != (jsdouble) length)
         goto error;
     return length;
@@ -241,18 +240,18 @@ js_GetLengthProperty(JSContext *cx, JSOb
     if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), tvr.addr()))
         return false;
 
     if (JSVAL_IS_INT(tvr.value())) {
         *lengthp = jsuint(jsint(JSVAL_TO_INT(tvr.value()))); /* jsuint cast does ToUint32 */
         return true;
     }
 
-    *lengthp = js_ValueToECMAUint32(cx, tvr.addr());
-    return !JSVAL_IS_NULL(tvr.value());
+    JS_STATIC_ASSERT(sizeof(jsuint) == sizeof(uint32_t));
+    return ValueToECMAUint32(cx, tvr.value(), (uint32_t *)lengthp);
 }
 
 static JSBool
 IndexToValue(JSContext *cx, jsdouble index, jsval *vp)
 {
     return js_NewWeaklyRootedNumber(cx, index, vp);
 }
 
@@ -2009,17 +2008,16 @@ typedef struct CompareArgs {
 
 static JS_REQUIRES_STACK JSBool
 sort_compare(void *arg, const void *a, const void *b, int *result)
 {
     jsval av = *(const jsval *)a, bv = *(const jsval *)b;
     CompareArgs *ca = (CompareArgs *) arg;
     JSContext *cx = ca->context;
     jsval *invokevp, *sp;
-    jsdouble cmp;
 
     /**
      * array_sort deals with holes and undefs on its own and they should not
      * come here.
      */
     JS_ASSERT(!JSVAL_IS_VOID(av));
     JS_ASSERT(!JSVAL_IS_VOID(bv));
 
@@ -2031,18 +2029,18 @@ sort_compare(void *arg, const void *a, c
     *sp++ = ca->fval;
     *sp++ = JSVAL_NULL;
     *sp++ = av;
     *sp++ = bv;
 
     if (!js_Invoke(cx, 2, invokevp, 0))
         return JS_FALSE;
 
-    cmp = js_ValueToNumber(cx, invokevp);
-    if (JSVAL_IS_NULL(*invokevp))
+    jsdouble cmp;
+    if (!ValueToNumber(cx, *invokevp, &cmp))
         return JS_FALSE;
 
     /* Clamp cmp to -1, 0, 1. */
     *result = 0;
     if (!JSDOUBLE_IS_NaN(cmp) && cmp != 0)
         *result = cmp > 0 ? 1 : -1;
 
     /*
@@ -2605,17 +2603,16 @@ array_unshift(JSContext *cx, uintN argc,
 }
 
 static JSBool
 array_splice(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval *argv;
     JSObject *obj;
     jsuint length, begin, end, count, delta, last;
-    jsdouble d;
     JSBool hole;
     JSObject *obj2;
 
     /*
      * Create a new array value to return.  Our ECMA v2 proposal specs
      * that splice always returns an array value, even when given no
      * arguments.  We think this is best because it eliminates the need
      * for callers to do an extra test to handle the empty splice case.
@@ -2629,18 +2626,18 @@ array_splice(JSContext *cx, uintN argc, 
     if (argc == 0)
         return JS_TRUE;
     argv = JS_ARGV(cx, vp);
     obj = JS_THIS_OBJECT(cx, vp);
     if (!obj || !js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
 
     /* Convert the first argument into a starting index. */
-    d = js_ValueToNumber(cx, argv);
-    if (JSVAL_IS_NULL(*argv))
+    jsdouble d;
+    if (!ValueToNumber(cx, *argv, &d))
         return JS_FALSE;
     d = js_DoubleToInteger(d);
     if (d < 0) {
         d += length;
         if (d < 0)
             d = 0;
     } else if (d > length) {
         d = length;
@@ -2650,18 +2647,17 @@ array_splice(JSContext *cx, uintN argc, 
     argv++;
 
     /* Convert the second argument from a count into a fencepost index. */
     delta = length - begin;
     if (argc == 0) {
         count = delta;
         end = length;
     } else {
-        d = js_ValueToNumber(cx, argv);
-        if (JSVAL_IS_NULL(*argv))
+        if (!ValueToNumber(cx, *argv, &d))
             return JS_FALSE;
         d = js_DoubleToInteger(d);
         if (d < 0)
             d = 0;
         else if (d > delta)
             d = delta;
         count = (jsuint)d;
         end = begin + count;
@@ -2854,44 +2850,42 @@ array_concat(JSContext *cx, uintN argc, 
 }
 
 static JSBool
 array_slice(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval *argv;
     JSObject *nobj, *obj;
     jsuint length, begin, end, slot;
-    jsdouble d;
     JSBool hole;
 
     argv = JS_ARGV(cx, vp);
 
     obj = JS_THIS_OBJECT(cx, vp);
     if (!obj || !js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
     begin = 0;
     end = length;
 
     if (argc > 0) {
-        d = js_ValueToNumber(cx, &argv[0]);
-        if (JSVAL_IS_NULL(argv[0]))
+        jsdouble d;
+        if (!ValueToNumber(cx, argv[0], &d))
             return JS_FALSE;
         d = js_DoubleToInteger(d);
         if (d < 0) {
             d += length;
             if (d < 0)
                 d = 0;
         } else if (d > length) {
             d = length;
         }
         begin = (jsuint)d;
 
         if (argc > 1) {
-            d = js_ValueToNumber(cx, &argv[1]);
-            if (JSVAL_IS_NULL(argv[1]))
+            if (!ValueToNumber(cx, argv[1], &d))
                 return JS_FALSE;
             d = js_DoubleToInteger(d);
             if (d < 0) {
                 d += length;
                 if (d < 0)
                     d = 0;
             } else if (d > length) {
                 d = length;
@@ -2951,18 +2945,17 @@ array_indexOfHelper(JSContext *cx, JSBoo
 
     if (argc <= 1) {
         i = isLast ? length - 1 : 0;
         tosearch = (argc != 0) ? vp[2] : JSVAL_VOID;
     } else {
         jsdouble start;
 
         tosearch = vp[2];
-        start = js_ValueToNumber(cx, &vp[3]);
-        if (JSVAL_IS_NULL(vp[3]))
+        if (!ValueToNumber(cx, vp[3], &start))
             return JS_FALSE;
         start = js_DoubleToInteger(start);
         if (start < 0) {
             start += length;
             if (start < 0) {
                 if (isLast)
                     goto not_found;
                 i = 0;
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -66,16 +66,18 @@
 #include "jsbuiltins.h"
 #include "jscntxt.h"
 #include "jsdate.h"
 #include "jsinterp.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsstr.h"
 
+using namespace js;
+
 /*
  * The JS 'Date' object is patterned after the Java 'Date' object.
  * Here is an script:
  *
  *    today = new Date();
  *
  *    print(today.toLocaleString());
  *
@@ -580,23 +582,22 @@ date_msecFromDate(jsdouble year, jsdoubl
 /* compute the time in msec (unclipped) from the given args */
 #define MAXARGS        7
 
 static JSBool
 date_msecFromArgs(JSContext *cx, uintN argc, jsval *argv, jsdouble *rval)
 {
     uintN loop;
     jsdouble array[MAXARGS];
-    jsdouble d;
     jsdouble msec_time;
 
     for (loop = 0; loop < MAXARGS; loop++) {
         if (loop < argc) {
-            d = js_ValueToNumber(cx, &argv[loop]);
-            if (JSVAL_IS_NULL(argv[loop]))
+            jsdouble d;
+            if (!ValueToNumber(cx, argv[loop], &d))
                 return JS_FALSE;
             /* return NaN if any arg is not finite */
             if (!JSDOUBLE_IS_FINITE(d)) {
                 *rval = js_NaN;
                 return JS_TRUE;
             }
             array[loop] = js_DoubleToInteger(d);
         } else {
@@ -1524,18 +1525,18 @@ date_setTime(JSContext *cx, uintN argc, 
     if (!JS_InstanceOf(cx, obj, &js_DateClass, vp + 2))
         return false;
 
     if (argc == 0) {
         SetDateToNaN(cx, obj, vp);
         return true;
     }
 
-    jsdouble result = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    jsdouble result;
+    if (!ValueToNumber(cx, vp[2], &result))
         return false;
 
     return SetUTCTime(cx, obj, TIMECLIP(result), vp);
 }
 
 static JSBool
 date_makeTime(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp)
 {
@@ -1571,18 +1572,17 @@ date_makeTime(JSContext *cx, uintN maxar
         return true;
     }
     if (argc > maxargs)
         argc = maxargs;  /* clamp argc */
     JS_ASSERT(argc <= 4);
 
     argv = vp + 2;
     for (i = 0; i < argc; i++) {
-        args[i] = js_ValueToNumber(cx, &argv[i]);
-        if (JSVAL_IS_NULL(argv[i]))
+        if (!ValueToNumber(cx, argv[i], &args[i]))
             return false;
         if (!JSDOUBLE_IS_FINITE(args[i])) {
             SetDateToNaN(cx, obj, vp);
             return true;
         }
         args[i] = js_DoubleToInteger(args[i]);
     }
 
@@ -1695,18 +1695,17 @@ date_makeDate(JSContext *cx, uintN maxar
         return true;
     }
     if (argc > maxargs)
         argc = maxargs;   /* clamp argc */
     JS_ASSERT(1 <= argc && argc <= 3);
 
     argv = vp + 2;
     for (i = 0; i < argc; i++) {
-        args[i] = js_ValueToNumber(cx, &argv[i]);
-        if (JSVAL_IS_NULL(argv[i]))
+        if (!ValueToNumber(cx, argv[i], &args[i]))
             return JS_FALSE;
         if (!JSDOUBLE_IS_FINITE(args[i])) {
             SetDateToNaN(cx, obj, vp);
             return true;
         }
         args[i] = js_DoubleToInteger(args[i]);
     }
 
@@ -1792,18 +1791,18 @@ date_setYear(JSContext *cx, uintN argc, 
         return false;
 
     if (argc == 0) {
         /* Call this only after GetUTCTime has verified that obj is Date. */
         SetDateToNaN(cx, obj, vp);
         return true;
     }
 
-    jsdouble year = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    jsdouble year;
+    if (!ValueToNumber(cx, vp[2], &year))
         return false;
     if (!JSDOUBLE_IS_FINITE(year)) {
         SetDateToNaN(cx, obj, vp);
         return true;
     }
     year = js_DoubleToInteger(year);
     if (year >= 0 && year <= 99)
         year += 1900;
@@ -2328,18 +2327,17 @@ js_Date(JSContext *cx, JSObject *obj, ui
 
     /* Date called as constructor. */
     jsdouble d;
     if (argc == 0) {
         d = NowAsMillis();
     } else if (argc == 1) {
         if (!JSVAL_IS_STRING(argv[0])) {
             /* the argument is a millisecond number */
-            d = js_ValueToNumber(cx, &argv[0]);
-            if (JSVAL_IS_NULL(argv[0]))
+            if (!ValueToNumber(cx, argv[0], &d))
                 return JS_FALSE;
             d = TIMECLIP(d);
         } else {
             /* the argument is a string; parse it. */
             JSString *str = js_ValueToString(cx, argv[0]);
             if (!str)
                 return JS_FALSE;
             argv[0] = STRING_TO_JSVAL(str);
--- a/js/src/jsdtoa.cpp
+++ b/js/src/jsdtoa.cpp
@@ -39,17 +39,17 @@
 
 /*
  * Portable double to alphanumeric string and back converters.
  */
 #include "jstypes.h"
 #include "jsstdint.h"
 #include "jsdtoa.h"
 #include "jsprf.h"
-#include "jsutil.h" /* Added by JSIFY */
+#include "jsapi.h"
 #include "jsprvtd.h"
 #include "jsnum.h"
 #include "jsbit.h"
 #include "jslibmath.h"
 #include "jscntxt.h"
 
 #ifdef IS_LITTLE_ENDIAN
 #define IEEE_8087
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -680,17 +680,16 @@ static const char *
 StringToFilename(JSContext *cx, JSString *str)
 {
     return js_GetStringBytes(cx, str);
 }
 
 static JSBool
 Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
-    uint32 lineno;
     JSString *message, *filename;
     JSStackFrame *fp;
 
     if (!JS_IsConstructing(cx)) {
         /*
          * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
          * called as functions, without operator new.  But as we do not give
          * each constructor a distinct JSClass, whose .name member is used by
@@ -740,19 +739,19 @@ Exception(JSContext *cx, JSObject *obj, 
             if (!filename)
                 return JS_FALSE;
         } else {
             filename = cx->runtime->emptyString;
         }
     }
 
     /* Set the 'lineNumber' property. */
+    uint32_t lineno;
     if (argc > 2) {
-        lineno = js_ValueToECMAUint32(cx, &argv[2]);
-        if (JSVAL_IS_NULL(argv[2]))
+        if (!ValueToECMAUint32(cx, argv[2], &lineno))
             return JS_FALSE;
     } else {
         if (!fp)
             fp = js_GetScriptedCaller(cx, NULL);
         lineno = (fp && fp->regs) ? js_FramePCToLineNumber(cx, fp) : 0;
     }
 
     return (obj->getClass() != &js_ErrorClass) ||
@@ -821,17 +820,16 @@ exn_toString(JSContext *cx, uintN argc, 
  * Return a string that may eval to something similar to the original object.
  */
 static JSBool
 exn_toSource(JSContext *cx, uintN argc, jsval *vp)
 {
     JSObject *obj;
     JSString *name, *message, *filename, *lineno_as_str, *result;
     jsval localroots[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL};
-    uint32 lineno;
     size_t lineno_length, name_length, message_length, filename_length, length;
     jschar *chars, *cp;
 
     obj = JS_THIS_OBJECT(cx, vp);
     if (!obj || !obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), vp))
         return false;
     name = js_ValueToString(cx, *vp);
     if (!name)
@@ -853,18 +851,18 @@ exn_toSource(JSContext *cx, uintN argc, 
         if (!JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) ||
             !(filename = js_ValueToSource(cx, localroots[1]))) {
             return false;
         }
         localroots[1] = STRING_TO_JSVAL(filename);
 
         if (!JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2]))
             return false;
-        lineno = js_ValueToECMAUint32 (cx, &localroots[2]);
-        if (JSVAL_IS_NULL(localroots[2]))
+        uint32_t lineno;
+        if (!ValueToECMAUint32(cx, localroots[2], &lineno))
             return false;
 
         if (lineno != 0) {
             lineno_as_str = js_ValueToString(cx, localroots[2]);
             if (!lineno_as_str)
                 return false;
             lineno_length = lineno_as_str->length();
         } else {
@@ -1238,17 +1236,16 @@ js_ReportUncaughtException(JSContext *cx
         roots[1] = STRING_TO_JSVAL(str);
         bytes = js_GetStringBytes(cx, str);
         if (!bytes)
             return false;
     }
 
     if (!reportp && exnObject && exnObject->getClass() == &js_ErrorClass) {
         const char *filename;
-        uint32 lineno;
 
         if (!JS_GetProperty(cx, exnObject, js_message_str, &roots[2]))
             return false;
         if (JSVAL_IS_STRING(roots[2])) {
             bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(roots[2]));
             if (!bytes)
                 return false;
         }
@@ -1259,18 +1256,18 @@ js_ReportUncaughtException(JSContext *cx
         if (!str)
             return false;
         filename = StringToFilename(cx, str);
         if (!filename)
             return false;
 
         if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]))
             return false;
-        lineno = js_ValueToECMAUint32 (cx, &roots[4]);
-        if (JSVAL_IS_NULL(roots[4]))
+        uint32_t lineno;
+        if (!ValueToECMAUint32 (cx, roots[4], &lineno))
             return false;
 
         reportp = &report;
         PodZero(&report);
         report.filename = filename;
         report.lineno = (uintN) lineno;
     }
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1891,17 +1891,17 @@ JS_FRIEND_DATA(JSClass) js_FunctionClass
     fun_convert,      fun_finalize,
     NULL,             NULL,
     NULL,             NULL,
     js_XDRFunctionObject, fun_hasInstance,
     JS_CLASS_TRACE(fun_trace), fun_reserveSlots
 };
 
 static JSBool
-fun_toStringHelper(JSContext *cx, uint32 indent, uintN argc, jsval *vp)
+fun_toStringHelper(JSContext *cx, uint32_t indent, uintN argc, jsval *vp)
 {
     jsval fval;
     JSObject *obj;
     JSFunction *fun;
     JSString *str;
 
     fval = JS_THIS(cx, vp);
     if (JSVAL_IS_NULL(fval))
@@ -1925,18 +1925,17 @@ fun_toStringHelper(JSContext *cx, uint32
                                  js_Function_str, js_toString_str,
                                  JS_GetTypeName(cx, JS_TypeOfValue(cx, fval)));
             return JS_FALSE;
         }
     }
 
     obj = JSVAL_TO_OBJECT(fval);
     if (argc != 0) {
-        indent = js_ValueToECMAUint32(cx, &vp[2]);
-        if (JSVAL_IS_NULL(vp[2]))
+        if (!ValueToECMAUint32(cx, vp[2], &indent))
             return JS_FALSE;
     }
 
     JS_ASSERT(JS_ObjectIsFunction(cx, obj));
     fun = GET_FUNCTION_PRIVATE(cx, obj);
     if (!fun)
         return JS_TRUE;
     str = JS_DecompileFunction(cx, fun, (uintN)indent);
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -1497,44 +1497,31 @@ js_UnwindScope(JSContext *cx, JSStackFra
 
     fp->regs->sp = StackBase(fp) + stackDepth;
     return normalUnwind;
 }
 
 JS_STATIC_INTERPRET JSBool
 js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, jsval *vp, jsval *vp2)
 {
-    jsval v;
-    jsdouble d;
-
-    v = *vp;
-    if (JSVAL_IS_DOUBLE(v)) {
-        d = *JSVAL_TO_DOUBLE(v);
-    } else if (JSVAL_IS_INT(v)) {
-        d = JSVAL_TO_INT(v);
-    } else {
-        d = js_ValueToNumber(cx, vp);
-        if (JSVAL_IS_NULL(*vp))
+    if (cs->format & JOF_POST) {
+        double d;
+        if (!ValueToNumberValue(cx, vp, &d))
             return JS_FALSE;
-        JS_ASSERT(JSVAL_IS_NUMBER(*vp) || *vp == JSVAL_TRUE);
-
-        /* Store the result of v conversion back in vp for post increments. */
-        if ((cs->format & JOF_POST) &&
-            *vp == JSVAL_TRUE
-            && !js_NewNumberInRootedValue(cx, d, vp)) {
-            return JS_FALSE;
-        }
+        (cs->format & JOF_INC) ? ++d : --d;
+        return js_NewNumberInRootedValue(cx, d, vp2);
     }
 
-    (cs->format & JOF_INC) ? d++ : d--;
+    double d;
+    if (!ValueToNumber(cx, *vp, &d))
+        return JS_FALSE;
+    (cs->format & JOF_INC) ? ++d : --d;
     if (!js_NewNumberInRootedValue(cx, d, vp2))
         return JS_FALSE;
-
-    if (!(cs->format & JOF_POST))
-        *vp = *vp2;
+    *vp = *vp2;
     return JS_TRUE;
 }
 
 jsval&
 js_GetUpvar(JSContext *cx, uintN level, uintN cookie)
 {
     level -= UPVAR_FRAME_SKIP(cookie);
     JS_ASSERT(level < JS_DISPLAY_SIZE);
@@ -1989,65 +1976,35 @@ namespace reprmeter {
             goto error;                                                       \
     JS_END_MACRO
 
 #define FETCH_NUMBER(cx, n, d)                                                \
     JS_BEGIN_MACRO                                                            \
         jsval v_;                                                             \
                                                                               \
         v_ = FETCH_OPND(n);                                                   \
-        VALUE_TO_NUMBER(cx, n, v_, d);                                        \
+        VALUE_TO_NUMBER(cx, v_, d);                                           \
     JS_END_MACRO
 
 #define FETCH_INT(cx, n, i)                                                   \
     JS_BEGIN_MACRO                                                            \
-        jsval v_;                                                             \
-                                                                              \
-        v_= FETCH_OPND(n);                                                    \
-        if (JSVAL_IS_INT(v_)) {                                               \
-            i = JSVAL_TO_INT(v_);                                             \
-        } else {                                                              \
-            i = js_ValueToECMAInt32(cx, &regs.sp[n]);                         \
-            if (JSVAL_IS_NULL(regs.sp[n]))                                    \
-                goto error;                                                   \
-        }                                                                     \
+        if (!ValueToECMAInt32(cx, regs.sp[n], &i))                            \
+            goto error;                                                       \
     JS_END_MACRO
 
 #define FETCH_UINT(cx, n, ui)                                                 \
     JS_BEGIN_MACRO                                                            \
-        jsval v_;                                                             \
-                                                                              \
-        v_= FETCH_OPND(n);                                                    \
-        if (JSVAL_IS_INT(v_)) {                                               \
-            ui = (uint32) JSVAL_TO_INT(v_);                                   \
-        } else {                                                              \
-            ui = js_ValueToECMAUint32(cx, &regs.sp[n]);                       \
-            if (JSVAL_IS_NULL(regs.sp[n]))                                    \
-                goto error;                                                   \
-        }                                                                     \
+        if (!ValueToECMAUint32(cx, regs.sp[n], &ui))                          \
+            goto error;                                                       \
     JS_END_MACRO
 
-/*
- * Optimized conversion macros that test for the desired type in v before
- * homing sp and calling a conversion function.
- */
-#define VALUE_TO_NUMBER(cx, n, v, d)                                          \
+#define VALUE_TO_NUMBER(cx, v, d)                                             \
     JS_BEGIN_MACRO                                                            \
-        JS_ASSERT(v == regs.sp[n]);                                           \
-        if (JSVAL_IS_INT(v)) {                                                \
-            d = (jsdouble)JSVAL_TO_INT(v);                                    \
-        } else if (JSVAL_IS_DOUBLE(v)) {                                      \
-            d = *JSVAL_TO_DOUBLE(v);                                          \
-        } else {                                                              \
-            d = js_ValueToNumber(cx, &regs.sp[n]);                            \
-            if (JSVAL_IS_NULL(regs.sp[n]))                                    \
-                goto error;                                                   \
-            JS_ASSERT(JSVAL_IS_NUMBER(regs.sp[n]) ||                          \
-                      regs.sp[n] == JSVAL_TRUE);                              \
-        }                                                                     \
+        if (!ValueToNumber(cx, v, &d))                                        \
+            goto error;                                                       \
     JS_END_MACRO
 
 #define POP_BOOLEAN(cx, v, b)                                                 \
     JS_BEGIN_MACRO                                                            \
         v = FETCH_OPND(-1);                                                   \
         if (v == JSVAL_NULL) {                                                \
             b = JS_FALSE;                                                     \
         } else if (JSVAL_IS_BOOLEAN(v)) {                                     \
@@ -2311,17 +2268,17 @@ js_Interpret(JSContext *cx)
     JSAtom *atom;
     uintN argc, attrs, flags;
     uint32 slot;
     jsval *vp, lval, rval, ltmp, rtmp;
     jsid id;
     JSProperty *prop;
     JSScopeProperty *sprop;
     JSString *str, *str2;
-    jsint i, j;
+    int32_t i, j;
     jsdouble d, d2;
     JSClass *clasp;
     JSFunction *fun;
     JSType type;
     jsint low, high, off, npairs;
     JSBool match;
 #if JS_HAS_GETTER_SETTER
     JSPropertyOp getter, setter;
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -51,16 +51,18 @@
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jslock.h"
 #include "jsmath.h"
 #include "jsnum.h"
 #include "jslibmath.h"
 #include "jsobj.h"
 
+using namespace js;
+
 #ifndef M_E
 #define M_E             2.7182818284590452354
 #endif
 #ifndef M_LOG2E
 #define M_LOG2E         1.4426950408889634074
 #endif
 #ifndef M_LOG10E
 #define M_LOG10E        0.43429448190325182765
@@ -105,34 +107,32 @@ static JSBool
 math_abs(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
-    x = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
     z = fabs(x);
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
 static JSBool
 math_acos(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
-    x = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
 #if defined(SOLARIS) && defined(__GNUC__)
     if (x < -1 || 1 < x) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
 #endif
     z = acos(x);
@@ -143,18 +143,17 @@ static JSBool
 math_asin(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
-    x = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
 #if defined(SOLARIS) && defined(__GNUC__)
     if (x < -1 || 1 < x) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
 #endif
     z = asin(x);
@@ -165,18 +164,17 @@ static JSBool
 math_atan(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
-    x = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
     z = atan(x);
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
 static inline jsdouble JS_FASTCALL
 math_atan2_kernel(jsdouble x, jsdouble y)
 {
@@ -211,21 +209,19 @@ static JSBool
 math_atan2(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, y;
 
     if (argc <= 1) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
-    x = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
-    y = js_ValueToNumber(cx, &vp[3]);
-    if (JSVAL_IS_NULL(vp[3]))
+    if (!ValueToNumber(cx, vp[3], &y))
         return JS_FALSE;
     return js_NewNumberInRootedValue(cx, math_atan2_kernel (x, y), vp);
 }
 
 static inline jsdouble JS_FASTCALL
 math_ceil_kernel(jsdouble x)
 {
 #ifdef __APPLE__
@@ -239,50 +235,47 @@ JSBool
 js_math_ceil(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
-    x = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
     z = math_ceil_kernel(x);
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
 static JSBool
 math_cos(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
-    x = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
     z = cos(x);
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
 static JSBool
 math_exp(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
-    x = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
 #ifdef _WIN32
     if (!JSDOUBLE_IS_NaN(x)) {
         if (x == js_PositiveInfinity) {
             *vp = cx->runtime->positiveInfinityValue;
             return JS_TRUE;
         }
         if (x == js_NegativeInfinity) {
@@ -299,34 +292,32 @@ JSBool
 js_math_floor(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
-    x = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
     z = floor(x);
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
 static JSBool
 math_log(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
-    x = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
 #if defined(SOLARIS) && defined(__GNUC__)
     if (x < 0) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
 #endif
     z = log(x);
@@ -341,18 +332,17 @@ js_math_max(JSContext *cx, uintN argc, j
     uintN i;
 
     if (argc == 0) {
         *vp = cx->runtime->negativeInfinityValue;
         return JS_TRUE;
     }
     argv = vp + 2;
     for (i = 0; i < argc; i++) {
-        x = js_ValueToNumber(cx, &argv[i]);
-        if (JSVAL_IS_NULL(argv[i]))
+        if (!ValueToNumber(cx, argv[i], &x))
             return JS_FALSE;
         if (JSDOUBLE_IS_NaN(x)) {
             *vp = cx->runtime->NaNValue;
             return JS_TRUE;
         }
         if (x == 0 && x == z) {
             if (js_copysign(1.0, z) == -1)
                 z = x;
@@ -371,18 +361,17 @@ js_math_min(JSContext *cx, uintN argc, j
     uintN i;
 
     if (argc == 0) {
         *vp = cx->runtime->positiveInfinityValue;
         return JS_TRUE;
     }
     argv = vp + 2;
     for (i = 0; i < argc; i++) {
-        x = js_ValueToNumber(cx, &argv[i]);
-        if (JSVAL_IS_NULL(argv[i]))
+        if (!ValueToNumber(cx, argv[i], &x))
             return JS_FALSE;
         if (JSDOUBLE_IS_NaN(x)) {
             *vp = cx->runtime->NaNValue;
             return JS_TRUE;
         }
         if (x == 0 && x == z) {
             if (js_copysign(1.0, x) == -1)
                 z = x;
@@ -397,21 +386,19 @@ static JSBool
 math_pow(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, y, z;
 
     if (argc <= 1) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
-    x = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
-    y = js_ValueToNumber(cx, &vp[3]);
-    if (JSVAL_IS_NULL(vp[3]))
+    if (!ValueToNumber(cx, vp[3], &y))
         return JS_FALSE;
     /*
      * Because C99 and ECMA specify different behavior for pow(),
      * we need to wrap the libm call to make it ECMA compliant.
      */
     if (!JSDOUBLE_IS_FINITE(y) && (x == 1.0 || x == -1.0)) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
@@ -496,66 +483,62 @@ JSBool
 js_math_round(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
-    x = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
     z = js_copysign(floor(x + 0.5), x);
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
 static JSBool
 math_sin(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
-    x = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
     z = sin(x);
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
 static JSBool
 math_sqrt(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
-    x = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
     z = sqrt(x);
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
 static JSBool
 math_tan(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
-    x = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
     z = tan(x);
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
 #if JS_HAS_TOSOURCE
 static JSBool
 math_toSource(JSContext *cx, uintN argc, jsval *vp)
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -100,40 +100,36 @@ JS_STATIC_ASSERT(ptrdiff_t(PTRDIFF_MAX) 
 JS_STATIC_ASSERT(ptrdiff_t(PTRDIFF_MIN) == PTRDIFF_MIN);
 JS_STATIC_ASSERT(uintptr_t(PTRDIFF_MAX) + uintptr_t(1) == uintptr_t(PTRDIFF_MIN));
 
 #endif /* JS_HAVE_STDINT_H */
 
 static JSBool
 num_isNaN(JSContext *cx, uintN argc, jsval *vp)
 {
-    jsdouble x;
-
     if (argc == 0) {
         *vp = JSVAL_TRUE;
         return JS_TRUE;
     }
-    x = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
-        return JS_FALSE;
+    jsdouble x;
+    if (!ValueToNumber(cx, vp[2], &x))
+        return false;
     *vp = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_NaN(x));
     return JS_TRUE;
 }
 
 static JSBool
 num_isFinite(JSContext *cx, uintN argc, jsval *vp)
 {
-    jsdouble x;
-
     if (argc == 0) {
         *vp = JSVAL_FALSE;
         return JS_TRUE;
     }
-    x = js_ValueToNumber(cx, &vp[2]);
-    if (JSVAL_IS_NULL(vp[2]))
+    jsdouble x;
+    if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
     *vp = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_FINITE(x));
     return JS_TRUE;
 }
 
 static JSBool
 num_parseFloat(JSContext *cx, uintN argc, jsval *vp)
 {
@@ -173,28 +169,27 @@ ParseFloat(JSContext* cx, JSString* str)
     return d;
 }
 #endif
 
 /* See ECMA 15.1.2.2. */
 static JSBool
 num_parseInt(JSContext *cx, uintN argc, jsval *vp)
 {
-    jsint radix;
     JSString *str;
     jsdouble d;
     const jschar *bp, *end, *ep;
 
     if (argc == 0) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
+    int32_t radix;
     if (argc > 1) {
-        radix = js_ValueToECMAInt32(cx, &vp[3]);
-        if (JSVAL_IS_NULL(vp[3]))
+        if (!ValueToECMAInt32(cx, vp[3], &radix))
             return JS_FALSE;
     } else {
         radix = 0;
     }
     if (radix != 0 && (radix < 2 || radix > 36)) {
         *vp = cx->runtime->NaNValue;
         return JS_TRUE;
     }
@@ -278,30 +273,20 @@ JSClass js_NumberClass = {
     JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   NULL,
     JSCLASS_NO_OPTIONAL_MEMBERS
 };
 
 static JSBool
 Number(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
     jsval v;
-    jsdouble d;
-
     if (argc != 0) {
-        d = js_ValueToNumber(cx, &argv[0]);
-        v = argv[0];
-        if (JSVAL_IS_NULL(v))
+        if (!ValueToNumberValue(cx, &argv[0]))
             return JS_FALSE;
-        if (v != JSVAL_TRUE) {
-            JS_ASSERT(JSVAL_IS_INT(v) || JSVAL_IS_DOUBLE(v));
-        } else {
-            if (!js_NewNumberInRootedValue(cx, d, &argv[0]))
-                return JS_FALSE;
-            v = argv[0];
-        }
+        v = argv[0];
     } else {
         v = JSVAL_ZERO;
     }
     if (!JS_IsConstructing(cx))
         *rval = v;
     else
         obj->fslots[JSSLOT_PRIMITIVE_THIS] = v;
     return true;
@@ -386,28 +371,27 @@ IntToCString(jsint i, jsint base, char *
 static JSString * JS_FASTCALL
 js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base);
 
 static JSBool
 num_toString(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval v;
     jsdouble d;
-    jsint base;
     JSString *str;
 
     if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v))
         return JS_FALSE;
     JS_ASSERT(JSVAL_IS_NUMBER(v));
     d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
-    base = 10;
+    int32_t base = 10;
     if (argc != 0 && !JSVAL_IS_VOID(vp[2])) {
-        base = js_ValueToECMAInt32(cx, &vp[2]);
-        if (JSVAL_IS_NULL(vp[2]))
+        if (!ValueToECMAInt32(cx, vp[2], &base))
             return JS_FALSE;
+
         if (base < 2 || base > 36) {
             char numBuf[12];
             char *numStr = IntToCString(base, 10, numBuf, sizeof numBuf);
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX,
                                  numStr);
             return JS_FALSE;
         }
     }
@@ -566,18 +550,17 @@ num_to(JSContext *cx, JSDToStrMode zeroA
         return JS_FALSE;
     JS_ASSERT(JSVAL_IS_NUMBER(v));
     d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
 
     if (argc == 0) {
         precision = 0.0;
         oneArgMode = zeroArgMode;
     } else {
-        precision = js_ValueToNumber(cx, &vp[2]);
-        if (JSVAL_IS_NULL(vp[2]))
+        if (!ValueToNumber(cx, vp[2], &precision))
             return JS_FALSE;
         precision = js_DoubleToInteger(precision);
         if (precision < precisionMin || precision > precisionMax) {
             numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, buf, sizeof buf,
                                DTOSTR_STANDARD, 0, precision);
             if (!numStr)
                 JS_ReportOutOfMemory(cx);
             else
@@ -946,130 +929,129 @@ js_NumberValueToCharBuffer(JSContext *cx
     size_t oldcstrlen = cstrlen;
     JSBool ok =
 #endif
         js_InflateStringToBuffer(cx, cstr, cstrlen, appendBegin, &cstrlen);
     JS_ASSERT(ok && cstrlen == oldcstrlen);
     return JS_TRUE;
 }
 
-jsdouble
-js_ValueToNumber(JSContext *cx, jsval *vp)
-{
-    jsval v;
-    JSString *str;
-    jsdouble d;
-    JSObject *obj;
+namespace js {
 
-    v = *vp;
+jsval
+ValueToNumberSlow(JSContext *cx, jsval v, double *out)
+{
+    JS_ASSERT(!JSVAL_IS_INT(v) && !JSVAL_IS_DOUBLE(v));
+    goto skip_int_double;
     for (;;) {
-        if (JSVAL_IS_INT(v))
-            return (jsdouble) JSVAL_TO_INT(v);
-        if (JSVAL_IS_DOUBLE(v))
-            return *JSVAL_TO_DOUBLE(v);
+        if (JSVAL_IS_INT(v)) {
+            *out = (double)JSVAL_TO_INT(v);
+            return v;
+        }
+        if (JSVAL_IS_DOUBLE(v)) {
+            *out = *JSVAL_TO_DOUBLE(v);
+            return v;
+        }
+      skip_int_double:
         if (JSVAL_IS_STRING(v)) {
-            str = JSVAL_TO_STRING(v);
+            JSString *str = JSVAL_TO_STRING(v);
 
-            d = StringToNumberType<jsdouble>(cx, str);
+            jsdouble d = StringToNumberType<jsdouble>(cx, str);
             if (JSDOUBLE_IS_NaN(d))
                 break;
 
             /*
              * JSVAL_TRUE indicates that double jsval was never constructed
              * for the result.
              */
-            *vp = JSVAL_TRUE;
-            return d;
+            *out = d;
+            return JSVAL_TRUE;
         }
         if (JSVAL_IS_BOOLEAN(v)) {
             if (JSVAL_TO_BOOLEAN(v)) {
-                *vp = JSVAL_ONE;
-                return 1.0;
+                *out = 1.0;
+                return JSVAL_ONE;
             }
-            *vp = JSVAL_ZERO;
-            return 0.0;
+            *out = 0.0;
+            return JSVAL_ZERO;
         }
         if (JSVAL_IS_NULL(v)) {
-            *vp = JSVAL_ZERO;
-            return 0.0;
+            *out = 0.0;
+            return JSVAL_ZERO;
         }
         if (JSVAL_IS_VOID(v))
             break;
 
         JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
-        obj = JSVAL_TO_OBJECT(v);
+        JSObject *obj = JSVAL_TO_OBJECT(v);
 
         /*
-         * vp roots obj so we cannot use it as an extra root for
-         * obj->defaultValue result when calling the hook.
+         * defaultValue has a special contract whereby the callee may not
+         * assume vp is rooted. Since obj is rooted elsewhere and no GC may
+         * occur after calling defaultValue, we can just use v.
          */
-        AutoValueRooter gcr(cx, v);
-        if (!obj->defaultValue(cx, JSTYPE_NUMBER, gcr.addr()))
-            obj = NULL;
-        else
-            v = *vp = gcr.value();
-        if (!obj) {
-            *vp = JSVAL_NULL;
-            return 0.0;
-        }
+        if (!obj->defaultValue(cx, JSTYPE_NUMBER, &v))
+            return JSVAL_NULL;
         if (!JSVAL_IS_PRIMITIVE(v))
             break;
     }
 
-    *vp = cx->runtime->NaNValue;
-    return js_NaN;
+    *out = js_NaN;
+    return cx->runtime->NaNValue;
 }
 
-int32
-js_ValueToECMAInt32(JSContext *cx, jsval *vp)
+bool
+ValueToNumberValueSlow(JSContext *cx, jsval *vp, double *out)
 {
-    jsval v;
-    jsdouble d;
+    jsval v = *vp = ValueToNumberSlow(cx, *vp, out);
+    return !JSVAL_IS_NULL(v) &&
+           (v != JSVAL_TRUE || js_NewNumberInRootedValue(cx, *out, vp));
+}
 
-    v = *vp;
-    if (JSVAL_IS_INT(v))
-        return JSVAL_TO_INT(v);
-    if (JSVAL_IS_DOUBLE(v)) {
-        d = *JSVAL_TO_DOUBLE(v);
-        *vp = JSVAL_TRUE;
-    } else {
-        d = js_ValueToNumber(cx, vp);
-        if (JSVAL_IS_NULL(*vp))
-            return 0;
-        *vp = JSVAL_TRUE;
-    }
-    return js_DoubleToECMAInt32(d);
+bool
+ValueToNumberValueSlow(JSContext *cx, jsval *vp)
+{
+    double d;
+    jsval v = *vp = ValueToNumberSlow(cx, *vp, &d);
+    return !JSVAL_IS_NULL(v) &&
+           (v != JSVAL_TRUE || js_NewNumberInRootedValue(cx, d, vp));
 }
 
-uint32
-js_ValueToECMAUint32(JSContext *cx, jsval *vp)
+bool
+ValueToECMAInt32Slow(JSContext *cx, jsval v, int32_t *out)
 {
-    jsval v;
-    jsint i;
+    JS_ASSERT(!JSVAL_IS_INT(v));
     jsdouble d;
-
-    v = *vp;
-    if (JSVAL_IS_INT(v)) {
-        i = JSVAL_TO_INT(v);
-        if (i < 0)
-            *vp = JSVAL_TRUE;
-        return (uint32) i;
-    }
     if (JSVAL_IS_DOUBLE(v)) {
         d = *JSVAL_TO_DOUBLE(v);
-        *vp = JSVAL_TRUE;
     } else {
-        d = js_ValueToNumber(cx, vp);
-        if (JSVAL_IS_NULL(*vp))
-            return 0;
-        *vp = JSVAL_TRUE;
+        if (JSVAL_IS_NULL(ValueToNumberSlow(cx, v, &d)))
+            return false;
     }
-    return js_DoubleToECMAUint32(d);
+    *out = js_DoubleToECMAInt32(d);
+    return true;
 }
 
+bool
+ValueToECMAUint32Slow(JSContext *cx, jsval v, uint32_t *out)
+{
+    JS_ASSERT(!JSVAL_IS_INT(v));
+    jsdouble d;
+    if (JSVAL_IS_DOUBLE(v)) {
+        d = *JSVAL_TO_DOUBLE(v);
+    } else {
+        if (JSVAL_IS_NULL(ValueToNumberSlow(cx, v, &d)))
+            return false;
+    }
+    *out = js_DoubleToECMAUint32(d);
+    return true;
+}
+
+}  /* namespace js */
+
 uint32
 js_DoubleToECMAUint32(jsdouble d)
 {
     int32 i;
     JSBool neg;
     jsdouble two32;
 
     if (!JSDOUBLE_IS_FINITE(d))
@@ -1089,74 +1071,85 @@ js_DoubleToECMAUint32(jsdouble d)
     d = neg ? -d : d;
 
     two32 = 4294967296.0;
     d = fmod(d, two32);
 
     return (uint32) (d >= 0 ? d : d + two32);
 }
 
-int32
-js_ValueToInt32(JSContext *cx, jsval *vp)
-{
-    jsval v;
-    jsdouble d;
+namespace js {
 
-    v = *vp;
-    if (JSVAL_IS_INT(v))
-        return JSVAL_TO_INT(v);
-    d = js_ValueToNumber(cx, vp);
-    if (JSVAL_IS_NULL(*vp))
-        return 0;
-    if (JSVAL_IS_INT(*vp))
-        return JSVAL_TO_INT(*vp);
+bool
+ValueToInt32Slow(JSContext *cx, jsval v, int32_t *out)
+{
+    JS_ASSERT(!JSVAL_IS_INT(v));
+    jsdouble d;
+    if (JSVAL_IS_DOUBLE(v)) {
+        d = *JSVAL_TO_DOUBLE(v);
+    } else {
+        jsval v2 = ValueToNumberSlow(cx, v, &d);
+        if (JSVAL_IS_NULL(v2))
+            return false;
+        if (JSVAL_IS_INT(v2)) {
+            *out = JSVAL_TO_INT(v2);
+            return true;
+        }
+    }
 
-    *vp = JSVAL_TRUE;
     if (JSDOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) {
         js_ReportValueError(cx, JSMSG_CANT_CONVERT,
                             JSDVG_SEARCH_STACK, v, NULL);
-        *vp = JSVAL_NULL;
-        return 0;
+        return false;
     }
-    return (int32) floor(d + 0.5);  /* Round to nearest */
+    *out = (int32) floor(d + 0.5);  /* Round to nearest */
+    return true;
 }
 
-uint16
-js_ValueToUint16(JSContext *cx, jsval *vp)
+bool
+ValueToUint16Slow(JSContext *cx, jsval v, uint16_t *out)
 {
+    JS_ASSERT(!JSVAL_IS_INT(v));
     jsdouble d;
-    uint16 u;
-    jsuint m;
-    JSBool neg;
-
-    d = js_ValueToNumber(cx, vp);
-    if (JSVAL_IS_NULL(*vp))
-        return 0;
-
-    if (JSVAL_IS_INT(*vp)) {
-        u = (uint16) JSVAL_TO_INT(*vp);
-    } else if (d == 0 || !JSDOUBLE_IS_FINITE(d)) {
-        u = (uint16) 0;
+    if (JSVAL_IS_DOUBLE(v)) {
+        d = *JSVAL_TO_DOUBLE(v);
     } else {
-        u = (uint16) d;
-        if ((jsdouble) u != d) {
-            neg = (d < 0);
-            d = floor(neg ? -d : d);
-            d = neg ? -d : d;
-            m = JS_BIT(16);
-            d = fmod(d, (double) m);
-            if (d < 0)
-                d += m;
-            u = (uint16) d;
+        jsval v2 = ValueToNumberSlow(cx, v, &d);
+        if (JSVAL_IS_NULL(v2))
+            return false;
+        if (JSVAL_IS_INT(v2)) {
+            *out = (uint16_t) JSVAL_TO_INT(v2);
+            return true;
         }
     }
-    *vp = INT_TO_JSVAL(u);
-    return u;
+
+    if (d == 0 || !JSDOUBLE_IS_FINITE(d)) {
+        *out = 0;
+        return true;
+    }
+
+    uint16 u = (uint16) d;
+    if ((jsdouble)u == d) {
+        *out = u;
+        return true;
+    }
+
+    bool neg = (d < 0);
+    d = floor(neg ? -d : d);
+    d = neg ? -d : d;
+    jsuint m = JS_BIT(16);
+    d = fmod(d, (double) m);
+    if (d < 0)
+        d += m;
+    *out = (uint16_t) d;
+    return true;
 }
 
+}  /* namespace js */
+
 JSBool
 js_strtod(JSContext *cx, const jschar *s, const jschar *send,
           const jschar **ep, jsdouble *dp)
 {
     const jschar *s1;
     size_t length, i;
     char cbuf[32];
     char *cstr, *istr, *estr;
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -43,29 +43,28 @@
 #include <math.h>
 #if defined(XP_WIN) || defined(XP_OS2)
 #include <float.h>
 #endif
 #ifdef SOLARIS
 #include <ieeefp.h>
 #endif
 
+#include "jsstdint.h"
 #include "jsstr.h"
 
 /*
  * JS number (IEEE double) interface.
  *
  * JS numbers are optimistically stored in the top 31 bits of 32-bit integers,
  * but floating point literals, results that overflow 31 bits, and division and
  * modulus operands and results require a 64-bit IEEE double.  These are GC'ed
  * and pointed to by 32-bit jsvals on the stack and in object properties.
  */
 
-JS_BEGIN_EXTERN_C
-
 /*
  * The ARM architecture supports two floating point models: VFP and FPA. When
  * targetting FPA, doubles are mixed-endian on little endian ARMs (meaning that
  * the high and low words are in big endian order).
  */
 #if defined(__arm) || defined(__arm32__) || defined(__arm26__) || defined(__arm__)
 #if !defined(__VFP_FP__)
 #define FPU_IS_ARM_FPA
@@ -182,17 +181,17 @@ extern void
 js_TraceRuntimeNumberState(JSTracer *trc);
 
 extern void
 js_FinishRuntimeNumberState(JSContext *cx);
 
 /* Initialize the Number class, returning its prototype object. */
 extern JSClass js_NumberClass;
 
-extern JSObject *
+extern "C" JSObject *
 js_InitNumberClass(JSContext *cx, JSObject *obj);
 
 /*
  * String constants for global function names, used in jsapi.c and jsnum.c.
  */
 extern const char js_Infinity_str[];
 extern const char js_NaN_str[];
 extern const char js_isNaN_str[];
@@ -219,39 +218,139 @@ js_NumberToString(JSContext *cx, jsdoubl
 
 /*
  * Convert an integer or double (contained in the given jsval) to a string and
  * append to the given buffer.
  */
 extern JSBool JS_FASTCALL
 js_NumberValueToCharBuffer(JSContext *cx, jsval v, JSCharBuffer &cb);
 
+namespace js {
+
 /*
- * Convert a value to a number. On exit JSVAL_IS_NULL(*vp) iff there was an
- * error. If on exit JSVAL_IS_NUMBER(*vp), then *vp holds the jsval that
- * matches the result. Otherwise *vp is JSVAL_TRUE indicating that the jsval
- * for result has to be created explicitly using, for example, the
- * js_NewNumberInRootedValue function.
+ * Convert a value to a number, returning the converted value in 'out' if the
+ * conversion succeeds. v most be a copy of a rooted jsval.
+ */
+JS_ALWAYS_INLINE bool
+ValueToNumber(JSContext *cx, jsval v, double *out)
+{
+    if (JSVAL_IS_INT(v)) {
+        *out = JSVAL_TO_INT(v);
+        return true;
+    }
+    if (JSVAL_IS_DOUBLE(v)) {
+        *out = *JSVAL_TO_DOUBLE(v);
+        return true;
+    }
+    extern jsval ValueToNumberSlow(JSContext *, jsval, double *);
+    return !JSVAL_IS_NULL(ValueToNumberSlow(cx, v, out));
+}
+
+/*
+ * Convert a value to a number, replacing 'vp' with the converted value and
+ * returning the value as a double in 'out'. vp must point to a rooted jsval.
+ *
+ * N.B. this function will allocate a new double if needed; callers needing
+ * only a double, not a value, should use ValueToNumber instead.
  */
-extern jsdouble
-js_ValueToNumber(JSContext *cx, jsval* vp);
+JS_ALWAYS_INLINE bool
+ValueToNumberValue(JSContext *cx, jsval *vp, double *out)
+{
+    jsval v = *vp;
+    if (JSVAL_IS_INT(v)) {
+        *out = JSVAL_TO_INT(v);
+        return true;
+    }
+    if (JSVAL_IS_DOUBLE(v)) {
+        *out = *JSVAL_TO_DOUBLE(v);
+        return true;
+    }
+    extern bool ValueToNumberValueSlow(JSContext *, jsval *, double *);
+    return ValueToNumberValueSlow(cx, vp, out);
+}
+
+/*
+ * Convert a value to a number, replacing 'vp' with the converted value. vp
+ * must point to a rooted jsval.
+ *
+ * N.B. this function will allocate a new double if needed; callers needing
+ * only a double, not a value, should use ValueToNumber instead.
+ */
+JS_ALWAYS_INLINE bool
+ValueToNumberValue(JSContext *cx, jsval *vp)
+{
+    jsval v = *vp;
+    if (JSVAL_IS_INT(v))
+        return true;
+    if (JSVAL_IS_DOUBLE(v))
+        return true;
+    extern bool ValueToNumberValueSlow(JSContext *, jsval *);
+    return ValueToNumberValueSlow(cx, vp);
+}
 
 /*
  * Convert a value to an int32 or uint32, according to the ECMA rules for
- * ToInt32 and ToUint32. On exit JSVAL_IS_NULL(*vp) iff there was an error. If
- * on exit JSVAL_IS_INT(*vp), then *vp holds the jsval matching the result.
- * Otherwise *vp is JSVAL_TRUE indicating that the jsval for result has to be
- * created explicitly using, for example, the js_NewNumberInRootedValue
- * function.
+ * ToInt32 and ToUint32. Return converted value on success, !ok on failure. v
+ * must be a copy of a rooted jsval.
  */
-extern int32
-js_ValueToECMAInt32(JSContext *cx, jsval *vp);
+JS_ALWAYS_INLINE bool
+ValueToECMAInt32(JSContext *cx, jsval v, int32_t *out)
+{
+    if (JSVAL_IS_INT(v)) {
+        *out = JSVAL_TO_INT(v);
+        return true;
+    }
+    extern bool ValueToECMAInt32Slow(JSContext *, jsval, int32_t *);
+    return ValueToECMAInt32Slow(cx, v, out);
+}
+
+JS_ALWAYS_INLINE bool
+ValueToECMAUint32(JSContext *cx, jsval v, uint32_t *out)
+{
+    if (JSVAL_IS_INT(v)) {
+        *out = (uint32_t)JSVAL_TO_INT(v);
+        return true;
+    }
+    extern bool ValueToECMAUint32Slow(JSContext *, jsval, uint32_t *);
+    return ValueToECMAUint32Slow(cx, v, out);
+}
 
-extern uint32
-js_ValueToECMAUint32(JSContext *cx, jsval *vp);
+/*
+ * Convert a value to a number, then to an int32 if it fits by rounding to
+ * nearest. Return converted value on success, !ok on failure. v must be a copy
+ * of a rooted jsval.
+ */
+JS_ALWAYS_INLINE bool
+ValueToInt32(JSContext *cx, jsval v, int32_t *out)
+{
+    if (JSVAL_IS_INT(v)) {
+        *out = JSVAL_TO_INT(v);
+        return true;
+    }
+    extern bool ValueToInt32Slow(JSContext *, jsval, int32_t *);
+    return ValueToInt32Slow(cx, v, out);
+}
+
+/*
+ * Convert a value to a number, then to a uint16 according to the ECMA rules
+ * for ToUint16. Return converted value on success, !ok on failure. v must be a
+ * copy of a rooted jsval.
+ */
+JS_ALWAYS_INLINE bool
+ValueToUint16(JSContext *cx, jsval v, uint16_t *out)
+{
+    if (JSVAL_IS_INT(v)) {
+        *out = (uint16_t)JSVAL_TO_INT(v);
+        return true;
+    }
+    extern bool ValueToUint16Slow(JSContext *, jsval, uint16_t *);
+    return ValueToUint16Slow(cx, v, out);
+}
+
+}  /* namespace js */
 
 /*
  * Specialized ToInt32 and ToUint32 converters for doubles.
  */
 /*
  * From the ES3 spec, 9.5
  *  2.  If Result(1) is NaN, +0, -0, +Inf, or -Inf, return +0.
  *  3.  Compute sign(Result(1)) * floor(abs(Result(1))).
@@ -350,39 +449,20 @@ js_DoubleToECMAInt32(jsdouble d)
     two32 = 4294967296.0;
     two31 = 2147483648.0;
     d = fmod(d, two32);
     d = (d >= 0) ? floor(d) : ceil(d) + two32;
     return (int32) (d >= two31 ? d - two32 : d);
 #endif
 }
 
-extern uint32
+uint32
 js_DoubleToECMAUint32(jsdouble d);
 
 /*
- * Convert a value to a number, then to an int32 if it fits by rounding to
- * nearest; but failing with an error report if the double is out of range
- * or unordered. On exit JSVAL_IS_NULL(*vp) iff there was an error. If on exit
- * JSVAL_IS_INT(*vp), then *vp holds the jsval matching the result. Otherwise
- * *vp is JSVAL_TRUE indicating that the jsval for result has to be created
- * explicitly using, for example, the js_NewNumberInRootedValue function.
- */
-extern int32
-js_ValueToInt32(JSContext *cx, jsval *vp);
-
-/*
- * Convert a value to a number, then to a uint16 according to the ECMA rules
- * for ToUint16. On exit JSVAL_IS_NULL(*vp) iff there was an error, otherwise
- * vp is jsval matching the result.
- */
-extern uint16
-js_ValueToUint16(JSContext *cx, jsval *vp);
-
-/*
  * Convert a jsdouble to an integral number, stored in a jsdouble.
  * If d is NaN, return 0.  If d is an infinity, return it without conversion.
  */
 static inline jsdouble
 js_DoubleToInteger(jsdouble d)
 {
     if (d == 0)
         return d;
@@ -421,19 +501,18 @@ js_strtod(JSContext *cx, const jschar *s
  *
  * If the string does not contain a number, set *ep to s and return 0.0 in dp.
  * Return false if out of memory.
  */
 extern JSBool
 js_strtointeger(JSContext *cx, const jschar *s, const jschar *send,
                 const jschar **ep, jsint radix, jsdouble *dp);
 
-JS_END_EXTERN_C
+namespace js {
 
-namespace js {
 template<typename T> struct NumberTraits { };
 template<> struct NumberTraits<int32> {
   static JS_ALWAYS_INLINE int32 NaN() { return 0; }
   static JS_ALWAYS_INLINE int32 toSelfType(int32 i) { return i; }
   static JS_ALWAYS_INLINE int32 toSelfType(jsdouble d) { return js_DoubleToECMAUint32(d); }
 };
 template<> struct NumberTraits<jsdouble> {
   static JS_ALWAYS_INLINE jsdouble NaN() { return js_NaN; }
--- a/js/src/jsops.cpp
+++ b/js/src/jsops.cpp
@@ -761,18 +761,18 @@ END_CASE(JSOP_BITAND)
                 DEFAULT_VALUE(cx, -2, JSTYPE_NUMBER, lval);                   \
             if (!JSVAL_IS_PRIMITIVE(rval))                                    \
                 DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval);                   \
             if (JSVAL_IS_STRING(lval) && JSVAL_IS_STRING(rval)) {             \
                 str  = JSVAL_TO_STRING(lval);                                 \
                 str2 = JSVAL_TO_STRING(rval);                                 \
                 cond = js_CompareStrings(str, str2) OP 0;                     \
             } else {                                                          \
-                VALUE_TO_NUMBER(cx, -2, lval, d);                             \
-                VALUE_TO_NUMBER(cx, -1, rval, d2);                            \
+                VALUE_TO_NUMBER(cx, lval, d);                                 \
+                VALUE_TO_NUMBER(cx, rval, d2);                                \
                 cond = JSDOUBLE_COMPARE(d, OP, d2, JS_FALSE);                 \
             }                                                                 \
         }                                                                     \
         TRY_BRANCH_AFTER_COND(cond, 2);                                       \
         regs.sp--;                                                            \
         STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));                               \
     JS_END_MACRO
 
@@ -846,18 +846,18 @@ END_CASE(JSOP_BITAND)
                     DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval);                 \
                     rtmp = JSVAL_TAG(rval);                                   \
                 }                                                             \
                 if (ltmp == JSVAL_STRING && rtmp == JSVAL_STRING) {           \
                     str  = JSVAL_TO_STRING(lval);                             \
                     str2 = JSVAL_TO_STRING(rval);                             \
                     cond = js_EqualStrings(str, str2) OP JS_TRUE;             \
                 } else {                                                      \
-                    VALUE_TO_NUMBER(cx, -2, lval, d);                         \
-                    VALUE_TO_NUMBER(cx, -1, rval, d2);                        \
+                    VALUE_TO_NUMBER(cx, lval, d);                             \
+                    VALUE_TO_NUMBER(cx, rval, d2);                            \
                     cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN);                \
                 }                                                             \
             }                                                                 \
         }                                                                     \
         TRY_BRANCH_AFTER_COND(cond, 2);                                       \
         regs.sp--;                                                            \
         STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));                               \
     JS_END_MACRO
@@ -940,17 +940,17 @@ BEGIN_CASE(JSOP_LSH)
 END_CASE(JSOP_LSH)
 
 BEGIN_CASE(JSOP_RSH)
     SIGNED_SHIFT_OP(>>);
 END_CASE(JSOP_RSH)
 
 BEGIN_CASE(JSOP_URSH)
 {
-    uint32 u;
+    uint32_t u;
 
     FETCH_UINT(cx, -2, u);
     FETCH_INT(cx, -1, j);
     u >>= (j & 31);
     regs.sp--;
     STORE_UINT(cx, -1, u);
 }
 END_CASE(JSOP_URSH)
@@ -991,18 +991,18 @@ BEGIN_CASE(JSOP_ADD)
                 regs.sp[-2] = STRING_TO_JSVAL(str);
             }
             str = js_ConcatStrings(cx, str, str2);
             if (!str)
                 goto error;
             regs.sp--;
             STORE_OPND(-1, STRING_TO_JSVAL(str));
         } else {
-            VALUE_TO_NUMBER(cx, -2, lval, d);
-            VALUE_TO_NUMBER(cx, -1, rval, d2);
+            VALUE_TO_NUMBER(cx, lval, d);
+            VALUE_TO_NUMBER(cx, rval, d2);
             d += d2;
             regs.sp--;
             STORE_NUMBER(cx, -1, d);
         }
     }
 END_CASE(JSOP_ADD)
 
 BEGIN_CASE(JSOP_OBJTOSTR)
@@ -1106,45 +1106,31 @@ BEGIN_CASE(JSOP_NEG)
     if (JSVAL_IS_INT(rval) &&
         rval != INT_TO_JSVAL(JSVAL_INT_MIN) &&
         (i = JSVAL_TO_INT(rval)) != 0) {
         JS_STATIC_ASSERT(!INT_FITS_IN_JSVAL(-JSVAL_INT_MIN));
         i = -i;
         JS_ASSERT(INT_FITS_IN_JSVAL(i));
         regs.sp[-1] = INT_TO_JSVAL(i);
     } else {
-        if (JSVAL_IS_DOUBLE(rval)) {
-            d = *JSVAL_TO_DOUBLE(rval);
-        } else {
-            d = js_ValueToNumber(cx, &regs.sp[-1]);
-            if (JSVAL_IS_NULL(regs.sp[-1]))
-                goto error;
-            JS_ASSERT(JSVAL_IS_NUMBER(regs.sp[-1]) ||
-                      regs.sp[-1] == JSVAL_TRUE);
-        }
+        if (!ValueToNumber(cx, regs.sp[-1], &d))
+            goto error;
         d = -d;
         if (!js_NewNumberInRootedValue(cx, d, &regs.sp[-1]))
             goto error;
     }
 END_CASE(JSOP_NEG)
 
 BEGIN_CASE(JSOP_POS)
+{
     rval = FETCH_OPND(-1);
-    if (!JSVAL_IS_NUMBER(rval)) {
-        d = js_ValueToNumber(cx, &regs.sp[-1]);
-        rval = regs.sp[-1];
-        if (JSVAL_IS_NULL(rval))
-            goto error;
-        if (rval == JSVAL_TRUE) {
-            if (!js_NewNumberInRootedValue(cx, d, &regs.sp[-1]))
-                goto error;
-        } else {
-            JS_ASSERT(JSVAL_IS_NUMBER(rval));
-        }
-    }
+    if (!ValueToNumberValue(cx, &regs.sp[-1]))
+        goto error;
+    rval = regs.sp[-1];
+}
 END_CASE(JSOP_POS)
 
 BEGIN_CASE(JSOP_DELNAME)
     LOAD_ATOM(0);
     id = ATOM_TO_JSID(atom);
     if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
         goto error;
 
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -352,18 +352,17 @@ js_str_escape(JSContext *cx, JSObject *o
     jschar ch;
     jsint mask;
     jsdouble d;
     const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
                            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
 
     mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
     if (argc > 1) {
-        d = js_ValueToNumber(cx, &argv[1]);
-        if (JSVAL_IS_NULL(argv[1]))
+        if (!ValueToNumber(cx, argv[1], &d))
             return JS_FALSE;
         if (!JSDOUBLE_IS_FINITE(d) ||
             (mask = (jsint)d) != d ||
             mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH))
         {
             char numBuf[12];
             JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) mask);
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
@@ -769,26 +768,24 @@ static JSBool
 str_substring(JSContext *cx, uintN argc, jsval *vp)
 {
     JSString *str;
     jsdouble d;
     jsdouble length, begin, end;
 
     NORMALIZE_THIS(cx, vp, str);
     if (argc != 0) {
-        d = js_ValueToNumber(cx, &vp[2]);
-        if (JSVAL_IS_NULL(vp[2]))
+        if (!ValueToNumber(cx, vp[2], &d))
             return JS_FALSE;
         length = str->length();
         begin = js_DoubleToInteger(d);
         if (argc == 1) {
             end = length;
         } else {
-            d = js_ValueToNumber(cx, &vp[3]);
-            if (JSVAL_IS_NULL(vp[3]))
+            if (!ValueToNumber(cx, vp[3], &d))
                 return JS_FALSE;
             end = js_DoubleToInteger(d);
         }
 
         str = SubstringTail(cx, str, length, begin, end);
         if (!str)
             return JS_FALSE;
     }
@@ -946,18 +943,17 @@ str_charAt(JSContext *cx, uintN argc, js
         if ((size_t)i >= str->length())
             goto out_of_range;
     } else {
         NORMALIZE_THIS(cx, vp, str);
 
         if (argc == 0) {
             d = 0.0;
         } else {
-            d = js_ValueToNumber(cx, &vp[2]);
-            if (JSVAL_IS_NULL(vp[2]))
+            if (!ValueToNumber(cx, vp[2], &d))
                 return JS_FALSE;
             d = js_DoubleToInteger(d);
         }
 
         if (d < 0 || str->length() <= d)
             goto out_of_range;
         i = (jsint) d;
     }
@@ -988,18 +984,17 @@ str_charCodeAt(JSContext *cx, uintN argc
         if ((size_t)i >= str->length())
             goto out_of_range;
     } else {
         NORMALIZE_THIS(cx, vp, str);
 
         if (argc == 0) {
             d = 0.0;
         } else {
-            d = js_ValueToNumber(cx, &vp[2]);
-            if (JSVAL_IS_NULL(vp[2]))
+            if (!ValueToNumber(cx, vp[2], &d))
                 return JS_FALSE;
             d = js_DoubleToInteger(d);
         }
 
         if (d < 0 || str->length() <= d)
             goto out_of_range;
         i = (jsint) d;
     }
@@ -1245,18 +1240,18 @@ str_indexOf(JSContext *cx, uintN argc, j
                 start = 0;
                 textlen = 0;
             } else {
                 start = i;
                 text += start;
                 textlen -= start;
             }
         } else {
-            jsdouble d = js_ValueToNumber(cx, &vp[3]);
-            if (JSVAL_IS_NULL(vp[3]))
+            jsdouble d;
+            if (!ValueToNumber(cx, vp[3], &d))
                 return JS_FALSE;
             d = js_DoubleToInteger(d);
             if (d <= 0) {
                 start = 0;
             } else if (d > textlen) {
                 start = 0;
                 textlen = 0;
             } else {
@@ -1305,18 +1300,17 @@ str_lastIndexOf(JSContext *cx, uintN arg
     if (argc > 1) {
         if (JSVAL_IS_INT(vp[3])) {
             j = JSVAL_TO_INT(vp[3]);
             if (j <= 0)
                 i = 0;
             else if (j < i)
                 i = j;
         } else {
-            d = js_ValueToNumber(cx, &vp[3]);
-            if (JSVAL_IS_NULL(vp[3]))
+            if (!ValueToNumber(cx, vp[3], &d))
                 return JS_FALSE;
             if (!JSDOUBLE_IS_NaN(d)) {
                 d = js_DoubleToInteger(d);
                 if (d <= 0)
                     i = 0;
                 else if (d < i)
                     i = (jsint)d;
             }
@@ -2182,18 +2176,18 @@ str_split(JSContext *cx, uintN argc, jsv
         sep = &tmp;
         re = NULL;
     }
 
     /* Use the second argument as the split limit, if given. */
     uint32 limit = 0; /* Avoid warning. */
     bool limited = (argc > 1) && !JSVAL_IS_VOID(vp[3]);
     if (limited) {
-        jsdouble d = js_ValueToNumber(cx, &vp[3]);
-        if (JSVAL_IS_NULL(vp[3]))
+        jsdouble d;
+        if (!ValueToNumber(cx, vp[3], &d))
             return false;
 
         /* Clamp limit between 0 and 1 + string length. */
         limit = js_DoubleToECMAUint32(d);
         if (limit > str->length())
             limit = 1 + str->length();
     }
 
@@ -2245,34 +2239,32 @@ static JSBool
 str_substr(JSContext *cx, uintN argc, jsval *vp)
 {
     JSString *str;
     jsdouble d;
     jsdouble length, begin, end;
 
     NORMALIZE_THIS(cx, vp, str);
     if (argc != 0) {
-        d = js_ValueToNumber(cx, &vp[2]);
-        if (JSVAL_IS_NULL(vp[2]))
+        if (!ValueToNumber(cx, vp[2], &d))
             return JS_FALSE;
         length = str->length();
         begin = js_DoubleToInteger(d);
         if (begin < 0) {
             begin += length;
             if (begin < 0)
                 begin = 0;
         } else if (begin > length) {
             begin = length;
         }
 
         if (argc == 1) {
             end = length;
         } else {
-            d = js_ValueToNumber(cx, &vp[3]);
-            if (JSVAL_IS_NULL(vp[3]))
+            if (!ValueToNumber(cx, vp[3], &d))
                 return JS_FALSE;
             end = js_DoubleToInteger(d);
             if (end < 0)
                 end = 0;
             end += begin;
             if (end > length)
                 end = length;
         }
@@ -2348,34 +2340,32 @@ str_slice(JSContext *cx, uintN argc, jsv
         }
     }
 
     NORMALIZE_THIS(cx, vp, str);
 
     if (argc != 0) {
         double begin, end, length;
 
-        begin = js_ValueToNumber(cx, &vp[2]);
-        if (JSVAL_IS_NULL(vp[2]))
+        if (!ValueToNumber(cx, vp[2], &begin))
             return JS_FALSE;
         begin = js_DoubleToInteger(begin);
         length = str->length();
         if (begin < 0) {
             begin += length;
             if (begin < 0)
                 begin = 0;
         } else if (begin > length) {
             begin = length;
         }
 
         if (argc == 1) {
             end = length;
         } else {
-            end = js_ValueToNumber(cx, &vp[3]);
-            if (JSVAL_IS_NULL(vp[3]))
+            if (!ValueToNumber(cx, vp[3], &end))
                 return JS_FALSE;
             end = js_DoubleToInteger(end);
             if (end < 0) {
                 end += length;
                 if (end < 0)
                     end = 0;
             } else if (end > length) {
                 end = length;
@@ -2983,36 +2973,40 @@ JS_DEFINE_CALLINFO_3(extern, OBJECT, js_
 
 #endif /* !JS_TRACER */
 
 static JSBool
 str_fromCharCode(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval *argv;
     uintN i;
-    uint16 code;
     jschar *chars;
     JSString *str;
 
     argv = vp + 2;
     JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
-    if (argc == 1 &&
-        (code = js_ValueToUint16(cx, &argv[0])) < UNIT_STRING_LIMIT) {
-        str = JSString::unitString(code);
-        if (!str)
+    if (argc == 1) {
+        uint16_t code;
+        if (!ValueToUint16(cx, argv[0], &code))
             return JS_FALSE;
-        *vp = STRING_TO_JSVAL(str);
-        return JS_TRUE;
+        if (code < UNIT_STRING_LIMIT) {
+            str = JSString::unitString(code);
+            if (!str)
+                return JS_FALSE;
+            *vp = STRING_TO_JSVAL(str);
+            return JS_TRUE;
+        }
+        argv[0] = INT_TO_JSVAL(code);
     }
     chars = (jschar *) cx->malloc((argc + 1) * sizeof(jschar));
     if (!chars)
         return JS_FALSE;
     for (i = 0; i < argc; i++) {
-        code = js_ValueToUint16(cx, &argv[i]);
-        if (JSVAL_IS_NULL(argv[i])) {
+        uint16_t code;
+        if (!ValueToUint16(cx, argv[i], &code)) {
             cx->free(chars);
             return JS_FALSE;
         }
         chars[i] = (jschar)code;
     }
     chars[i] = 0;
     str = js_NewString(cx, chars, argc);
     if (!str) {
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -8855,21 +8855,20 @@ TraceRecorder::relational(LOpcode op, bo
           default:
             JS_NOT_REACHED("JSVAL_IS_NUMBER if int/double, objects should "
                            "have been handled at start of method");
             RETURN_STOP_A("safety belt");
         }
     }
     {
         AutoValueRooter tvr(cx, JSVAL_NULL);
-
         *tvr.addr() = l;
-        lnum = js_ValueToNumber(cx, tvr.addr());
+        ValueToNumber(cx, tvr.value(), &lnum);
         *tvr.addr() = r;
-        rnum = js_ValueToNumber(cx, tvr.addr());
+        ValueToNumber(cx, tvr.value(), &rnum);
     }
     cond = EvalCmp(op, lnum, rnum);
     fp = true;
 
     /* 11.8.5 steps 6-15. */
   do_comparison:
     /*
      * If the result is not a number or it's not a quad, we must use an integer
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -114,20 +114,19 @@ ArrayBuffer::class_constructor(JSContext
     }
 
     if (argc == 0) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_TYPED_ARRAY_BAD_ARGS);
         return false;
     }
 
-    int32 nbytes = js_ValueToECMAInt32(cx, &argv[0]);
-    if (JSVAL_IS_NULL(argv[0]))
+    int32_t nbytes;
+    if (!ValueToECMAInt32(cx, argv[0], &nbytes))
         return false;
-
     if (nbytes < 0 || !INT_FITS_IN_JSVAL(nbytes)) {
         /*
          * We're just not going to support arrays that are bigger than what will fit
          * as an integer jsval; if someone actually ever complains (validly), then we
          * can fix.
          */
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_BAD_ARRAY_LENGTH);
@@ -559,20 +558,18 @@ class TypedArrayTemplate
 
         if (JSVAL_IS_DOUBLE(*vp)) {
             d = *JSVAL_TO_DOUBLE(*vp);
         } else if (JSVAL_IS_NULL(*vp)) {
             d = 0.0f;
         } else if (JSVAL_IS_PRIMITIVE(*vp)) {
             JS_ASSERT(JSVAL_IS_STRING(*vp) || JSVAL_IS_SPECIAL(*vp));
             if (JSVAL_IS_STRING(*vp)) {
-                // note that ValueToNumber will always
-                // succeed with a string arg
-                d = js_ValueToNumber(cx, vp);
-                JS_ASSERT(*vp != JSVAL_NULL);
+                // note that ValueToNumber will always succeed with a string arg
+                ValueToNumber(cx, *vp, &d);
             } else if (*vp == JSVAL_VOID) {
                 d = js_NaN;
             } else {
                 d = (double) JSVAL_TO_BOOLEAN(*vp);
             }
         } else {
             // non-primitive assignments become NaN or 0 (for float/int arrays)
             d = js_NaN;
@@ -715,36 +712,32 @@ class TypedArrayTemplate
                 return false;
             }
 
             if (!tarray->init(cx, len)) {
                 delete tarray;
                 return false;
             }
         } else if (JSVAL_IS_OBJECT(argv[0])) {
-            int32 byteOffset = -1;
-            int32 length = -1;
+            int32_t byteOffset = -1;
+            int32_t length = -1;
 
             if (argc > 1) {
-                byteOffset = js_ValueToInt32(cx, &argv[1]);
-                if (JSVAL_IS_NULL(argv[1]))
+                if (!ValueToInt32(cx, argv[1], &byteOffset))
                     return false;
-
                 if (byteOffset < 0) {
                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                          JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "1");
                     return false;
                 }
             }
 
             if (argc > 2) {
-                length = js_ValueToInt32(cx, &argv[2]);
-                if (JSVAL_IS_NULL(argv[2]))
+                if (!ValueToInt32(cx, argv[2], &length))
                     return false;
-
                 if (length < 0) {
                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                          JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "2");
                     return false;
                 }
             }
 
             tarray = new ThisTypeArray();
@@ -784,34 +777,32 @@ class TypedArrayTemplate
         argv = JS_ARGV(cx, vp);
         obj = JS_THIS_OBJECT(cx, vp);
 
         ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
         if (!tarray)
             return true;
 
         // these are the default values
-        int32 begin = 0, end = tarray->length;
-        int32 length = int32(tarray->length);
+        int32_t begin = 0, end = tarray->length;
+        int32_t length = int32(tarray->length);
 
         if (argc > 0) {
-            begin = js_ValueToInt32(cx, &argv[0]);
-            if (JSVAL_IS_NULL(argv[0]))
+            if (!ValueToInt32(cx, argv[0], &begin))
                 return false;
             if (begin < 0) {
                 begin += length;
                 if (begin < 0)
                     begin = 0;
             } else if (begin > length) {
                 begin = length;
             }
 
             if (argc > 1) {
-                end = js_ValueToInt32(cx, &argv[1]);
-                if (JSVAL_IS_NULL(argv[1]))
+                if (!ValueToInt32(cx, argv[1], &end))
                     return false;
                 if (end < 0) {
                     end += length;
                     if (end < 0)
                         end = 0;
                 } else if (end > length) {
                     end = length;
                 }
@@ -996,18 +987,18 @@ class TypedArrayTemplate
     {
         if (JSVAL_IS_INT(v))
             return NativeType(JSVAL_TO_INT(v));
 
         if (JSVAL_IS_DOUBLE(v))
             return NativeType(*JSVAL_TO_DOUBLE(v));
 
         if (JSVAL_IS_PRIMITIVE(v) && v != JSVAL_HOLE) {
-            jsdouble dval = js_ValueToNumber(cx, &v);
-            JS_ASSERT(v != JSVAL_NULL);
+            jsdouble dval;
+            ValueToNumber(cx, v, &dval);
             return NativeType(dval);
         }
 
         if (ArrayTypeIsFloatingPoint())
             return NativeType(js_NaN);
 
         return NativeType(int32(0));
     }
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -44,16 +44,17 @@
 #include <errno.h>
 #include <math.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <signal.h>
 #include <locale.h>
 #include "jstypes.h"
+#include "jsstdint.h"
 #include "jsarena.h"
 #include "jsutil.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbuiltins.h"
 #include "jscntxt.h"