Bug 106495: baking out the last commit as the tree is closed.
authorigor@mir2.org
Thu, 02 Aug 2007 04:27:04 -0700
changeset 4154 c1283b499d2bce1b4ba568c316ec5cde3bb54bed
parent 4153 8c565d01c37098ce1a1f82d8157d205b7c9359ee
child 4155 fcc40460c8b3610f14b12baca21626f996c79734
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs106495
milestone1.9a7pre
Bug 106495: baking out the last commit as the tree is closed.
js/src/jsnum.c
js/src/jsnum.h
js/src/jsscan.c
js/src/jsstr.c
js/src/jsstr.h
--- a/js/src/jsnum.c
+++ b/js/src/jsnum.c
@@ -92,18 +92,21 @@ num_parseFloat(JSContext *cx, uintN argc
 {
     JSString *str;
     jsdouble d;
     const jschar *bp, *ep;
 
     str = js_ValueToString(cx, vp[2]);
     if (!str)
         return JS_FALSE;
-    bp = JSSTRING_CHARS(str);
-    if (!js_strtod(cx, bp, bp + JSSTRING_LENGTH(str), &ep, &d))
+    /* XXXbe js_strtod shouldn't require NUL termination */
+    bp = js_UndependString(cx, str);
+    if (!bp)
+        return JS_FALSE;
+    if (!js_strtod(cx, bp, &ep, &d))
         return JS_FALSE;
     if (ep == bp) {
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
         return JS_TRUE;
     }
     return js_NewNumberValue(cx, d, vp);
 }
 
@@ -125,18 +128,21 @@ num_parseInt(JSContext *cx, uintN argc, 
     if (radix != 0 && (radix < 2 || radix > 36)) {
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
         return JS_TRUE;
     }
 
     str = js_ValueToString(cx, vp[2]);
     if (!str)
         return JS_FALSE;
-    bp = JSSTRING_CHARS(str);
-    if (!js_strtointeger(cx, bp, bp + JSSTRING_LENGTH(str), &ep, radix, &d))
+    /* XXXbe js_strtointeger shouldn't require NUL termination */
+    bp = js_UndependString(cx, str);
+    if (!bp)
+        return JS_FALSE;
+    if (!js_strtointeger(cx, bp, &ep, radix, &d))
         return JS_FALSE;
     if (ep == bp) {
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
         return JS_TRUE;
     }
     return js_NewNumberValue(cx, d, vp);
 }
 
@@ -695,46 +701,47 @@ js_NumberToString(JSContext *cx, jsdoubl
     return JS_NewStringCopyZ(cx, numStr);
 }
 
 JSBool
 js_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
 {
     JSObject *obj;
     JSString *str;
-    const jschar *bp, *end, *ep;
+    const jschar *bp, *ep;
 
     if (JSVAL_IS_OBJECT(v)) {
         obj = JSVAL_TO_OBJECT(v);
         if (!obj) {
             *dp = 0;
             return JS_TRUE;
         }
         if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_NUMBER, &v))
             return JS_FALSE;
     }
     if (JSVAL_IS_INT(v)) {
         *dp = (jsdouble)JSVAL_TO_INT(v);
     } else if (JSVAL_IS_DOUBLE(v)) {
         *dp = *JSVAL_TO_DOUBLE(v);
     } else if (JSVAL_IS_STRING(v)) {
         str = JSVAL_TO_STRING(v);
-
         /*
          * Note that ECMA doesn't treat a string beginning with a '0' as an
          * octal number here.  This works because all such numbers will be
          * interpreted as decimal by js_strtod and will never get passed to
          * js_strtointeger (which would interpret them as octal).
          */
-        bp = JSSTRING_CHARS(str);
-        end = bp + JSSTRING_LENGTH(str);
-        if ((!js_strtod(cx, bp, end, &ep, dp) ||
-             js_SkipWhiteSpace(ep, end) != end) &&
-             (!js_strtointeger(cx, bp, end, &ep, 0, dp) ||
-              js_SkipWhiteSpace(ep, end) != end)) {
+        /* XXXbe js_strtod shouldn't require NUL termination */
+        bp = js_UndependString(cx, str);
+        if (!bp)
+            return JS_FALSE;
+        if ((!js_strtod(cx, bp, &ep, dp) ||
+             js_SkipWhiteSpace(ep) != bp + str->length) &&
+            (!js_strtointeger(cx, bp, &ep, 0, dp) ||
+             js_SkipWhiteSpace(ep) != bp + str->length)) {
             goto badstr;
         }
     } else if (JSVAL_IS_BOOLEAN(v)) {
         *dp = JSVAL_TO_BOOLEAN(v) ? 1 : 0;
     } else {
 badstr:
         *dp = *cx->runtime->jsNaN;
     }
@@ -865,44 +872,42 @@ js_DoubleToInteger(jsdouble d)
     }
     neg = (d < 0);
     d = floor(neg ? -d : d);
     return neg ? -d : d;
 }
 
 
 JSBool
-js_strtod(JSContext *cx, const jschar *s, const jschar *send,
-          const jschar **ep, jsdouble *dp)
+js_strtod(JSContext *cx, const jschar *s, const jschar **ep, jsdouble *dp)
 {
-    const jschar *s1;
-    size_t length, i;
     char cbuf[32];
+    size_t i;
     char *cstr, *istr, *estr;
     JSBool negative;
     jsdouble d;
-
-    s1 = js_SkipWhiteSpace(s, send);
-    length = send - s1;
+    const jschar *s1 = js_SkipWhiteSpace(s);
+    size_t length = js_strlen(s1);
 
     /* Use cbuf to avoid malloc */
     if (length >= sizeof cbuf) {
         cstr = (char *) JS_malloc(cx, length + 1);
         if (!cstr)
            return JS_FALSE;
     } else {
         cstr = cbuf;
     }
 
-    for (i = 0; i != length; i++) {
-        if (s1[i] >> 8)
+    for (i = 0; i <= length; i++) {
+        if (s1[i] >> 8) {
+            cstr[i] = 0;
             break;
+        }
         cstr[i] = (char)s1[i];
     }
-    cstr[i] = 0;
 
     istr = cstr;
     if ((negative = (*istr == '-')) != 0 || *istr == '+')
         istr++;
     if (!strncmp(istr, js_Infinity_str, sizeof js_Infinity_str - 1)) {
         d = *(negative ? cx->runtime->jsNegativeInfinity : cx->runtime->jsPositiveInfinity);
         estr = istr + 8;
     } else {
@@ -969,78 +974,66 @@ static intN GetNextBinaryDigit(struct Bi
         bdr->digitMask = bdr->base >> 1;
     }
     bit = (bdr->digit & bdr->digitMask) != 0;
     bdr->digitMask >>= 1;
     return bit;
 }
 
 JSBool
-js_strtointeger(JSContext *cx, const jschar *s, const jschar *send,
-                const jschar **ep, jsint base, jsdouble *dp)
+js_strtointeger(JSContext *cx, const jschar *s, const jschar **ep, jsint base, jsdouble *dp)
 {
-    const jschar *s1, *start;
     JSBool negative;
     jsdouble value;
+    const jschar *start;
+    const jschar *s1 = js_SkipWhiteSpace(s);
 
-    s1 = js_SkipWhiteSpace(s, send);
-    if (s1 == send)
-        goto no_digits;
-    if ((negative = (*s1 == '-')) != 0 || *s1 == '+') {
+    if ((negative = (*s1 == '-')) != 0 || *s1 == '+')
         s1++;
-        if (s1 == send)
-            goto no_digits;
-    }
 
     if (base == 0) {
         /* No base supplied, or some base that evaluated to 0. */
         if (*s1 == '0') {
             /* It's either hex or octal; only increment char if str isn't '0' */
-            if (s1 + 1 != send && (s1[1] == 'X' || s1[1] == 'x')) {
-                base = 16;
+            if (s1[1] == 'X' || s1[1] == 'x') { /* Hex */
                 s1 += 2;
-                if (s1 == send)
-                    goto no_digits;
-            } else {
+                base = 16;
+            } else {    /* Octal */
                 base = 8;
             }
         } else {
             base = 10; /* Default to decimal. */
         }
-    } else if (base == 16) {
+    } else if (base == 16 && *s1 == '0' && (s1[1] == 'X' || s1[1] == 'x')) {
         /* If base is 16, ignore hex prefix. */
-        if (*s1 == '0' && s1 + 1 != send && (s1[1] == 'X' || s1[1] == 'x')) {
-            s1 += 2;
-            if (s1 == send)
-                goto no_digits;
-        }
+        s1 += 2;
     }
 
     /*
      * Done with the preliminaries; find some prefix of the string that's
      * a number in the given base.
      */
-    JS_ASSERT(s1 < send);
-    start = s1;
+    start = s1; /* Mark - if string is empty, we return NaN. */
     value = 0.0;
-    do {
+    for (;;) {
         uintN digit;
         jschar c = *s1;
         if ('0' <= c && c <= '9')
             digit = c - '0';
         else if ('a' <= c && c <= 'z')
             digit = c - 'a' + 10;
         else if ('A' <= c && c <= 'Z')
             digit = c - 'A' + 10;
         else
             break;
         if (digit >= (uintN)base)
             break;
         value = value * base + digit;
-    } while (++s1 != send);
+        s1++;
+    }
 
     if (value >= 9007199254740992.0) {
         if (base == 10) {
             /*
              * If we're accumulating a decimal number and the number is >=
              * 2^53, then the result from the repeated multiply-add above may
              * be inaccurate.  Call JS_strtod to get the correct answer.
              */
@@ -1116,17 +1109,16 @@ js_strtointeger(JSContext *cx, const jsc
                 }
               done:;
             }
         }
     }
     /* We don't worry about inaccurate numbers for any other base. */
 
     if (s1 == start) {
-      no_digits:
         *dp = 0.0;
         *ep = s;
     } else {
         *dp = negative ? -value : value;
         *ep = s1;
     }
     return JS_TRUE;
 }
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -237,27 +237,25 @@ js_DoubleToInteger(jsdouble d);
  * return the closest double number to the given input in dp.
  *
  * Also allows inputs of the form [+|-]Infinity, which produce an infinity of
  * the appropriate sign.  The case of the "Infinity" string must match exactly.
  * 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_strtod(JSContext *cx, const jschar *s, const jschar *send,
-          const jschar **ep, jsdouble *dp);
+js_strtod(JSContext *cx, const jschar *s, const jschar **ep, jsdouble *dp);
 
 /*
  * Similar to strtol except that it handles integers of arbitrary size.
  * Guaranteed to return the closest double number to the given input when radix
  * is 10 or a power of 2.  Callers may see round-off errors for very large
  * numbers of a different radix than 10 or a power of 2.
  *
  * 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_strtointeger(JSContext *cx, const jschar *s, const jschar **ep, jsint radix, jsdouble *dp);
 
 JS_END_EXTERN_C
 
 #endif /* jsnum_h___ */
--- a/js/src/jsscan.c
+++ b/js/src/jsscan.c
@@ -1114,17 +1114,16 @@ js_GetToken(JSContext *cx, JSTokenStream
                                                TOKENBUF_BASE(),               \
                                                TOKENBUF_LENGTH(),             \
                                                0)                             \
                              : NULL)
 #define ADD_TO_TOKENBUF(c)  FastAppendChar(&ts->tokenbuf, (jschar) (c))
 
 /* The following 4 macros should only be used when TOKENBUF_OK() is true. */
 #define TOKENBUF_BASE()     (ts->tokenbuf.base)
-#define TOKENBUF_END()      (ts->tokenbuf.ptr)
 #define TOKENBUF_CHAR(i)    (ts->tokenbuf.base[i])
 #define TRIM_TOKENBUF(i)    (ts->tokenbuf.ptr = ts->tokenbuf.base + i)
 #define NUL_TERM_TOKENBUF() (*ts->tokenbuf.ptr = 0)
 
     /* Check for a pushed-back token resulting from mismatching lookahead. */
     while (ts->lookahead != 0) {
         JS_ASSERT(!(ts->flags & TSF_XMLTEXTMODE));
         ts->lookahead--;
@@ -1439,26 +1438,24 @@ retry:
 
         /* Put back the next char and NUL-terminate tokenbuf for js_strto*. */
         UngetChar(ts, c);
         ADD_TO_TOKENBUF(0);
 
         if (!TOKENBUF_OK())
             goto error;
         if (radix == 10) {
-            if (!js_strtod(cx, TOKENBUF_BASE(), TOKENBUF_END(),
-                           &endptr, &dval)) {
+            if (!js_strtod(cx, TOKENBUF_BASE(), &endptr, &dval)) {
                 js_ReportCompileErrorNumber(cx, ts,
                                             JSREPORT_TS | JSREPORT_ERROR,
                                             JSMSG_OUT_OF_MEMORY);
                 goto error;
             }
         } else {
-            if (!js_strtointeger(cx, TOKENBUF_BASE(), TOKENBUF_END(),
-                                 &endptr, radix, &dval)) {
+            if (!js_strtointeger(cx, TOKENBUF_BASE(), &endptr, radix, &dval)) {
                 js_ReportCompileErrorNumber(cx, ts,
                                             JSREPORT_TS | JSREPORT_ERROR,
                                             JSMSG_OUT_OF_MEMORY);
                 goto error;
             }
         }
         tp->t_dval = dval;
         tt = TOK_NUMBER;
--- a/js/src/jsstr.c
+++ b/js/src/jsstr.c
@@ -2856,20 +2856,20 @@ js_strchr_limit(const jschar *s, jschar 
         if (*s == c)
             return (jschar *)s;
         s++;
     }
     return NULL;
 }
 
 const jschar *
-js_SkipWhiteSpace(const jschar *s, const jschar *end)
+js_SkipWhiteSpace(const jschar *s)
 {
-    JS_ASSERT(s <= end);
-    while (s != end && JS_ISSPACE(*s))
+    /* JS_ISSPACE is false on a null. */
+    while (JS_ISSPACE(*s))
         s++;
     return s;
 }
 
 #ifdef JS_C_STRINGS_ARE_UTF8
 
 jschar *
 js_InflateString(JSContext *cx, const char *bytes, size_t *length)
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -432,17 +432,17 @@ extern jschar *
 js_strchr_limit(const jschar *s, jschar c, const jschar *limit);
 
 #define js_strncpy(t, s, n)     memcpy((t), (s), (n) * sizeof(jschar))
 
 /*
  * Return s advanced past any Unicode white space characters.
  */
 extern const jschar *
-js_SkipWhiteSpace(const jschar *s, const jschar *end);
+js_SkipWhiteSpace(const jschar *s);
 
 /*
  * Inflate bytes to JS chars and vice versa.  Report out of memory via cx
  * and return null on error, otherwise return the jschar or byte vector that
  * was JS_malloc'ed. length is updated with the length of the new string in jschars.
  */
 extern jschar *
 js_InflateString(JSContext *cx, const char *bytes, size_t *length);