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 id12825
push userrsayre@mozilla.com
push dateThu, 15 Apr 2010 16:08:37 +0000
treeherdermozilla-central@1138f6156b1b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersigor
bugs552574
milestone1.9.3a4pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
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"