Bug 898912 (part 5) - Add GetDecimalInteger(), a version of GetPrefixInteger() specialized for decimal integers. r=till.
authorNicholas Nethercote <nnethercote@mozilla.com>
Mon, 29 Jul 2013 18:31:13 -0700
changeset 153152 a418ca312cbd24ac8b9ee21a2c8902d0ff036bea
parent 153151 0a4f1b961a988844a3e6f37103a5f30aab073dbd
child 153153 a09b9ba8dc0354c6a80036522588a25f55908aca
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs898912
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 898912 (part 5) - Add GetDecimalInteger(), a version of GetPrefixInteger() specialized for decimal integers. r=till.
js/src/frontend/TokenStream.cpp
js/src/jsnum.cpp
js/src/jsnum.h
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -1230,21 +1230,21 @@ TokenStream::getTokenInternal()
         }
 
         /*
          * Unlike identifiers and strings, numbers cannot contain escaped
          * chars, so we don't need to use tokenbuf.  Instead we can just
          * convert the jschars in userbuf directly to the numeric value.
          */
         double dval;
-        const jschar *dummy;
         if (!((decimalPoint == HasDecimal) || hasExp)) {
-            if (!GetPrefixInteger(cx, numStart, userbuf.addressOfNextRawChar(), 10, &dummy, &dval))
+            if (!GetDecimalInteger(cx, numStart, userbuf.addressOfNextRawChar(), &dval))
                 goto error;
         } else {
+            const jschar *dummy;
             if (!js_strtod(cx, numStart, userbuf.addressOfNextRawChar(), &dummy, &dval))
                 goto error;
         }
         tp->setNumber(dval, decimalPoint);
         tt = TOK_NUMBER;
         goto out;
     }
 
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -45,18 +45,18 @@
 using namespace js;
 using namespace js::types;
 
 using mozilla::PodCopy;
 using mozilla::RangedPtr;
 
 /*
  * If we're accumulating a decimal number and the number is >= 2^53, then the
- * fast result from the loop in GetPrefixInteger may be inaccurate. Call
- * js_strtod_harder to get the correct answer.
+ * fast result from the loop in Get{Prefix,Decimal}Integer may be inaccurate.
+ * Call js_strtod_harder to get the correct answer.
  */
 static bool
 ComputeAccurateDecimalInteger(ExclusiveContext *cx,
                               const jschar *start, const jschar *end, double *dp)
 {
     size_t length = end - start;
     char *cstr = cx->pod_malloc<char>(length + 1);
     if (!cstr)
@@ -135,17 +135,17 @@ ComputeAccurateBinaryBaseInteger(const j
     BinaryDigitReader bdr(base, start, end);
 
     /* Skip leading zeroes. */
     int bit;
     do {
         bit = bdr.nextDigit();
     } while (bit == 0);
 
-    JS_ASSERT(bit == 1); // guaranteed by GetPrefixInteger
+    JS_ASSERT(bit == 1); // guaranteed by Get{Prefix,Decimal}Integer
 
     /* Gather the 53 significant bits (including the leading 1). */
     double value = 1.0;
     for (int j = 52; j > 0; j--) {
         bit = bdr.nextDigit();
         if (bit < 0)
             return value;
         value = value * 2 + bit;
@@ -227,16 +227,40 @@ js::GetPrefixInteger(ExclusiveContext *c
     if (base == 10)
         return ComputeAccurateDecimalInteger(cx, start, s, dp);
     if ((base & (base - 1)) == 0)
         *dp = ComputeAccurateBinaryBaseInteger(start, s, base);
 
     return true;
 }
 
+bool
+js::GetDecimalInteger(ExclusiveContext *cx, const jschar *start, const jschar *end, double *dp)
+{
+    JS_ASSERT(start <= end);
+
+    const jschar *s = start;
+    double d = 0.0;
+    for (; s < end; s++) {
+        jschar c = *s;
+        JS_ASSERT('0' <= c && c <= '9');
+        int digit = c - '0';
+        d = d * 10 + digit;
+    }
+
+    *dp = d;
+
+    // If we haven't reached the limit of integer precision, we're done.
+    if (d < DOUBLE_INTEGRAL_PRECISION_LIMIT)
+        return true;
+
+    // Otherwise compute the correct integer from the prefix of valid digits.
+    return ComputeAccurateDecimalInteger(cx, start, s, dp);
+}
+
 static JSBool
 num_isNaN(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() == 0) {
         args.rval().setBoolean(true);
         return true;
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -126,16 +126,24 @@ ParseDecimalNumber(const JS::TwoByteChar
  *
  * If [start, end) does not begin with a number with the specified base,
  * *dp == 0 and *endp == start upon return.
  */
 extern bool
 GetPrefixInteger(ExclusiveContext *cx, const jschar *start, const jschar *end, int base,
                  const jschar **endp, double *dp);
 
+/*
+ * This is like GetPrefixInteger, but only deals with base 10, and doesn't have
+ * and |endp| outparam.  It should only be used when the jschars are known to
+ * only contain digits.
+ */
+extern bool
+GetDecimalInteger(ExclusiveContext *cx, const jschar *start, const jschar *end, double *dp);
+
 extern bool
 StringToNumber(ExclusiveContext *cx, JSString *str, double *result);
 
 /* ES5 9.3 ToNumber, overwriting *vp with the appropriate number value. */
 JS_ALWAYS_INLINE bool
 ToNumber(JSContext *cx, JS::MutableHandleValue vp)
 {
 #ifdef DEBUG