Avoid malloc and JS_dtobasestr for single digit numbers base != 10 (522195, r=brendan).
authorAndreas Gal <gal@mozilla.com>
Wed, 14 Oct 2009 13:25:20 -0700
changeset 33937 2a21a74b71a9f81a6642622bdc015b7a9b74e78e
parent 33936 dde13d040e441b2e3ebbd4af54126f69eecd95b7
child 33938 e0f7220ab9ee15357867aac670e8fb1607767211
push idunknown
push userunknown
push dateunknown
reviewersbrendan
bugs522195
milestone1.9.3a1pre
Avoid malloc and JS_dtobasestr for single digit numbers base != 10 (522195, r=brendan).
js/src/jsnum.cpp
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -376,16 +376,19 @@ IntToCString(jsint i, jsint base, char *
     }
     if (i < 0)
         *--cp = '-';
 
     JS_ASSERT(cp >= buf);
     return cp;
 }
 
+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;
 
@@ -401,29 +404,21 @@ num_toString(JSContext *cx, uintN argc, 
         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;
         }
     }
-    if (base == 10) {
-        str = js_NumberToString(cx, d);
-    } else {
-        char *dStr = JS_dtobasestr(base, d);
-        if (!dStr) {
-            JS_ReportOutOfMemory(cx);
-            return JS_FALSE;
-        }
-        str = JS_NewStringCopyZ(cx, dStr);
-        js_free(dStr);
+    str = js_NumberToStringWithBase(cx, d, base);
+    if (!str) {
+        JS_ReportOutOfMemory(cx);
+        return JS_FALSE;
     }
-    if (!str)
-        return JS_FALSE;
     *vp = STRING_TO_JSVAL(str);
     return JS_TRUE;
 }
 
 static JSBool
 num_toLocaleString(JSContext *cx, uintN argc, jsval *vp)
 {
     char thousandsLength, decimalLength;
@@ -624,18 +619,19 @@ num_toPrecision(JSContext *cx, uintN arg
     if (argc == 0 || JSVAL_IS_VOID(vp[2]))
         return num_toString(cx, 0, vp);
     return num_to(cx, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0,
                   argc, vp);
 }
 
 #ifdef JS_TRACER
 
-JS_DEFINE_TRCINFO_1(num_toString,
-    (2, (extern, STRING, js_NumberToString,      CONTEXT, THIS_DOUBLE,        1, 1)))
+JS_DEFINE_TRCINFO_2(num_toString,
+    (2, (extern, STRING, js_NumberToString,         CONTEXT, THIS_DOUBLE,        1, 1)),
+    (3, (static, STRING, js_NumberToStringWithBase, CONTEXT, THIS_DOUBLE, INT32, 1, 1)))
 
 #endif /* JS_TRACER */
 
 static JSFunctionSpec number_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,       num_toSource,          0,JSFUN_THISP_NUMBER),
 #endif
     JS_TN(js_toString_str,       num_toString,          1,JSFUN_THISP_NUMBER, &num_toString_trcinfo),
@@ -854,48 +850,60 @@ NumberToCString(JSContext *cx, jsdouble 
         if (!numStr) {
             JS_ReportOutOfMemory(cx);
             return NULL;
         }
     }
     return numStr;
 }
 
-static JSString *
-NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base)
+static JSString * JS_FASTCALL
+js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base)
 {
     /*
      * The longest possible result here that would need to fit in buf is
      * (-0x80000000).toString(2), which has length 33.  (This can produce
      * longer results, but in those cases buf is not used; see comment at
      * NumberToCString.)
      */
     char buf[34];
     char *numStr;
     JSString *s;
 
+    /*
+     * Caller is responsible for error reporting. When called from trace,
+     * returning NULL here will cause us to fall of trace and then retry
+     * from the interpreter (which will report the error).
+     */
     if (base < 2 || base > 36)
         return NULL;
+
+    jsint i;
+    if (JSDOUBLE_IS_INT(d, i)) {
+        if (base == 10 && jsuint(i) < INT_STRING_LIMIT)
+            return JSString::intString(i);
+        if (jsuint(i) < jsuint(base)) {
+            if (i < 10)
+                return JSString::intString(i);
+            return JSString::unitString('a' + i - 10);
+        }
+    }
     numStr = NumberToCString(cx, d, base, buf, sizeof buf);
     if (!numStr)
         return NULL;
     s = JS_NewStringCopyZ(cx, numStr);
     if (!(numStr >= buf && numStr < buf + sizeof buf))
         js_free(numStr);
     return s;
 }
 
 JSString * JS_FASTCALL
 js_NumberToString(JSContext *cx, jsdouble d)
 {
-    jsint i;
-
-    if (JSDOUBLE_IS_INT(d, i) && jsuint(i) < INT_STRING_LIMIT)
-        return JSString::intString(i);
-    return NumberToStringWithBase(cx, d, 10);
+    return js_NumberToStringWithBase(cx, d, 10);
 }
 
 JSBool JS_FASTCALL
 js_NumberValueToCharBuffer(JSContext *cx, jsval v, JSCharBuffer &cb)
 {
     /* Convert to C-string. */
     static const size_t arrSize = DTOSTR_STANDARD_BUFFER_SIZE;
     char arr[arrSize];