LCOV - code coverage report
Current view: directory - js/src - jsnum.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 660 486 73.6 %
Date: 2012-04-07 Functions: 41 35 85.4 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  *
       3                 :  * ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla Communicator client code, released
      17                 :  * March 31, 1998.
      18                 :  *
      19                 :  * The Initial Developer of the Original Code is
      20                 :  * Netscape Communications Corporation.
      21                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      22                 :  * the Initial Developer. All Rights Reserved.
      23                 :  *
      24                 :  * Contributor(s):
      25                 :  *   IBM Corp.
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : /*
      42                 :  * JS number type and wrapper class.
      43                 :  */
      44                 : #ifdef XP_OS2
      45                 : #define _PC_53  PC_53
      46                 : #define _MCW_EM MCW_EM
      47                 : #define _MCW_PC MCW_PC
      48                 : #endif
      49                 : #include <locale.h>
      50                 : #include <limits.h>
      51                 : #include <math.h>
      52                 : #include <stdlib.h>
      53                 : #include <string.h>
      54                 : 
      55                 : #include "mozilla/RangedPtr.h"
      56                 : 
      57                 : #include "jstypes.h"
      58                 : #include "jsutil.h"
      59                 : #include "jsapi.h"
      60                 : #include "jsatom.h"
      61                 : #include "jscntxt.h"
      62                 : #include "jsversion.h"
      63                 : #include "jsdtoa.h"
      64                 : #include "jsgc.h"
      65                 : #include "jsinterp.h"
      66                 : #include "jsnum.h"
      67                 : #include "jsobj.h"
      68                 : #include "jsopcode.h"
      69                 : #include "jsprf.h"
      70                 : #include "jsscope.h"
      71                 : #include "jsstr.h"
      72                 : #include "jslibmath.h"
      73                 : 
      74                 : #include "vm/GlobalObject.h"
      75                 : #include "vm/MethodGuard.h"
      76                 : #include "vm/StringBuffer.h"
      77                 : 
      78                 : #include "jsatominlines.h"
      79                 : #include "jsinferinlines.h"
      80                 : #include "jsnuminlines.h"
      81                 : #include "jsobjinlines.h"
      82                 : 
      83                 : #include "vm/MethodGuard-inl.h"
      84                 : #include "vm/NumberObject-inl.h"
      85                 : #include "vm/String-inl.h"
      86                 : 
      87                 : using namespace js;
      88                 : using namespace js::types;
      89                 : 
      90                 : /*
      91                 :  * If we're accumulating a decimal number and the number is >= 2^53, then the
      92                 :  * fast result from the loop in GetPrefixInteger may be inaccurate. Call
      93                 :  * js_strtod_harder to get the correct answer.
      94                 :  */
      95                 : static bool
      96            1998 : ComputeAccurateDecimalInteger(JSContext *cx, const jschar *start, const jschar *end, double *dp)
      97                 : {
      98            1998 :     size_t length = end - start;
      99            1998 :     char *cstr = static_cast<char *>(cx->malloc_(length + 1));
     100            1998 :     if (!cstr)
     101               0 :         return false;
     102                 : 
     103           43623 :     for (size_t i = 0; i < length; i++) {
     104           41625 :         char c = char(start[i]);
     105           41625 :         JS_ASSERT(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'));
     106           41625 :         cstr[i] = c;
     107                 :     }
     108            1998 :     cstr[length] = 0;
     109                 : 
     110                 :     char *estr;
     111            1998 :     int err = 0;
     112            1998 :     *dp = js_strtod_harder(cx->runtime->dtoaState, cstr, &estr, &err);
     113            1998 :     if (err == JS_DTOA_ENOMEM) {
     114               0 :         JS_ReportOutOfMemory(cx);
     115               0 :         cx->free_(cstr);
     116               0 :         return false;
     117                 :     }
     118            1998 :     if (err == JS_DTOA_ERANGE && *dp == HUGE_VAL)
     119               0 :         *dp = js_PositiveInfinity;
     120            1998 :     cx->free_(cstr);
     121            1998 :     return true;
     122                 : }
     123                 : 
     124                 : class BinaryDigitReader
     125                 : {
     126                 :     const int base;      /* Base of number; must be a power of 2 */
     127                 :     int digit;           /* Current digit value in radix given by base */
     128                 :     int digitMask;       /* Mask to extract the next bit from digit */
     129                 :     const jschar *start; /* Pointer to the remaining digits */
     130                 :     const jschar *end;   /* Pointer to first non-digit */
     131                 : 
     132                 :   public:
     133               0 :     BinaryDigitReader(int base, const jschar *start, const jschar *end)
     134               0 :       : base(base), digit(0), digitMask(0), start(start), end(end)
     135                 :     {
     136               0 :     }
     137                 : 
     138                 :     /* Return the next binary digit from the number, or -1 if done. */
     139               0 :     int nextDigit() {
     140               0 :         if (digitMask == 0) {
     141               0 :             if (start == end)
     142               0 :                 return -1;
     143                 : 
     144               0 :             int c = *start++;
     145               0 :             JS_ASSERT(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'));
     146               0 :             if ('0' <= c && c <= '9')
     147               0 :                 digit = c - '0';
     148               0 :             else if ('a' <= c && c <= 'z')
     149               0 :                 digit = c - 'a' + 10;
     150                 :             else
     151               0 :                 digit = c - 'A' + 10;
     152               0 :             digitMask = base >> 1;
     153                 :         }
     154                 : 
     155               0 :         int bit = (digit & digitMask) != 0;
     156               0 :         digitMask >>= 1;
     157               0 :         return bit;
     158                 :     }
     159                 : };
     160                 : 
     161                 : /*
     162                 :  * The fast result might also have been inaccurate for power-of-two bases. This
     163                 :  * happens if the addition in value * 2 + digit causes a round-down to an even
     164                 :  * least significant mantissa bit when the first dropped bit is a one.  If any
     165                 :  * of the following digits in the number (which haven't been added in yet) are
     166                 :  * nonzero, then the correct action would have been to round up instead of
     167                 :  * down.  An example occurs when reading the number 0x1000000000000081, which
     168                 :  * rounds to 0x1000000000000000 instead of 0x1000000000000100.
     169                 :  */
     170                 : static double
     171               0 : ComputeAccurateBinaryBaseInteger(JSContext *cx, const jschar *start, const jschar *end, int base)
     172                 : {
     173               0 :     BinaryDigitReader bdr(base, start, end);
     174                 : 
     175                 :     /* Skip leading zeroes. */
     176                 :     int bit;
     177               0 :     do {
     178               0 :         bit = bdr.nextDigit();
     179                 :     } while (bit == 0);
     180                 : 
     181               0 :     JS_ASSERT(bit == 1); // guaranteed by GetPrefixInteger
     182                 : 
     183                 :     /* Gather the 53 significant bits (including the leading 1). */
     184               0 :     double value = 1.0;
     185               0 :     for (int j = 52; j > 0; j--) {
     186               0 :         bit = bdr.nextDigit();
     187               0 :         if (bit < 0)
     188               0 :             return value;
     189               0 :         value = value * 2 + bit;
     190                 :     }
     191                 : 
     192                 :     /* bit2 is the 54th bit (the first dropped from the mantissa). */
     193               0 :     int bit2 = bdr.nextDigit();
     194               0 :     if (bit2 >= 0) {
     195               0 :         double factor = 2.0;
     196               0 :         int sticky = 0;  /* sticky is 1 if any bit beyond the 54th is 1 */
     197                 :         int bit3;
     198                 : 
     199               0 :         while ((bit3 = bdr.nextDigit()) >= 0) {
     200               0 :             sticky |= bit3;
     201               0 :             factor *= 2;
     202                 :         }
     203               0 :         value += bit2 & (bit | sticky);
     204               0 :         value *= factor;
     205                 :     }
     206                 : 
     207               0 :     return value;
     208                 : }
     209                 : 
     210                 : namespace js {
     211                 : 
     212                 : bool
     213          564486 : GetPrefixInteger(JSContext *cx, const jschar *start, const jschar *end, int base,
     214                 :                  const jschar **endp, double *dp)
     215                 : {
     216          564486 :     JS_ASSERT(start <= end);
     217          564486 :     JS_ASSERT(2 <= base && base <= 36);
     218                 : 
     219          564486 :     const jschar *s = start;
     220          564486 :     double d = 0.0;
     221         1286642 :     for (; s < end; s++) {
     222                 :         int digit;
     223          865697 :         jschar c = *s;
     224          865697 :         if ('0' <= c && c <= '9')
     225          708818 :             digit = c - '0';
     226          156879 :         else if ('a' <= c && c <= 'z')
     227           14805 :             digit = c - 'a' + 10;
     228          142074 :         else if ('A' <= c && c <= 'Z')
     229            1395 :             digit = c - 'A' + 10;
     230                 :         else
     231          140679 :             break;
     232          725018 :         if (digit >= base)
     233            2862 :             break;
     234          722156 :         d = d * base + digit;
     235                 :     }
     236                 : 
     237          564486 :     *endp = s;
     238          564486 :     *dp = d;
     239                 : 
     240                 :     /* If we haven't reached the limit of integer precision, we're done. */
     241          564486 :     if (d < DOUBLE_INTEGRAL_PRECISION_LIMIT)
     242          562488 :         return true;
     243                 : 
     244                 :     /*
     245                 :      * Otherwise compute the correct integer from the prefix of valid digits
     246                 :      * if we're computing for base ten or a power of two.  Don't worry about
     247                 :      * other bases; see 15.1.2.2 step 13.
     248                 :      */
     249            1998 :     if (base == 10)
     250            1998 :         return ComputeAccurateDecimalInteger(cx, start, s, dp);
     251               0 :     if ((base & (base - 1)) == 0)
     252               0 :         *dp = ComputeAccurateBinaryBaseInteger(cx, start, s, base);
     253                 : 
     254               0 :     return true;
     255                 : }
     256                 : 
     257                 : } // namespace js
     258                 : 
     259                 : static JSBool
     260              63 : num_isNaN(JSContext *cx, unsigned argc, Value *vp)
     261                 : {
     262              63 :     if (argc == 0) {
     263               0 :         vp->setBoolean(true);
     264               0 :         return JS_TRUE;
     265                 :     }
     266                 :     double x;
     267              63 :     if (!ToNumber(cx, vp[2], &x))
     268               0 :         return false;
     269              63 :     vp->setBoolean(JSDOUBLE_IS_NaN(x));
     270              63 :     return JS_TRUE;
     271                 : }
     272                 : 
     273                 : static JSBool
     274               0 : num_isFinite(JSContext *cx, unsigned argc, Value *vp)
     275                 : {
     276               0 :     if (argc == 0) {
     277               0 :         vp->setBoolean(false);
     278               0 :         return JS_TRUE;
     279                 :     }
     280                 :     double x;
     281               0 :     if (!ToNumber(cx, vp[2], &x))
     282               0 :         return JS_FALSE;
     283               0 :     vp->setBoolean(JSDOUBLE_IS_FINITE(x));
     284               0 :     return JS_TRUE;
     285                 : }
     286                 : 
     287                 : static JSBool
     288            2025 : num_parseFloat(JSContext *cx, unsigned argc, Value *vp)
     289                 : {
     290                 :     JSString *str;
     291                 :     double d;
     292                 :     const jschar *bp, *end, *ep;
     293                 : 
     294            2025 :     if (argc == 0) {
     295               0 :         vp->setDouble(js_NaN);
     296               0 :         return JS_TRUE;
     297                 :     }
     298            2025 :     str = ToString(cx, vp[2]);
     299            2025 :     if (!str)
     300               0 :         return JS_FALSE;
     301            2025 :     bp = str->getChars(cx);
     302            2025 :     if (!bp)
     303               0 :         return JS_FALSE;
     304            2025 :     end = bp + str->length();
     305            2025 :     if (!js_strtod(cx, bp, end, &ep, &d))
     306               0 :         return JS_FALSE;
     307            2025 :     if (ep == bp) {
     308               0 :         vp->setDouble(js_NaN);
     309               0 :         return JS_TRUE;
     310                 :     }
     311            2025 :     vp->setNumber(d);
     312            2025 :     return JS_TRUE;
     313                 : }
     314                 : 
     315                 : static bool
     316          146358 : ParseIntStringHelper(JSContext *cx, const jschar *ws, const jschar *end, int maybeRadix,
     317                 :                      bool stripPrefix, double *dp)
     318                 : {
     319          146358 :     JS_ASSERT(maybeRadix == 0 || (2 <= maybeRadix && maybeRadix <= 36));
     320          146358 :     JS_ASSERT(ws <= end);
     321                 : 
     322          146358 :     const jschar *s = SkipSpace(ws, end);
     323          146358 :     JS_ASSERT(ws <= s);
     324          146358 :     JS_ASSERT(s <= end);
     325                 : 
     326                 :     /* 15.1.2.2 steps 3-4. */
     327          146358 :     bool negative = (s != end && s[0] == '-');
     328                 : 
     329                 :     /* 15.1.2.2 step 5. */
     330          146358 :     if (s != end && (s[0] == '-' || s[0] == '+'))
     331           71568 :         s++;
     332                 : 
     333                 :     /* 15.1.2.2 step 9. */
     334          146358 :     int radix = maybeRadix;
     335          146358 :     if (radix == 0) {
     336          145170 :         if (end - s >= 2 && s[0] == '0' && (s[1] != 'x' && s[1] != 'X')) {
     337                 :             /*
     338                 :              * Non-standard: ES5 requires that parseInt interpret leading-zero
     339                 :              * strings not starting with "0x" or "0X" as decimal (absent an
     340                 :              * explicitly specified non-zero radix), but we continue to
     341                 :              * interpret such strings as octal, as per ES3 and web practice.
     342                 :              */
     343             513 :             radix = 8;
     344                 :         } else {
     345          144657 :             radix = 10;
     346                 :         }
     347                 :     }
     348                 : 
     349                 :     /* 15.1.2.2 step 10. */
     350          146358 :     if (stripPrefix) {
     351          145224 :         if (end - s >= 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
     352              54 :             s += 2;
     353              54 :             radix = 16;
     354                 :         }
     355                 :     }
     356                 : 
     357                 :     /* 15.1.2.2 steps 11-14. */
     358                 :     const jschar *actualEnd;
     359          146358 :     if (!GetPrefixInteger(cx, s, end, radix, &actualEnd, dp))
     360               0 :         return false;
     361          146358 :     if (s == actualEnd)
     362             576 :         *dp = js_NaN;
     363          145782 :     else if (negative)
     364           71550 :         *dp = -*dp;
     365          146358 :     return true;
     366                 : }
     367                 : 
     368                 : /* See ECMA 15.1.2.2. */
     369                 : JSBool
     370          201446 : js::num_parseInt(JSContext *cx, unsigned argc, Value *vp)
     371                 : {
     372          201446 :     CallArgs args = CallArgsFromVp(argc, vp);
     373                 : 
     374                 :     /* Fast paths and exceptional cases. */
     375          201446 :     if (args.length() == 0) {
     376               0 :         args.rval().setDouble(js_NaN);
     377               0 :         return true;
     378                 :     }
     379                 : 
     380          213588 :     if (args.length() == 1 || 
     381           12142 :         (args[1].isInt32() && (args[1].toInt32() == 0 || args[1].toInt32() == 10))) {
     382          201392 :         if (args[0].isInt32()) {
     383            3077 :             args.rval() = args[0];
     384            3077 :             return true;
     385                 :         }
     386                 :         /*
     387                 :          * Step 1 is |inputString = ToString(string)|. When string >=
     388                 :          * 1e21, ToString(string) is in the form "NeM". 'e' marks the end of
     389                 :          * the word, which would mean the result of parseInt(string) should be |N|.
     390                 :          *
     391                 :          * To preserve this behaviour, we can't use the fast-path when string >
     392                 :          * 1e21, or else the result would be |NeM|.
     393                 :          * 
     394                 :          * The same goes for values smaller than 1.0e-6, because the string would be in
     395                 :          * the form of "Ne-M".
     396                 :          */
     397          198315 :         if (args[0].isDouble()) {
     398          124812 :             double d = args[0].toDouble();
     399          124812 :             if (1.0e-6 < d && d < 1.0e21) {
     400           50283 :                 args.rval().setNumber(floor(d));
     401           50283 :                 return true;
     402                 :             }
     403           74529 :             if (-1.0e21 < d && d < -1.0e-6) {
     404            1656 :                 args.rval().setNumber(-floor(-d));
     405            1656 :                 return true;
     406                 :             }
     407           72873 :             if (d == 0.0) {
     408              72 :                 args.rval().setInt32(0);
     409              72 :                 return true;
     410                 :             }
     411                 :         }
     412                 :     }
     413                 : 
     414                 :     /* Step 1. */
     415          146358 :     JSString *inputString = ToString(cx, args[0]);
     416          146358 :     if (!inputString)
     417               0 :         return false;
     418          146358 :     args[0].setString(inputString);
     419                 : 
     420                 :     /* 15.1.2.2 steps 6-8. */
     421          146358 :     bool stripPrefix = true;
     422          146358 :     int32_t radix = 0;
     423          146358 :     if (args.length() > 1) {
     424            1773 :         if (!ToInt32(cx, args[1], &radix))
     425               0 :             return false;
     426            1773 :         if (radix != 0) {
     427            1188 :             if (radix < 2 || radix > 36) {
     428               0 :                 args.rval().setDouble(js_NaN);
     429               0 :                 return true;
     430                 :             }
     431            1188 :             if (radix != 16)
     432            1134 :                 stripPrefix = false;
     433                 :         }
     434                 :     }
     435                 : 
     436                 :     /* Steps 2-5, 9-14. */
     437          146358 :     const jschar *ws = inputString->getChars(cx);
     438          146358 :     if (!ws)
     439               0 :         return false;
     440          146358 :     const jschar *end = ws + inputString->length();
     441                 : 
     442                 :     double number;
     443          146358 :     if (!ParseIntStringHelper(cx, ws, end, radix, stripPrefix, &number))
     444               0 :         return false;
     445                 : 
     446                 :     /* Step 15. */
     447          146358 :     args.rval().setNumber(number);
     448          146358 :     return true;
     449                 : }
     450                 : 
     451                 : const char js_isNaN_str[]      = "isNaN";
     452                 : const char js_isFinite_str[]   = "isFinite";
     453                 : const char js_parseFloat_str[] = "parseFloat";
     454                 : const char js_parseInt_str[]   = "parseInt";
     455                 : 
     456                 : static JSFunctionSpec number_functions[] = {
     457                 :     JS_FN(js_isNaN_str,         num_isNaN,           1,0),
     458                 :     JS_FN(js_isFinite_str,      num_isFinite,        1,0),
     459                 :     JS_FN(js_parseFloat_str,    num_parseFloat,      1,0),
     460                 :     JS_FN(js_parseInt_str,      num_parseInt,        2,0),
     461                 :     JS_FS_END
     462                 : };
     463                 : 
     464                 : Class js::NumberClass = {
     465                 :     js_Number_str,
     466                 :     JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number),
     467                 :     JS_PropertyStub,         /* addProperty */
     468                 :     JS_PropertyStub,         /* delProperty */
     469                 :     JS_PropertyStub,         /* getProperty */
     470                 :     JS_StrictPropertyStub,   /* setProperty */
     471                 :     JS_EnumerateStub,
     472                 :     JS_ResolveStub,
     473                 :     JS_ConvertStub
     474                 : };
     475                 : 
     476                 : static JSBool
     477           16400 : Number(JSContext *cx, unsigned argc, Value *vp)
     478                 : {
     479                 :     /* Sample JS_CALLEE before clobbering. */
     480           16400 :     bool isConstructing = IsConstructing(vp);
     481                 : 
     482           16400 :     if (argc > 0) {
     483           16373 :         if (!ToNumber(cx, &vp[2]))
     484               0 :             return false;
     485           16373 :         vp[0] = vp[2];
     486                 :     } else {
     487              27 :         vp[0].setInt32(0);
     488                 :     }
     489                 : 
     490           16400 :     if (!isConstructing)
     491           16085 :         return true;
     492                 : 
     493             315 :     JSObject *obj = NumberObject::create(cx, vp[0].toNumber());
     494             315 :     if (!obj)
     495               0 :         return false;
     496             315 :     vp->setObject(*obj);
     497             315 :     return true;
     498                 : }
     499                 : 
     500                 : #if JS_HAS_TOSOURCE
     501                 : static JSBool
     502             144 : num_toSource(JSContext *cx, unsigned argc, Value *vp)
     503                 : {
     504             144 :     CallArgs args = CallArgsFromVp(argc, vp);
     505                 : 
     506                 :     double d;
     507                 :     bool ok;
     508             144 :     if (!BoxedPrimitiveMethodGuard(cx, args, num_toSource, &d, &ok))
     509              63 :         return ok;
     510                 : 
     511             162 :     StringBuffer sb(cx);
     512             162 :     if (!sb.append("(new Number(") || !NumberValueToStringBuffer(cx, NumberValue(d), sb) ||
     513              81 :         !sb.append("))"))
     514                 :     {
     515               0 :         return false;
     516                 :     }
     517                 : 
     518              81 :     JSString *str = sb.finishString();
     519              81 :     if (!str)
     520               0 :         return false;
     521              81 :     args.rval().setString(str);
     522              81 :     return true;
     523                 : }
     524                 : #endif
     525                 : 
     526         3163377 : ToCStringBuf::ToCStringBuf() :dbuf(NULL)
     527                 : {
     528                 :     JS_STATIC_ASSERT(sbufSize >= DTOSTR_STANDARD_BUFFER_SIZE);
     529         3163377 : }
     530                 : 
     531         3163377 : ToCStringBuf::~ToCStringBuf()
     532                 : {
     533         3163377 :     if (dbuf)
     534               0 :         UnwantedForeground::free_(dbuf);
     535         3163377 : }
     536                 : 
     537                 : JSString * JS_FASTCALL
     538        39744150 : js_IntToString(JSContext *cx, int32_t si)
     539                 : {
     540                 :     uint32_t ui;
     541        39744150 :     if (si >= 0) {
     542        39723860 :         if (StaticStrings::hasInt(si))
     543          840795 :             return cx->runtime->staticStrings.getInt(si);
     544        38883065 :         ui = si;
     545                 :     } else {
     546           20290 :         ui = uint32_t(-si);
     547           20290 :         JS_ASSERT_IF(si == INT32_MIN, ui == uint32_t(INT32_MAX) + 1);
     548                 :     }
     549                 : 
     550        38903355 :     JSCompartment *c = cx->compartment;
     551        38903355 :     if (JSString *str = c->dtoaCache.lookup(10, si))
     552           87750 :         return str;
     553                 : 
     554        38815605 :     JSShortString *str = js_NewGCShortString(cx);
     555        38815605 :     if (!str)
     556               9 :         return NULL;
     557                 : 
     558        38815596 :     jschar *storage = str->inlineStorageBeforeInit();
     559                 :     RangedPtr<jschar> end(storage + JSShortString::MAX_SHORT_LENGTH,
     560        38815596 :                           storage, JSShortString::MAX_SHORT_LENGTH + 1);
     561        38815596 :     *end = '\0';
     562                 : 
     563        38815596 :     RangedPtr<jschar> start = BackfillIndexInCharBuffer(ui, end);
     564                 : 
     565        38815596 :     if (si < 0)
     566            5183 :         *--start = '-';
     567                 : 
     568        38815596 :     str->initAtOffsetInBuffer(start.get(), end - start);
     569                 : 
     570        38815596 :     c->dtoaCache.cache(10, si, str);
     571        38815596 :     return str;
     572                 : }
     573                 : 
     574                 : /* Returns a non-NULL pointer to inside cbuf.  */
     575                 : static char *
     576          138701 : IntToCString(ToCStringBuf *cbuf, int i, int base = 10)
     577                 : {
     578          138701 :     unsigned u = (i < 0) ? -i : i;
     579                 : 
     580          138701 :     RangedPtr<char> cp(cbuf->sbuf + cbuf->sbufSize - 1, cbuf->sbuf, cbuf->sbufSize);
     581          138701 :     *cp = '\0';
     582                 : 
     583                 :     /* Build the string from behind. */
     584          138701 :     switch (base) {
     585                 :     case 10:
     586          136127 :       cp = BackfillIndexInCharBuffer(u, cp);
     587          136127 :       break;
     588                 :     case 16:
     589            5580 :       do {
     590            5580 :           unsigned newu = u / 16;
     591            5580 :           *--cp = "0123456789abcdef"[u - newu * 16];
     592            5580 :           u = newu;
     593                 :       } while (u != 0);
     594            2340 :       break;
     595                 :     default:
     596             234 :       JS_ASSERT(base >= 2 && base <= 36);
     597            1449 :       do {
     598            1449 :           unsigned newu = u / base;
     599            1449 :           *--cp = "0123456789abcdefghijklmnopqrstuvwxyz"[u - newu * base];
     600            1449 :           u = newu;
     601                 :       } while (u != 0);
     602             234 :       break;
     603                 :     }
     604          138701 :     if (i < 0)
     605           29366 :         *--cp = '-';
     606                 : 
     607          138701 :     return cp.get();
     608                 : }
     609                 : 
     610                 : static JSString * JS_FASTCALL
     611                 : js_NumberToStringWithBase(JSContext *cx, double d, int base);
     612                 : 
     613                 : static JS_ALWAYS_INLINE bool
     614          153126 : num_toStringHelper(JSContext *cx, Native native, unsigned argc, Value *vp)
     615                 : {
     616          153126 :     CallArgs args = CallArgsFromVp(argc, vp);
     617                 : 
     618                 :     double d;
     619                 :     bool ok;
     620          153126 :     if (!BoxedPrimitiveMethodGuard(cx, args, native, &d, &ok))
     621             135 :         return ok;
     622                 : 
     623          152991 :     int32_t base = 10;
     624          152991 :     if (args.hasDefined(0)) {
     625                 :         double d2;
     626          148635 :         if (!ToInteger(cx, args[0], &d2))
     627               0 :             return false;
     628                 : 
     629          148635 :         if (d2 < 2 || d2 > 36) {
     630               0 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX);
     631               0 :             return false;
     632                 :         }
     633                 : 
     634          148635 :         base = int32_t(d2);
     635                 :     }
     636          152991 :     JSString *str = js_NumberToStringWithBase(cx, d, base);
     637          152991 :     if (!str) {
     638               0 :         JS_ReportOutOfMemory(cx);
     639               0 :         return false;
     640                 :     }
     641          152991 :     args.rval().setString(str);
     642          152991 :     return true;
     643                 : }
     644                 : 
     645                 : static JSBool
     646          153018 : num_toString(JSContext *cx, unsigned argc, Value *vp)
     647                 : {
     648          153018 :     return num_toStringHelper(cx, num_toString, argc, vp);
     649                 : }
     650                 : 
     651                 : static JSBool
     652              18 : num_toLocaleString(JSContext *cx, unsigned argc, Value *vp)
     653                 : {
     654                 :     size_t thousandsLength, decimalLength;
     655                 :     const char *numGrouping, *tmpGroup;
     656                 :     JSRuntime *rt;
     657                 :     JSString *str;
     658                 :     const char *num, *end, *tmpSrc;
     659                 :     char *buf, *tmpDest;
     660                 :     const char *nint;
     661                 :     int digits, buflen, remainder, nrepeat;
     662                 : 
     663                 :     /*
     664                 :      * Create the string, move back to bytes to make string twiddling
     665                 :      * a bit easier and so we can insert platform charset seperators.
     666                 :      */
     667              18 :     if (!num_toStringHelper(cx, num_toLocaleString, 0, vp))
     668               9 :         return JS_FALSE;
     669               9 :     JS_ASSERT(vp->isString());
     670              18 :     JSAutoByteString numBytes(cx, vp->toString());
     671               9 :     if (!numBytes)
     672               0 :         return JS_FALSE;
     673               9 :     num = numBytes.ptr();
     674               9 :     if (!num)
     675               0 :         return JS_FALSE;
     676                 : 
     677                 :     /*
     678                 :      * Find the first non-integer value, whether it be a letter as in
     679                 :      * 'Infinity', a decimal point, or an 'e' from exponential notation.
     680                 :      */
     681               9 :     nint = num;
     682               9 :     if (*nint == '-')
     683               0 :         nint++;
     684              27 :     while (*nint >= '0' && *nint <= '9')
     685               9 :         nint++;
     686               9 :     digits = nint - num;
     687               9 :     end = num + digits;
     688               9 :     if (!digits)
     689               0 :         return JS_TRUE;
     690                 : 
     691               9 :     rt = cx->runtime;
     692               9 :     thousandsLength = strlen(rt->thousandsSeparator);
     693               9 :     decimalLength = strlen(rt->decimalSeparator);
     694                 : 
     695                 :     /* Figure out how long resulting string will be. */
     696               9 :     buflen = strlen(num);
     697               9 :     if (*nint == '.')
     698               9 :         buflen += decimalLength - 1; /* -1 to account for existing '.' */
     699                 : 
     700               9 :     numGrouping = tmpGroup = rt->numGrouping;
     701               9 :     remainder = digits;
     702               9 :     if (*num == '-')
     703               0 :         remainder--;
     704                 : 
     705              18 :     while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') {
     706               9 :         if (*tmpGroup >= remainder)
     707               9 :             break;
     708               0 :         buflen += thousandsLength;
     709               0 :         remainder -= *tmpGroup;
     710               0 :         tmpGroup++;
     711                 :     }
     712               9 :     if (*tmpGroup == '\0' && *numGrouping != '\0') {
     713               0 :         nrepeat = (remainder - 1) / tmpGroup[-1];
     714               0 :         buflen += thousandsLength * nrepeat;
     715               0 :         remainder -= nrepeat * tmpGroup[-1];
     716                 :     } else {
     717               9 :         nrepeat = 0;
     718                 :     }
     719               9 :     tmpGroup--;
     720                 : 
     721               9 :     buf = (char *)cx->malloc_(buflen + 1);
     722               9 :     if (!buf)
     723               0 :         return JS_FALSE;
     724                 : 
     725               9 :     tmpDest = buf;
     726               9 :     tmpSrc = num;
     727                 : 
     728              27 :     while (*tmpSrc == '-' || remainder--) {
     729               9 :         JS_ASSERT(tmpDest - buf < buflen);
     730               9 :         *tmpDest++ = *tmpSrc++;
     731                 :     }
     732              18 :     while (tmpSrc < end) {
     733               0 :         JS_ASSERT(tmpDest - buf + ptrdiff_t(thousandsLength) <= buflen);
     734               0 :         strcpy(tmpDest, rt->thousandsSeparator);
     735               0 :         tmpDest += thousandsLength;
     736               0 :         JS_ASSERT(tmpDest - buf + *tmpGroup <= buflen);
     737               0 :         js_memcpy(tmpDest, tmpSrc, *tmpGroup);
     738               0 :         tmpDest += *tmpGroup;
     739               0 :         tmpSrc += *tmpGroup;
     740               0 :         if (--nrepeat < 0)
     741               0 :             tmpGroup--;
     742                 :     }
     743                 : 
     744               9 :     if (*nint == '.') {
     745               9 :         JS_ASSERT(tmpDest - buf + ptrdiff_t(decimalLength) <= buflen);
     746               9 :         strcpy(tmpDest, rt->decimalSeparator);
     747               9 :         tmpDest += decimalLength;
     748               9 :         JS_ASSERT(tmpDest - buf + ptrdiff_t(strlen(nint + 1)) <= buflen);
     749               9 :         strcpy(tmpDest, nint + 1);
     750                 :     } else {
     751               0 :         JS_ASSERT(tmpDest - buf + ptrdiff_t(strlen(nint)) <= buflen);
     752               0 :         strcpy(tmpDest, nint);
     753                 :     }
     754                 : 
     755               9 :     if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode) {
     756               0 :         JSBool ok = cx->localeCallbacks->localeToUnicode(cx, buf, vp);
     757               0 :         cx->free_(buf);
     758               0 :         return ok;
     759                 :     }
     760                 : 
     761               9 :     str = js_NewStringCopyN(cx, buf, buflen);
     762               9 :     cx->free_(buf);
     763               9 :     if (!str)
     764               0 :         return JS_FALSE;
     765                 : 
     766               9 :     vp->setString(str);
     767               9 :     return JS_TRUE;
     768                 : }
     769                 : 
     770                 : JSBool
     771              99 : js_num_valueOf(JSContext *cx, unsigned argc, Value *vp)
     772                 : {
     773              99 :     CallArgs args = CallArgsFromVp(argc, vp);
     774                 : 
     775                 :     double d;
     776                 :     bool ok;
     777              99 :     if (!BoxedPrimitiveMethodGuard(cx, args, js_num_valueOf, &d, &ok))
     778              63 :         return ok;
     779                 : 
     780              36 :     args.rval().setNumber(d);
     781              36 :     return true;
     782                 : }
     783                 : 
     784                 : 
     785                 : #define MAX_PRECISION 100
     786                 : 
     787                 : static JSBool
     788             180 : num_to(JSContext *cx, Native native, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode,
     789                 :        int precisionMin, int precisionMax, int precisionOffset,
     790                 :        CallArgs args)
     791                 : {
     792                 :     /* Use MAX_PRECISION+1 because precisionOffset can be 1. */
     793                 :     char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)];
     794                 :     char *numStr;
     795                 : 
     796                 :     double d;
     797                 :     bool ok;
     798             180 :     if (!BoxedPrimitiveMethodGuard(cx, args, native, &d, &ok))
     799             126 :         return ok;
     800                 : 
     801                 :     double precision;
     802              54 :     if (args.length() == 0) {
     803              54 :         precision = 0.0;
     804              54 :         oneArgMode = zeroArgMode;
     805                 :     } else {
     806               0 :         if (!ToInteger(cx, args[0], &precision))
     807               0 :             return false;
     808               0 :         if (precision < precisionMin || precision > precisionMax) {
     809               0 :             ToCStringBuf cbuf;
     810               0 :             numStr = IntToCString(&cbuf, int(precision));
     811               0 :             JS_ASSERT(numStr);
     812               0 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PRECISION_RANGE, numStr);
     813               0 :             return JS_FALSE;
     814                 :         }
     815                 :     }
     816                 : 
     817                 :     numStr = js_dtostr(cx->runtime->dtoaState, buf, sizeof buf,
     818              54 :                        oneArgMode, (int)precision + precisionOffset, d);
     819              54 :     if (!numStr) {
     820               0 :         JS_ReportOutOfMemory(cx);
     821               0 :         return JS_FALSE;
     822                 :     }
     823              54 :     JSString *str = js_NewStringCopyZ(cx, numStr);
     824              54 :     if (!str)
     825               0 :         return JS_FALSE;
     826              54 :     args.rval().setString(str);
     827              54 :     return JS_TRUE;
     828                 : }
     829                 : 
     830                 : /*
     831                 :  * In the following three implementations, we allow a larger range of precision
     832                 :  * than ECMA requires; this is permitted by ECMA-262.
     833                 :  */
     834                 : static JSBool
     835              90 : num_toFixed(JSContext *cx, unsigned argc, Value *vp)
     836                 : {
     837                 :     return num_to(cx, num_toFixed, DTOSTR_FIXED, DTOSTR_FIXED, -20, MAX_PRECISION, 0,
     838              90 :                   CallArgsFromVp(argc, vp));
     839                 : }
     840                 : 
     841                 : static JSBool
     842              90 : num_toExponential(JSContext *cx, unsigned argc, Value *vp)
     843                 : {
     844                 :     return num_to(cx, num_toExponential, DTOSTR_STANDARD_EXPONENTIAL, DTOSTR_EXPONENTIAL, 0,
     845              90 :                   MAX_PRECISION, 1, CallArgsFromVp(argc, vp));
     846                 : }
     847                 : 
     848                 : static JSBool
     849              90 : num_toPrecision(JSContext *cx, unsigned argc, Value *vp)
     850                 : {
     851              90 :     CallArgs args = CallArgsFromVp(argc, vp);
     852              90 :     if (!args.hasDefined(0))
     853              90 :         return num_toStringHelper(cx, num_toPrecision, 0, vp);
     854                 :     return num_to(cx, num_toPrecision, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0,
     855               0 :                   args);
     856                 : }
     857                 : 
     858                 : static JSFunctionSpec number_methods[] = {
     859                 : #if JS_HAS_TOSOURCE
     860                 :     JS_FN(js_toSource_str,       num_toSource,          0, 0),
     861                 : #endif
     862                 :     JS_FN(js_toString_str,       num_toString,          1, 0),
     863                 :     JS_FN(js_toLocaleString_str, num_toLocaleString,    0, 0),
     864                 :     JS_FN(js_valueOf_str,        js_num_valueOf,        0, 0),
     865                 :     JS_FN("toFixed",             num_toFixed,           1, 0),
     866                 :     JS_FN("toExponential",       num_toExponential,     1, 0),
     867                 :     JS_FN("toPrecision",         num_toPrecision,       1, 0),
     868                 :     JS_FS_END
     869                 : };
     870                 : 
     871                 : /* NB: Keep this in synch with number_constants[]. */
     872                 : enum nc_slot {
     873                 :     NC_NaN,
     874                 :     NC_POSITIVE_INFINITY,
     875                 :     NC_NEGATIVE_INFINITY,
     876                 :     NC_MAX_VALUE,
     877                 :     NC_MIN_VALUE,
     878                 :     NC_LIMIT
     879                 : };
     880                 : 
     881                 : /*
     882                 :  * Some to most C compilers forbid spelling these at compile time, or barf
     883                 :  * if you try, so all but MAX_VALUE are set up by InitRuntimeNumberState
     884                 :  * using union jsdpun.
     885                 :  */
     886                 : static JSConstDoubleSpec number_constants[] = {
     887                 :     {0,                         "NaN",               0,{0,0,0}},
     888                 :     {0,                         "POSITIVE_INFINITY", 0,{0,0,0}},
     889                 :     {0,                         "NEGATIVE_INFINITY", 0,{0,0,0}},
     890                 :     {1.7976931348623157E+308,   "MAX_VALUE",         0,{0,0,0}},
     891                 :     {0,                         "MIN_VALUE",         0,{0,0,0}},
     892                 :     {0,0,0,{0,0,0}}
     893                 : };
     894                 : 
     895                 : double js_NaN;
     896                 : double js_PositiveInfinity;
     897                 : double js_NegativeInfinity;
     898                 : 
     899                 : #if (defined __GNUC__ && defined __i386__) || \
     900                 :     (defined __SUNPRO_CC && defined __i386)
     901                 : 
     902                 : /*
     903                 :  * Set the exception mask to mask all exceptions and set the FPU precision
     904                 :  * to 53 bit mantissa (64 bit doubles).
     905                 :  */
     906           20777 : inline void FIX_FPU() {
     907                 :     short control;
     908           20777 :     asm("fstcw %0" : "=m" (control) : );
     909           20777 :     control &= ~0x300; // Lower bits 8 and 9 (precision control).
     910           20777 :     control |= 0x2f3;  // Raise bits 0-5 (exception masks) and 9 (64-bit precision).
     911           20777 :     asm("fldcw %0" : : "m" (control) );
     912           20777 : }
     913                 : 
     914                 : #else
     915                 : 
     916                 : #define FIX_FPU() ((void)0)
     917                 : 
     918                 : #endif
     919                 : 
     920                 : namespace js {
     921                 : 
     922                 : bool
     923           18761 : InitRuntimeNumberState(JSRuntime *rt)
     924                 : {
     925           18761 :     FIX_FPU();
     926                 : 
     927                 :     jsdpun u;
     928           18761 :     u.s.hi = JSDOUBLE_HI32_NAN;
     929           18761 :     u.s.lo = JSDOUBLE_LO32_NAN;
     930           18761 :     number_constants[NC_NaN].dval = js_NaN = u.d;
     931           18761 :     rt->NaNValue.setDouble(u.d);
     932                 : 
     933           18761 :     u.s.hi = JSDOUBLE_HI32_EXPMASK;
     934           18761 :     u.s.lo = 0x00000000;
     935           18761 :     number_constants[NC_POSITIVE_INFINITY].dval = js_PositiveInfinity = u.d;
     936           18761 :     rt->positiveInfinityValue.setDouble(u.d);
     937                 : 
     938           18761 :     u.s.hi = JSDOUBLE_HI32_SIGNBIT | JSDOUBLE_HI32_EXPMASK;
     939           18761 :     u.s.lo = 0x00000000;
     940           18761 :     number_constants[NC_NEGATIVE_INFINITY].dval = js_NegativeInfinity = u.d;
     941           18761 :     rt->negativeInfinityValue.setDouble(u.d);
     942                 : 
     943           18761 :     u.s.hi = 0;
     944           18761 :     u.s.lo = 1;
     945           18761 :     number_constants[NC_MIN_VALUE].dval = u.d;
     946                 : 
     947                 :     /* Copy locale-specific separators into the runtime strings. */
     948                 :     const char *thousandsSeparator, *decimalPoint, *grouping;
     949                 : #ifdef HAVE_LOCALECONV
     950           18761 :     struct lconv *locale = localeconv();
     951           18761 :     thousandsSeparator = locale->thousands_sep;
     952           18761 :     decimalPoint = locale->decimal_point;
     953           18761 :     grouping = locale->grouping;
     954                 : #else
     955                 :     thousandsSeparator = getenv("LOCALE_THOUSANDS_SEP");
     956                 :     decimalPoint = getenv("LOCALE_DECIMAL_POINT");
     957                 :     grouping = getenv("LOCALE_GROUPING");
     958                 : #endif
     959           18761 :     if (!thousandsSeparator)
     960               0 :         thousandsSeparator = "'";
     961           18761 :     if (!decimalPoint)
     962               0 :         decimalPoint = ".";
     963           18761 :     if (!grouping)
     964               0 :         grouping = "\3\0";
     965                 : 
     966                 :     /*
     967                 :      * We use single malloc to get the memory for all separator and grouping
     968                 :      * strings.
     969                 :      */
     970           18761 :     size_t thousandsSeparatorSize = strlen(thousandsSeparator) + 1;
     971           18761 :     size_t decimalPointSize = strlen(decimalPoint) + 1;
     972           18761 :     size_t groupingSize = strlen(grouping) + 1;
     973                 : 
     974                 :     char *storage = static_cast<char *>(OffTheBooks::malloc_(thousandsSeparatorSize +
     975                 :                                                              decimalPointSize +
     976           18761 :                                                              groupingSize));
     977           18761 :     if (!storage)
     978               0 :         return false;
     979                 : 
     980           18761 :     js_memcpy(storage, thousandsSeparator, thousandsSeparatorSize);
     981           18761 :     rt->thousandsSeparator = storage;
     982           18761 :     storage += thousandsSeparatorSize;
     983                 : 
     984           18761 :     js_memcpy(storage, decimalPoint, decimalPointSize);
     985           18761 :     rt->decimalSeparator = storage;
     986           18761 :     storage += decimalPointSize;
     987                 : 
     988           18761 :     js_memcpy(storage, grouping, groupingSize);
     989           18761 :     rt->numGrouping = grouping;
     990           18761 :     return true;
     991                 : }
     992                 : 
     993                 : void
     994           18761 : FinishRuntimeNumberState(JSRuntime *rt)
     995                 : {
     996                 :     /*
     997                 :      * The free also releases the memory for decimalSeparator and numGrouping
     998                 :      * strings.
     999                 :      */
    1000           18761 :     char *storage = const_cast<char *>(rt->thousandsSeparator);
    1001           18761 :     Foreground::free_(storage);
    1002           18761 : }
    1003                 : 
    1004                 : } /* namespace js */
    1005                 : 
    1006                 : JSObject *
    1007            2016 : js_InitNumberClass(JSContext *cx, JSObject *obj)
    1008                 : {
    1009            2016 :     JS_ASSERT(obj->isNative());
    1010                 : 
    1011                 :     /* XXX must do at least once per new thread, so do it per JSContext... */
    1012            2016 :     FIX_FPU();
    1013                 : 
    1014            2016 :     GlobalObject *global = &obj->asGlobal();
    1015                 : 
    1016            2016 :     JSObject *numberProto = global->createBlankPrototype(cx, &NumberClass);
    1017            2016 :     if (!numberProto)
    1018               0 :         return NULL;
    1019            2016 :     numberProto->asNumber().setPrimitiveValue(0);
    1020                 : 
    1021            2016 :     JSFunction *ctor = global->createConstructor(cx, Number, CLASS_ATOM(cx, Number), 1);
    1022            2016 :     if (!ctor)
    1023               0 :         return NULL;
    1024                 : 
    1025            2016 :     if (!LinkConstructorAndPrototype(cx, ctor, numberProto))
    1026               0 :         return NULL;
    1027                 : 
    1028                 :     /* Add numeric constants (MAX_VALUE, NaN, &c.) to the Number constructor. */
    1029            2016 :     if (!JS_DefineConstDoubles(cx, ctor, number_constants))
    1030               0 :         return NULL;
    1031                 : 
    1032            2016 :     if (!DefinePropertiesAndBrand(cx, numberProto, NULL, number_methods))
    1033               0 :         return NULL;
    1034                 : 
    1035            2016 :     if (!JS_DefineFunctions(cx, global, number_functions))
    1036               0 :         return NULL;
    1037                 : 
    1038                 :     /* ES5 15.1.1.1, 15.1.1.2 */
    1039            6048 :     if (!DefineNativeProperty(cx, global, ATOM_TO_JSID(cx->runtime->atomState.NaNAtom),
    1040                 :                               cx->runtime->NaNValue, JS_PropertyStub, JS_StrictPropertyStub,
    1041            4032 :                               JSPROP_PERMANENT | JSPROP_READONLY, 0, 0) ||
    1042            2016 :         !DefineNativeProperty(cx, global, ATOM_TO_JSID(cx->runtime->atomState.InfinityAtom),
    1043                 :                               cx->runtime->positiveInfinityValue,
    1044                 :                               JS_PropertyStub, JS_StrictPropertyStub,
    1045            4032 :                               JSPROP_PERMANENT | JSPROP_READONLY, 0, 0))
    1046                 :     {
    1047               0 :         return NULL;
    1048                 :     }
    1049                 : 
    1050            2016 :     if (!DefineConstructorAndPrototype(cx, global, JSProto_Number, ctor, numberProto))
    1051               0 :         return NULL;
    1052                 : 
    1053            2016 :     return numberProto;
    1054                 : }
    1055                 : 
    1056                 : namespace v8 {
    1057                 : namespace internal {
    1058                 : extern char* DoubleToCString(double v, char* buffer, int buflen);
    1059                 : }
    1060                 : }
    1061                 : 
    1062                 : namespace js {
    1063                 : 
    1064                 : static char *
    1065          234994 : FracNumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, int base = 10)
    1066                 : {
    1067                 : #ifdef DEBUG
    1068                 :     {
    1069                 :         int32_t _;
    1070          234994 :         JS_ASSERT(!JSDOUBLE_IS_INT32(d, &_));
    1071                 :     }
    1072                 : #endif
    1073                 : 
    1074                 :     char* numStr;
    1075          234994 :     if (base == 10) {
    1076                 :         /*
    1077                 :          * This is V8's implementation of the algorithm described in the
    1078                 :          * following paper:
    1079                 :          *
    1080                 :          *   Printing floating-point numbers quickly and accurately with integers.
    1081                 :          *   Florian Loitsch, PLDI 2010.
    1082                 :          *
    1083                 :          * It fails on a small number of cases, whereupon we fall back to
    1084                 :          * js_dtostr() (which uses David Gay's dtoa).
    1085                 :          */
    1086          234994 :         numStr = v8::internal::DoubleToCString(d, cbuf->sbuf, cbuf->sbufSize);
    1087          234994 :         if (!numStr)
    1088                 :             numStr = js_dtostr(cx->runtime->dtoaState, cbuf->sbuf, cbuf->sbufSize,
    1089           13448 :                                DTOSTR_STANDARD, 0, d);
    1090                 :     } else {
    1091               0 :         numStr = cbuf->dbuf = js_dtobasestr(cx->runtime->dtoaState, base, d);
    1092                 :     }
    1093          234994 :     return numStr;
    1094                 : }
    1095                 : 
    1096                 : char *
    1097           69883 : NumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, int base/* = 10*/)
    1098                 : {
    1099                 :     int32_t i;
    1100           69883 :     return (JSDOUBLE_IS_INT32(d, &i))
    1101           39544 :            ? IntToCString(cbuf, i, base)
    1102          109427 :            : FracNumberToCString(cx, cbuf, d, base);
    1103                 : }
    1104                 : 
    1105                 : }
    1106                 : 
    1107                 : static JSString * JS_FASTCALL
    1108         3001603 : js_NumberToStringWithBase(JSContext *cx, double d, int base)
    1109                 : {
    1110         6003206 :     ToCStringBuf cbuf;
    1111                 :     char *numStr;
    1112                 : 
    1113                 :     /*
    1114                 :      * Caller is responsible for error reporting. When called from trace,
    1115                 :      * returning NULL here will cause us to fall of trace and then retry
    1116                 :      * from the interpreter (which will report the error).
    1117                 :      */
    1118         3001603 :     if (base < 2 || base > 36)
    1119               0 :         return NULL;
    1120                 : 
    1121         3001603 :     JSCompartment *c = cx->compartment;
    1122                 : 
    1123                 :     int32_t i;
    1124         3001603 :     if (JSDOUBLE_IS_INT32(d, &i)) {
    1125          163514 :         if (base == 10 && StaticStrings::hasInt(i))
    1126            9007 :             return cx->runtime->staticStrings.getInt(i);
    1127          154507 :         if (unsigned(i) < unsigned(base)) {
    1128          145845 :             if (i < 10)
    1129           58221 :                 return cx->runtime->staticStrings.getInt(i);
    1130           87624 :             jschar c = 'a' + i - 10;
    1131           87624 :             JS_ASSERT(StaticStrings::hasUnit(c));
    1132           87624 :             return cx->runtime->staticStrings.getUnit(c);
    1133                 :         }
    1134                 : 
    1135            8662 :         if (JSFlatString *str = c->dtoaCache.lookup(base, d))
    1136            1396 :             return str;
    1137                 : 
    1138            7266 :         numStr = IntToCString(&cbuf, i, base);
    1139            7266 :         JS_ASSERT(!cbuf.dbuf && numStr >= cbuf.sbuf && numStr < cbuf.sbuf + cbuf.sbufSize);
    1140                 :     } else {
    1141         2838089 :         if (JSFlatString *str = c->dtoaCache.lookup(base, d))
    1142         2633434 :             return str;
    1143                 : 
    1144          204655 :         numStr = FracNumberToCString(cx, &cbuf, d, base);
    1145          204655 :         if (!numStr) {
    1146               0 :             JS_ReportOutOfMemory(cx);
    1147               0 :             return NULL;
    1148                 :         }
    1149          409310 :         JS_ASSERT_IF(base == 10,
    1150          613965 :                      !cbuf.dbuf && numStr >= cbuf.sbuf && numStr < cbuf.sbuf + cbuf.sbufSize);
    1151               0 :         JS_ASSERT_IF(base != 10,
    1152          204655 :                      cbuf.dbuf && cbuf.dbuf == numStr);
    1153                 :     }
    1154                 : 
    1155          211921 :     JSFixedString *s = js_NewStringCopyZ(cx, numStr);
    1156          211921 :     c->dtoaCache.cache(base, d, s);
    1157          211921 :     return s;
    1158                 : }
    1159                 : 
    1160                 : JSString * JS_FASTCALL
    1161         2848612 : js_NumberToString(JSContext *cx, double d)
    1162                 : {
    1163         2848612 :     return js_NumberToStringWithBase(cx, d, 10);
    1164                 : }
    1165                 : 
    1166                 : namespace js {
    1167                 : 
    1168                 : JSFixedString *
    1169               0 : NumberToString(JSContext *cx, double d)
    1170                 : {
    1171               0 :     if (JSString *str = js_NumberToStringWithBase(cx, d, 10))
    1172               0 :         return &str->asFixed();
    1173               0 :     return NULL;
    1174                 : }
    1175                 : 
    1176                 : JSFixedString *
    1177              52 : IndexToString(JSContext *cx, uint32_t index)
    1178                 : {
    1179              52 :     if (StaticStrings::hasUint(index))
    1180              22 :         return cx->runtime->staticStrings.getUint(index);
    1181                 : 
    1182              30 :     JSCompartment *c = cx->compartment;
    1183              30 :     if (JSFixedString *str = c->dtoaCache.lookup(10, index))
    1184               0 :         return str;
    1185                 : 
    1186              30 :     JSShortString *str = js_NewGCShortString(cx);
    1187              30 :     if (!str)
    1188               0 :         return NULL;
    1189                 : 
    1190              30 :     jschar *storage = str->inlineStorageBeforeInit();
    1191              30 :     size_t length = JSShortString::MAX_SHORT_LENGTH;
    1192              30 :     const RangedPtr<jschar> end(storage + length, storage, length + 1);
    1193              30 :     *end = '\0';
    1194                 : 
    1195              30 :     RangedPtr<jschar> start = BackfillIndexInCharBuffer(index, end);
    1196                 : 
    1197              30 :     str->initAtOffsetInBuffer(start.get(), end - start);
    1198                 : 
    1199              30 :     c->dtoaCache.cache(10, index, str);
    1200              30 :     return str;
    1201                 : }
    1202                 : 
    1203                 : bool JS_FASTCALL
    1204          161774 : NumberValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb)
    1205                 : {
    1206                 :     /* Convert to C-string. */
    1207          323548 :     ToCStringBuf cbuf;
    1208                 :     const char *cstr;
    1209          161774 :     if (v.isInt32()) {
    1210           91891 :         cstr = IntToCString(&cbuf, v.toInt32());
    1211                 :     } else {
    1212           69883 :         cstr = NumberToCString(cx, &cbuf, v.toDouble());
    1213           69883 :         if (!cstr) {
    1214               0 :             JS_ReportOutOfMemory(cx);
    1215               0 :             return JS_FALSE;
    1216                 :         }
    1217                 :     }
    1218                 : 
    1219                 :     /*
    1220                 :      * Inflate to jschar string.  The input C-string characters are < 127, so
    1221                 :      * even if jschars are UTF-8, all chars should map to one jschar.
    1222                 :      */
    1223          161774 :     size_t cstrlen = strlen(cstr);
    1224          161774 :     JS_ASSERT(!cbuf.dbuf && cstrlen < cbuf.sbufSize);
    1225          161774 :     return sb.appendInflated(cstr, cstrlen);
    1226                 : }
    1227                 : 
    1228                 : JS_PUBLIC_API(bool)
    1229         1201174 : ToNumberSlow(JSContext *cx, Value v, double *out)
    1230                 : {
    1231         1201174 :     JS_ASSERT(!v.isNumber());
    1232         1201174 :     goto skip_int_double;
    1233                 :     for (;;) {
    1234          259497 :         if (v.isNumber()) {
    1235            3825 :             *out = v.toNumber();
    1236            3825 :             return true;
    1237                 :         }
    1238                 :       skip_int_double:
    1239         1456846 :         if (v.isString())
    1240          680866 :             return StringToNumberType<double>(cx, v.toString(), out);
    1241          775980 :         if (v.isBoolean()) {
    1242           91404 :             if (v.toBoolean()) {
    1243           67838 :                 *out = 1.0;
    1244           67838 :                 return true;
    1245                 :             }
    1246           23566 :             *out = 0.0;
    1247           23566 :             return true;
    1248                 :         }
    1249          684576 :         if (v.isNull()) {
    1250           10508 :             *out = 0.0;
    1251           10508 :             return true;
    1252                 :         }
    1253          674068 :         if (v.isUndefined())
    1254          414526 :             break;
    1255                 : 
    1256          259542 :         JS_ASSERT(v.isObject());
    1257          259542 :         if (!ToPrimitive(cx, JSTYPE_NUMBER, &v))
    1258              45 :             return false;
    1259          259497 :         if (v.isObject())
    1260               0 :             break;
    1261                 :     }
    1262                 : 
    1263          414526 :     *out = js_NaN;
    1264          414526 :     return true;
    1265                 : }
    1266                 : 
    1267                 : JS_PUBLIC_API(bool)
    1268         1684200 : ToInt32Slow(JSContext *cx, const Value &v, int32_t *out)
    1269                 : {
    1270         1684200 :     JS_ASSERT(!v.isInt32());
    1271                 :     double d;
    1272         1684200 :     if (v.isDouble()) {
    1273         1068600 :         d = v.toDouble();
    1274                 :     } else {
    1275          615600 :         if (!ToNumberSlow(cx, v, &d))
    1276              27 :             return false;
    1277                 :     }
    1278         1684173 :     *out = js_DoubleToECMAInt32(d);
    1279         1684173 :     return true;
    1280                 : }
    1281                 : 
    1282                 : bool
    1283            2125 : ToUint32Slow(JSContext *cx, const Value &v, uint32_t *out)
    1284                 : {
    1285            2125 :     JS_ASSERT(!v.isInt32());
    1286                 :     double d;
    1287            2125 :     if (v.isDouble()) {
    1288            1702 :         d = v.toDouble();
    1289                 :     } else {
    1290             423 :         if (!ToNumberSlow(cx, v, &d))
    1291               0 :             return false;
    1292                 :     }
    1293            2125 :     *out = js_DoubleToECMAUint32(d);
    1294            2125 :     return true;
    1295                 : }
    1296                 : 
    1297                 : }  /* namespace js */
    1298                 : 
    1299                 : namespace js {
    1300                 : 
    1301                 : bool
    1302               0 : NonstandardToInt32Slow(JSContext *cx, const Value &v, int32_t *out)
    1303                 : {
    1304               0 :     JS_ASSERT(!v.isInt32());
    1305                 :     double d;
    1306               0 :     if (v.isDouble()) {
    1307               0 :         d = v.toDouble();
    1308               0 :     } else if (!ToNumberSlow(cx, v, &d)) {
    1309               0 :         return false;
    1310                 :     }
    1311                 : 
    1312               0 :     if (JSDOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) {
    1313                 :         js_ReportValueError(cx, JSMSG_CANT_CONVERT,
    1314               0 :                             JSDVG_SEARCH_STACK, v, NULL);
    1315               0 :         return false;
    1316                 :     }
    1317               0 :     *out = (int32_t) floor(d + 0.5);  /* Round to nearest */
    1318               0 :     return true;
    1319                 : }
    1320                 : 
    1321                 : bool
    1322             576 : ValueToUint16Slow(JSContext *cx, const Value &v, uint16_t *out)
    1323                 : {
    1324             576 :     JS_ASSERT(!v.isInt32());
    1325                 :     double d;
    1326             576 :     if (v.isDouble()) {
    1327               0 :         d = v.toDouble();
    1328             576 :     } else if (!ToNumberSlow(cx, v, &d)) {
    1329               9 :         return false;
    1330                 :     }
    1331                 : 
    1332             567 :     if (d == 0 || !JSDOUBLE_IS_FINITE(d)) {
    1333              90 :         *out = 0;
    1334              90 :         return true;
    1335                 :     }
    1336                 : 
    1337             477 :     uint16_t u = (uint16_t) d;
    1338             477 :     if ((double)u == d) {
    1339             477 :         *out = u;
    1340             477 :         return true;
    1341                 :     }
    1342                 : 
    1343               0 :     bool neg = (d < 0);
    1344               0 :     d = floor(neg ? -d : d);
    1345               0 :     d = neg ? -d : d;
    1346               0 :     unsigned m = JS_BIT(16);
    1347               0 :     d = fmod(d, (double) m);
    1348               0 :     if (d < 0)
    1349               0 :         d += m;
    1350               0 :     *out = (uint16_t) d;
    1351               0 :     return true;
    1352                 : }
    1353                 : 
    1354                 : }  /* namespace js */
    1355                 : 
    1356                 : JSBool
    1357          607405 : js_strtod(JSContext *cx, const jschar *s, const jschar *send,
    1358                 :           const jschar **ep, double *dp)
    1359                 : {
    1360                 :     size_t i;
    1361                 :     char cbuf[32];
    1362                 :     char *cstr, *istr, *estr;
    1363                 :     JSBool negative;
    1364                 :     double d;
    1365                 : 
    1366          607405 :     const jschar *s1 = SkipSpace(s, send);
    1367          607405 :     size_t length = send - s1;
    1368                 : 
    1369                 :     /* Use cbuf to avoid malloc */
    1370          607405 :     if (length >= sizeof cbuf) {
    1371          254232 :         cstr = (char *) cx->malloc_(length + 1);
    1372          254232 :         if (!cstr)
    1373               0 :            return JS_FALSE;
    1374                 :     } else {
    1375          353173 :         cstr = cbuf;
    1376                 :     }
    1377                 : 
    1378        64952153 :     for (i = 0; i != length; i++) {
    1379        64344748 :         if (s1[i] >> 8)
    1380               0 :             break;
    1381        64344748 :         cstr[i] = (char)s1[i];
    1382                 :     }
    1383          607405 :     cstr[i] = 0;
    1384                 : 
    1385          607405 :     istr = cstr;
    1386          607405 :     if ((negative = (*istr == '-')) != 0 || *istr == '+')
    1387             306 :         istr++;
    1388          607405 :     if (*istr == 'I' && !strncmp(istr, "Infinity", 8)) {
    1389             172 :         d = negative ? js_NegativeInfinity : js_PositiveInfinity;
    1390             172 :         estr = istr + 8;
    1391                 :     } else {
    1392                 :         int err;
    1393          607233 :         d = js_strtod_harder(cx->runtime->dtoaState, cstr, &estr, &err);
    1394          607233 :         if (d == HUGE_VAL)
    1395              10 :             d = js_PositiveInfinity;
    1396          607223 :         else if (d == -HUGE_VAL)
    1397               0 :             d = js_NegativeInfinity;
    1398                 :     }
    1399                 : 
    1400          607405 :     i = estr - cstr;
    1401          607405 :     if (cstr != cbuf)
    1402          254232 :         cx->free_(cstr);
    1403          607405 :     *ep = i ? s1 + i : s;
    1404          607405 :     *dp = d;
    1405          607405 :     return JS_TRUE;
    1406                 : }

Generated by: LCOV version 1.7