LCOV - code coverage report
Current view: directory - js/src - jsnum.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 660 535 81.1 %
Date: 2012-06-02 Functions: 41 38 92.7 %

       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                 : 
      77                 : #include "jsatominlines.h"
      78                 : #include "jsinferinlines.h"
      79                 : #include "jsnuminlines.h"
      80                 : #include "jsobjinlines.h"
      81                 : 
      82                 : #include "vm/MethodGuard-inl.h"
      83                 : #include "vm/NumberObject-inl.h"
      84                 : #include "vm/String-inl.h"
      85                 : #include "vm/StringBuffer-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            2009 : ComputeAccurateDecimalInteger(JSContext *cx, const jschar *start, const jschar *end, double *dp)
      97                 : {
      98            2009 :     size_t length = end - start;
      99            2009 :     char *cstr = static_cast<char *>(cx->malloc_(length + 1));
     100            2009 :     if (!cstr)
     101               0 :         return false;
     102                 : 
     103           43845 :     for (size_t i = 0; i < length; i++) {
     104           41836 :         char c = char(start[i]);
     105           41836 :         JS_ASSERT(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'));
     106           41836 :         cstr[i] = c;
     107                 :     }
     108            2009 :     cstr[length] = 0;
     109                 : 
     110                 :     char *estr;
     111            2009 :     int err = 0;
     112            2009 :     *dp = js_strtod_harder(cx->runtime->dtoaState, cstr, &estr, &err);
     113            2009 :     if (err == JS_DTOA_ENOMEM) {
     114               0 :         JS_ReportOutOfMemory(cx);
     115               0 :         cx->free_(cstr);
     116               0 :         return false;
     117                 :     }
     118            2009 :     if (err == JS_DTOA_ERANGE && *dp == HUGE_VAL)
     119               0 :         *dp = js_PositiveInfinity;
     120            2009 :     cx->free_(cstr);
     121            2009 :     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              24 :     BinaryDigitReader(int base, const jschar *start, const jschar *end)
     134              24 :       : base(base), digit(0), digitMask(0), start(start), end(end)
     135                 :     {
     136              24 :     }
     137                 : 
     138                 :     /* Return the next binary digit from the number, or -1 if done. */
     139            1564 :     int nextDigit() {
     140            1564 :         if (digitMask == 0) {
     141             409 :             if (start == end)
     142              24 :                 return -1;
     143                 : 
     144             385 :             int c = *start++;
     145             385 :             JS_ASSERT(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'));
     146             385 :             if ('0' <= c && c <= '9')
     147             209 :                 digit = c - '0';
     148             176 :             else if ('a' <= c && c <= 'z')
     149             176 :                 digit = c - 'a' + 10;
     150                 :             else
     151               0 :                 digit = c - 'A' + 10;
     152             385 :             digitMask = base >> 1;
     153                 :         }
     154                 : 
     155            1540 :         int bit = (digit & digitMask) != 0;
     156            1540 :         digitMask >>= 1;
     157            1540 :         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              24 : ComputeAccurateBinaryBaseInteger(JSContext *cx, const jschar *start, const jschar *end, int base)
     172                 : {
     173              24 :     BinaryDigitReader bdr(base, start, end);
     174                 : 
     175                 :     /* Skip leading zeroes. */
     176                 :     int bit;
     177              40 :     do {
     178              40 :         bit = bdr.nextDigit();
     179                 :     } while (bit == 0);
     180                 : 
     181              24 :     JS_ASSERT(bit == 1); // guaranteed by GetPrefixInteger
     182                 : 
     183                 :     /* Gather the 53 significant bits (including the leading 1). */
     184              24 :     double value = 1.0;
     185            1272 :     for (int j = 52; j > 0; j--) {
     186            1248 :         bit = bdr.nextDigit();
     187            1248 :         if (bit < 0)
     188               0 :             return value;
     189            1248 :         value = value * 2 + bit;
     190                 :     }
     191                 : 
     192                 :     /* bit2 is the 54th bit (the first dropped from the mantissa). */
     193              24 :     int bit2 = bdr.nextDigit();
     194              24 :     if (bit2 >= 0) {
     195              24 :         double factor = 2.0;
     196              24 :         int sticky = 0;  /* sticky is 1 if any bit beyond the 54th is 1 */
     197                 :         int bit3;
     198                 : 
     199             276 :         while ((bit3 = bdr.nextDigit()) >= 0) {
     200             228 :             sticky |= bit3;
     201             228 :             factor *= 2;
     202                 :         }
     203              24 :         value += bit2 & (bit | sticky);
     204              24 :         value *= factor;
     205                 :     }
     206                 : 
     207              24 :     return value;
     208                 : }
     209                 : 
     210                 : namespace js {
     211                 : 
     212                 : bool
     213         6130705 : GetPrefixInteger(JSContext *cx, const jschar *start, const jschar *end, int base,
     214                 :                  const jschar **endp, double *dp)
     215                 : {
     216         6130705 :     JS_ASSERT(start <= end);
     217         6130705 :     JS_ASSERT(2 <= base && base <= 36);
     218                 : 
     219         6130705 :     const jschar *s = start;
     220         6130705 :     double d = 0.0;
     221        18675206 :     for (; s < end; s++) {
     222                 :         int digit;
     223        12688238 :         jschar c = *s;
     224        12688238 :         if ('0' <= c && c <= '9')
     225        12519828 :             digit = c - '0';
     226          168410 :         else if ('a' <= c && c <= 'z')
     227           26045 :             digit = c - 'a' + 10;
     228          142365 :         else if ('A' <= c && c <= 'Z')
     229            1662 :             digit = c - 'A' + 10;
     230                 :         else
     231          140703 :             break;
     232        12547535 :         if (digit >= base)
     233            3034 :             break;
     234        12544501 :         d = d * base + digit;
     235                 :     }
     236                 : 
     237         6130705 :     *endp = s;
     238         6130705 :     *dp = d;
     239                 : 
     240                 :     /* If we haven't reached the limit of integer precision, we're done. */
     241         6130705 :     if (d < DOUBLE_INTEGRAL_PRECISION_LIMIT)
     242         6128672 :         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            2033 :     if (base == 10)
     250            2009 :         return ComputeAccurateDecimalInteger(cx, start, s, dp);
     251              24 :     if ((base & (base - 1)) == 0)
     252              24 :         *dp = ComputeAccurateBinaryBaseInteger(cx, start, s, base);
     253                 : 
     254              24 :     return true;
     255                 : }
     256                 : 
     257                 : } // namespace js
     258                 : 
     259                 : static JSBool
     260            7663 : num_isNaN(JSContext *cx, unsigned argc, Value *vp)
     261                 : {
     262            7663 :     if (argc == 0) {
     263               0 :         vp->setBoolean(true);
     264               0 :         return JS_TRUE;
     265                 :     }
     266                 :     double x;
     267            7663 :     if (!ToNumber(cx, vp[2], &x))
     268               0 :         return false;
     269            7663 :     vp->setBoolean(JSDOUBLE_IS_NaN(x));
     270            7663 :     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            3431 : num_parseFloat(JSContext *cx, unsigned argc, Value *vp)
     289                 : {
     290                 :     JSString *str;
     291                 :     double d;
     292                 :     const jschar *bp, *end, *ep;
     293                 : 
     294            3431 :     if (argc == 0) {
     295               0 :         vp->setDouble(js_NaN);
     296               0 :         return JS_TRUE;
     297                 :     }
     298            3431 :     str = ToString(cx, vp[2]);
     299            3431 :     if (!str)
     300               0 :         return JS_FALSE;
     301            3431 :     bp = str->getChars(cx);
     302            3431 :     if (!bp)
     303               0 :         return JS_FALSE;
     304            3431 :     end = bp + str->length();
     305            3431 :     if (!js_strtod(cx, bp, end, &ep, &d))
     306               0 :         return JS_FALSE;
     307            3431 :     if (ep == bp) {
     308               1 :         vp->setDouble(js_NaN);
     309               1 :         return JS_TRUE;
     310                 :     }
     311            3430 :     vp->setNumber(d);
     312            3430 :     return JS_TRUE;
     313                 : }
     314                 : 
     315                 : static bool
     316          164346 : ParseIntStringHelper(JSContext *cx, const jschar *ws, const jschar *end, int maybeRadix,
     317                 :                      bool stripPrefix, double *dp)
     318                 : {
     319          164346 :     JS_ASSERT(maybeRadix == 0 || (2 <= maybeRadix && maybeRadix <= 36));
     320          164346 :     JS_ASSERT(ws <= end);
     321                 : 
     322          164346 :     const jschar *s = SkipSpace(ws, end);
     323          164346 :     JS_ASSERT(ws <= s);
     324          164346 :     JS_ASSERT(s <= end);
     325                 : 
     326                 :     /* 15.1.2.2 steps 3-4. */
     327          164346 :     bool negative = (s != end && s[0] == '-');
     328                 : 
     329                 :     /* 15.1.2.2 step 5. */
     330          164346 :     if (s != end && (s[0] == '-' || s[0] == '+'))
     331           71598 :         s++;
     332                 : 
     333                 :     /* 15.1.2.2 step 9. */
     334          164346 :     int radix = maybeRadix;
     335          164346 :     if (radix == 0) {
     336          148152 :         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             517 :             radix = 8;
     344                 :         } else {
     345          147635 :             radix = 10;
     346                 :         }
     347                 :     }
     348                 : 
     349                 :     /* 15.1.2.2 step 10. */
     350          164346 :     if (stripPrefix) {
     351          155227 :         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          164346 :     if (!GetPrefixInteger(cx, s, end, radix, &actualEnd, dp))
     360               0 :         return false;
     361          164346 :     if (s == actualEnd)
     362             752 :         *dp = js_NaN;
     363          163594 :     else if (negative)
     364           71580 :         *dp = -*dp;
     365          164346 :     return true;
     366                 : }
     367                 : 
     368                 : /* See ECMA 15.1.2.2. */
     369                 : JSBool
     370          219736 : js::num_parseInt(JSContext *cx, unsigned argc, Value *vp)
     371                 : {
     372          219736 :     CallArgs args = CallArgsFromVp(argc, vp);
     373                 : 
     374                 :     /* Fast paths and exceptional cases. */
     375          219736 :     if (args.length() == 0) {
     376               0 :         args.rval().setDouble(js_NaN);
     377               0 :         return true;
     378                 :     }
     379                 : 
     380          276911 :     if (args.length() == 1 || 
     381           57175 :         (args[1].isInt32() && (args[1].toInt32() == 0 || args[1].toInt32() == 10))) {
     382          212434 :         if (args[0].isInt32()) {
     383            3199 :             args.rval() = args[0];
     384            3199 :             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          209235 :         if (args[0].isDouble()) {
     398          124992 :             double d = args[0].toDouble();
     399          124992 :             if (1.0e-6 < d && d < 1.0e21) {
     400           50463 :                 args.rval().setNumber(floor(d));
     401           50463 :                 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          164346 :     JSString *inputString = ToString(cx, args[0]);
     416          164346 :     if (!inputString)
     417               0 :         return false;
     418          164346 :     args[0].setString(inputString);
     419                 : 
     420                 :     /* 15.1.2.2 steps 6-8. */
     421          164346 :     bool stripPrefix = true;
     422          164346 :     int32_t radix = 0;
     423          164346 :     if (args.length() > 1) {
     424           16779 :         if (!ToInt32(cx, args[1], &radix))
     425               0 :             return false;
     426           16779 :         if (radix != 0) {
     427           16194 :             if (radix < 2 || radix > 36) {
     428               0 :                 args.rval().setDouble(js_NaN);
     429               0 :                 return true;
     430                 :             }
     431           16194 :             if (radix != 16)
     432            9119 :                 stripPrefix = false;
     433                 :         }
     434                 :     }
     435                 : 
     436                 :     /* Steps 2-5, 9-14. */
     437          164346 :     const jschar *ws = inputString->getChars(cx);
     438          164346 :     if (!ws)
     439               0 :         return false;
     440          164346 :     const jschar *end = ws + inputString->length();
     441                 : 
     442                 :     double number;
     443          164346 :     if (!ParseIntStringHelper(cx, ws, end, radix, stripPrefix, &number))
     444               0 :         return false;
     445                 : 
     446                 :     /* Step 15. */
     447          164346 :     args.rval().setNumber(number);
     448          164346 :     return true;
     449                 : }
     450                 : 
     451                 : const char js_Infinity_str[]   = "Infinity";
     452                 : const char js_NaN_str[]        = "NaN";
     453                 : const char js_isNaN_str[]      = "isNaN";
     454                 : const char js_isFinite_str[]   = "isFinite";
     455                 : const char js_parseFloat_str[] = "parseFloat";
     456                 : const char js_parseInt_str[]   = "parseInt";
     457                 : 
     458                 : static JSFunctionSpec number_functions[] = {
     459                 :     JS_FN(js_isNaN_str,         num_isNaN,           1,0),
     460                 :     JS_FN(js_isFinite_str,      num_isFinite,        1,0),
     461                 :     JS_FN(js_parseFloat_str,    num_parseFloat,      1,0),
     462                 :     JS_FN(js_parseInt_str,      num_parseInt,        2,0),
     463                 :     JS_FS_END
     464                 : };
     465                 : 
     466                 : Class js::NumberClass = {
     467                 :     js_Number_str,
     468                 :     JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number),
     469                 :     JS_PropertyStub,         /* addProperty */
     470                 :     JS_PropertyStub,         /* delProperty */
     471                 :     JS_PropertyStub,         /* getProperty */
     472                 :     JS_StrictPropertyStub,   /* setProperty */
     473                 :     JS_EnumerateStub,
     474                 :     JS_ResolveStub,
     475                 :     JS_ConvertStub
     476                 : };
     477                 : 
     478                 : static JSBool
     479           22581 : Number(JSContext *cx, unsigned argc, Value *vp)
     480                 : {
     481                 :     /* Sample JS_CALLEE before clobbering. */
     482           22581 :     bool isConstructing = IsConstructing(vp);
     483                 : 
     484           22581 :     if (argc > 0) {
     485           22554 :         if (!ToNumber(cx, &vp[2]))
     486               0 :             return false;
     487           22554 :         vp[0] = vp[2];
     488                 :     } else {
     489              27 :         vp[0].setInt32(0);
     490                 :     }
     491                 : 
     492           22581 :     if (!isConstructing)
     493           21832 :         return true;
     494                 : 
     495             749 :     JSObject *obj = NumberObject::create(cx, vp[0].toNumber());
     496             749 :     if (!obj)
     497               0 :         return false;
     498             749 :     vp->setObject(*obj);
     499             749 :     return true;
     500                 : }
     501                 : 
     502                 : #if JS_HAS_TOSOURCE
     503                 : static JSBool
     504             180 : num_toSource(JSContext *cx, unsigned argc, Value *vp)
     505                 : {
     506             180 :     CallArgs args = CallArgsFromVp(argc, vp);
     507                 : 
     508                 :     double d;
     509                 :     bool ok;
     510             180 :     if (!BoxedPrimitiveMethodGuard(cx, args, num_toSource, &d, &ok))
     511              63 :         return ok;
     512                 : 
     513             234 :     StringBuffer sb(cx);
     514             234 :     if (!sb.append("(new Number(") || !NumberValueToStringBuffer(cx, NumberValue(d), sb) ||
     515             117 :         !sb.append("))"))
     516                 :     {
     517               0 :         return false;
     518                 :     }
     519                 : 
     520             117 :     JSString *str = sb.finishString();
     521             117 :     if (!str)
     522               0 :         return false;
     523             117 :     args.rval().setString(str);
     524             117 :     return true;
     525                 : }
     526                 : #endif
     527                 : 
     528         3803388 : ToCStringBuf::ToCStringBuf() :dbuf(NULL)
     529                 : {
     530                 :     JS_STATIC_ASSERT(sbufSize >= DTOSTR_STANDARD_BUFFER_SIZE);
     531         3803388 : }
     532                 : 
     533         3803388 : ToCStringBuf::~ToCStringBuf()
     534                 : {
     535         3803388 :     if (dbuf)
     536             326 :         UnwantedForeground::free_(dbuf);
     537         3803388 : }
     538                 : 
     539                 : JSString * JS_FASTCALL
     540        46150849 : js_IntToString(JSContext *cx, int32_t si)
     541                 : {
     542                 :     uint32_t ui;
     543        46150849 :     if (si >= 0) {
     544        46126567 :         if (StaticStrings::hasInt(si))
     545         3607643 :             return cx->runtime->staticStrings.getInt(si);
     546        42518924 :         ui = si;
     547                 :     } else {
     548           24282 :         ui = uint32_t(-si);
     549           24282 :         JS_ASSERT_IF(si == INT32_MIN, ui == uint32_t(INT32_MAX) + 1);
     550                 :     }
     551                 : 
     552        42543206 :     JSCompartment *c = cx->compartment;
     553        42543206 :     if (JSString *str = c->dtoaCache.lookup(10, si))
     554          115053 :         return str;
     555                 : 
     556        42428153 :     JSShortString *str = js_NewGCShortString(cx);
     557        42428153 :     if (!str)
     558               9 :         return NULL;
     559                 : 
     560        42428144 :     jschar *storage = str->inlineStorageBeforeInit();
     561                 :     RangedPtr<jschar> end(storage + JSShortString::MAX_SHORT_LENGTH,
     562        42428144 :                           storage, JSShortString::MAX_SHORT_LENGTH + 1);
     563        42428144 :     *end = '\0';
     564                 : 
     565        42428144 :     RangedPtr<jschar> start = BackfillIndexInCharBuffer(ui, end);
     566                 : 
     567        42428144 :     if (si < 0)
     568            5836 :         *--start = '-';
     569                 : 
     570        42428144 :     str->initAtOffsetInBuffer(start.get(), end - start);
     571                 : 
     572        42428144 :     c->dtoaCache.cache(10, si, str);
     573        42428144 :     return str;
     574                 : }
     575                 : 
     576                 : /* Returns a non-NULL pointer to inside cbuf.  */
     577                 : static char *
     578          688668 : IntToCString(ToCStringBuf *cbuf, int i, int base = 10)
     579                 : {
     580          688668 :     unsigned u = (i < 0) ? -i : i;
     581                 : 
     582          688668 :     RangedPtr<char> cp(cbuf->sbuf + cbuf->sbufSize - 1, cbuf->sbuf, cbuf->sbufSize);
     583          688668 :     *cp = '\0';
     584                 : 
     585                 :     /* Build the string from behind. */
     586          688668 :     switch (base) {
     587                 :     case 10:
     588          636646 :       cp = BackfillIndexInCharBuffer(u, cp);
     589          636646 :       break;
     590                 :     case 16:
     591          104016 :       do {
     592          104016 :           unsigned newu = u / 16;
     593          104016 :           *--cp = "0123456789abcdef"[u - newu * 16];
     594          104016 :           u = newu;
     595                 :       } while (u != 0);
     596           51558 :       break;
     597                 :     default:
     598             464 :       JS_ASSERT(base >= 2 && base <= 36);
     599            2166 :       do {
     600            2166 :           unsigned newu = u / base;
     601            2166 :           *--cp = "0123456789abcdefghijklmnopqrstuvwxyz"[u - newu * base];
     602            2166 :           u = newu;
     603                 :       } while (u != 0);
     604             464 :       break;
     605                 :     }
     606          688668 :     if (i < 0)
     607           29433 :         *--cp = '-';
     608                 : 
     609          688668 :     return cp.get();
     610                 : }
     611                 : 
     612                 : static JSString * JS_FASTCALL
     613                 : js_NumberToStringWithBase(JSContext *cx, double d, int base);
     614                 : 
     615                 : static JS_ALWAYS_INLINE bool
     616          245877 : num_toStringHelper(JSContext *cx, Native native, unsigned argc, Value *vp)
     617                 : {
     618          245877 :     CallArgs args = CallArgsFromVp(argc, vp);
     619                 : 
     620                 :     double d;
     621                 :     bool ok;
     622          245877 :     if (!BoxedPrimitiveMethodGuard(cx, args, native, &d, &ok))
     623             135 :         return ok;
     624                 : 
     625          245742 :     int32_t base = 10;
     626          245742 :     if (args.hasDefined(0)) {
     627                 :         double d2;
     628          233108 :         if (!ToInteger(cx, args[0], &d2))
     629               0 :             return false;
     630                 : 
     631          233108 :         if (d2 < 2 || d2 > 36) {
     632               0 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX);
     633               0 :             return false;
     634                 :         }
     635                 : 
     636          233108 :         base = int32_t(d2);
     637                 :     }
     638          245742 :     JSString *str = js_NumberToStringWithBase(cx, d, base);
     639          245742 :     if (!str) {
     640               0 :         JS_ReportOutOfMemory(cx);
     641               0 :         return false;
     642                 :     }
     643          245742 :     args.rval().setString(str);
     644          245742 :     return true;
     645                 : }
     646                 : 
     647                 : static JSBool
     648          245766 : num_toString(JSContext *cx, unsigned argc, Value *vp)
     649                 : {
     650          245766 :     return num_toStringHelper(cx, num_toString, argc, vp);
     651                 : }
     652                 : 
     653                 : static JSBool
     654              21 : num_toLocaleString(JSContext *cx, unsigned argc, Value *vp)
     655                 : {
     656                 :     size_t thousandsLength, decimalLength;
     657                 :     const char *numGrouping, *tmpGroup;
     658                 :     JSRuntime *rt;
     659                 :     JSString *str;
     660                 :     const char *num, *end, *tmpSrc;
     661                 :     char *buf, *tmpDest;
     662                 :     const char *nint;
     663                 :     int digits, buflen, remainder, nrepeat;
     664                 : 
     665                 :     /*
     666                 :      * Create the string, move back to bytes to make string twiddling
     667                 :      * a bit easier and so we can insert platform charset seperators.
     668                 :      */
     669              21 :     if (!num_toStringHelper(cx, num_toLocaleString, 0, vp))
     670               9 :         return JS_FALSE;
     671              12 :     JS_ASSERT(vp->isString());
     672              24 :     JSAutoByteString numBytes(cx, vp->toString());
     673              12 :     if (!numBytes)
     674               0 :         return JS_FALSE;
     675              12 :     num = numBytes.ptr();
     676              12 :     if (!num)
     677               0 :         return JS_FALSE;
     678                 : 
     679                 :     /*
     680                 :      * Find the first non-integer value, whether it be a letter as in
     681                 :      * 'Infinity', a decimal point, or an 'e' from exponential notation.
     682                 :      */
     683              12 :     nint = num;
     684              12 :     if (*nint == '-')
     685               0 :         nint++;
     686              36 :     while (*nint >= '0' && *nint <= '9')
     687              12 :         nint++;
     688              12 :     digits = nint - num;
     689              12 :     end = num + digits;
     690              12 :     if (!digits)
     691               0 :         return JS_TRUE;
     692                 : 
     693              12 :     rt = cx->runtime;
     694              12 :     thousandsLength = strlen(rt->thousandsSeparator);
     695              12 :     decimalLength = strlen(rt->decimalSeparator);
     696                 : 
     697                 :     /* Figure out how long resulting string will be. */
     698              12 :     buflen = strlen(num);
     699              12 :     if (*nint == '.')
     700              12 :         buflen += decimalLength - 1; /* -1 to account for existing '.' */
     701                 : 
     702              12 :     numGrouping = tmpGroup = rt->numGrouping;
     703              12 :     remainder = digits;
     704              12 :     if (*num == '-')
     705               0 :         remainder--;
     706                 : 
     707              24 :     while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') {
     708              12 :         if (*tmpGroup >= remainder)
     709              12 :             break;
     710               0 :         buflen += thousandsLength;
     711               0 :         remainder -= *tmpGroup;
     712               0 :         tmpGroup++;
     713                 :     }
     714              12 :     if (*tmpGroup == '\0' && *numGrouping != '\0') {
     715               0 :         nrepeat = (remainder - 1) / tmpGroup[-1];
     716               0 :         buflen += thousandsLength * nrepeat;
     717               0 :         remainder -= nrepeat * tmpGroup[-1];
     718                 :     } else {
     719              12 :         nrepeat = 0;
     720                 :     }
     721              12 :     tmpGroup--;
     722                 : 
     723              12 :     buf = (char *)cx->malloc_(buflen + 1);
     724              12 :     if (!buf)
     725               0 :         return JS_FALSE;
     726                 : 
     727              12 :     tmpDest = buf;
     728              12 :     tmpSrc = num;
     729                 : 
     730              36 :     while (*tmpSrc == '-' || remainder--) {
     731              12 :         JS_ASSERT(tmpDest - buf < buflen);
     732              12 :         *tmpDest++ = *tmpSrc++;
     733                 :     }
     734              24 :     while (tmpSrc < end) {
     735               0 :         JS_ASSERT(tmpDest - buf + ptrdiff_t(thousandsLength) <= buflen);
     736               0 :         strcpy(tmpDest, rt->thousandsSeparator);
     737               0 :         tmpDest += thousandsLength;
     738               0 :         JS_ASSERT(tmpDest - buf + *tmpGroup <= buflen);
     739               0 :         js_memcpy(tmpDest, tmpSrc, *tmpGroup);
     740               0 :         tmpDest += *tmpGroup;
     741               0 :         tmpSrc += *tmpGroup;
     742               0 :         if (--nrepeat < 0)
     743               0 :             tmpGroup--;
     744                 :     }
     745                 : 
     746              12 :     if (*nint == '.') {
     747              12 :         JS_ASSERT(tmpDest - buf + ptrdiff_t(decimalLength) <= buflen);
     748              12 :         strcpy(tmpDest, rt->decimalSeparator);
     749              12 :         tmpDest += decimalLength;
     750              12 :         JS_ASSERT(tmpDest - buf + ptrdiff_t(strlen(nint + 1)) <= buflen);
     751              12 :         strcpy(tmpDest, nint + 1);
     752                 :     } else {
     753               0 :         JS_ASSERT(tmpDest - buf + ptrdiff_t(strlen(nint)) <= buflen);
     754               0 :         strcpy(tmpDest, nint);
     755                 :     }
     756                 : 
     757              12 :     if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode) {
     758               3 :         JSBool ok = cx->localeCallbacks->localeToUnicode(cx, buf, vp);
     759               3 :         cx->free_(buf);
     760               3 :         return ok;
     761                 :     }
     762                 : 
     763               9 :     str = js_NewStringCopyN(cx, buf, buflen);
     764               9 :     cx->free_(buf);
     765               9 :     if (!str)
     766               0 :         return JS_FALSE;
     767                 : 
     768               9 :     vp->setString(str);
     769               9 :     return JS_TRUE;
     770                 : }
     771                 : 
     772                 : JSBool
     773              99 : js_num_valueOf(JSContext *cx, unsigned argc, Value *vp)
     774                 : {
     775              99 :     CallArgs args = CallArgsFromVp(argc, vp);
     776                 : 
     777                 :     double d;
     778                 :     bool ok;
     779              99 :     if (!BoxedPrimitiveMethodGuard(cx, args, js_num_valueOf, &d, &ok))
     780              63 :         return ok;
     781                 : 
     782              36 :     args.rval().setNumber(d);
     783              36 :     return true;
     784                 : }
     785                 : 
     786                 : 
     787                 : #define MAX_PRECISION 100
     788                 : 
     789                 : static JSBool
     790             411 : num_to(JSContext *cx, Native native, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode,
     791                 :        int precisionMin, int precisionMax, int precisionOffset,
     792                 :        CallArgs args)
     793                 : {
     794                 :     /* Use MAX_PRECISION+1 because precisionOffset can be 1. */
     795                 :     char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)];
     796                 :     char *numStr;
     797                 : 
     798                 :     double d;
     799                 :     bool ok;
     800             411 :     if (!BoxedPrimitiveMethodGuard(cx, args, native, &d, &ok))
     801             126 :         return ok;
     802                 : 
     803                 :     double precision;
     804             285 :     if (args.length() == 0) {
     805              54 :         precision = 0.0;
     806              54 :         oneArgMode = zeroArgMode;
     807                 :     } else {
     808             231 :         if (!ToInteger(cx, args[0], &precision))
     809               0 :             return false;
     810             231 :         if (precision < precisionMin || precision > precisionMax) {
     811               0 :             ToCStringBuf cbuf;
     812               0 :             numStr = IntToCString(&cbuf, int(precision));
     813               0 :             JS_ASSERT(numStr);
     814               0 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PRECISION_RANGE, numStr);
     815               0 :             return JS_FALSE;
     816                 :         }
     817                 :     }
     818                 : 
     819                 :     numStr = js_dtostr(cx->runtime->dtoaState, buf, sizeof buf,
     820             285 :                        oneArgMode, (int)precision + precisionOffset, d);
     821             285 :     if (!numStr) {
     822               0 :         JS_ReportOutOfMemory(cx);
     823               0 :         return JS_FALSE;
     824                 :     }
     825             285 :     JSString *str = js_NewStringCopyZ(cx, numStr);
     826             285 :     if (!str)
     827               0 :         return JS_FALSE;
     828             285 :     args.rval().setString(str);
     829             285 :     return JS_TRUE;
     830                 : }
     831                 : 
     832                 : /*
     833                 :  * In the following three implementations, we allow a larger range of precision
     834                 :  * than ECMA requires; this is permitted by ECMA-262.
     835                 :  */
     836                 : static JSBool
     837             321 : num_toFixed(JSContext *cx, unsigned argc, Value *vp)
     838                 : {
     839                 :     return num_to(cx, num_toFixed, DTOSTR_FIXED, DTOSTR_FIXED, -20, MAX_PRECISION, 0,
     840             321 :                   CallArgsFromVp(argc, vp));
     841                 : }
     842                 : 
     843                 : static JSBool
     844              90 : num_toExponential(JSContext *cx, unsigned argc, Value *vp)
     845                 : {
     846                 :     return num_to(cx, num_toExponential, DTOSTR_STANDARD_EXPONENTIAL, DTOSTR_EXPONENTIAL, 0,
     847              90 :                   MAX_PRECISION, 1, CallArgsFromVp(argc, vp));
     848                 : }
     849                 : 
     850                 : static JSBool
     851              90 : num_toPrecision(JSContext *cx, unsigned argc, Value *vp)
     852                 : {
     853              90 :     CallArgs args = CallArgsFromVp(argc, vp);
     854              90 :     if (!args.hasDefined(0))
     855              90 :         return num_toStringHelper(cx, num_toPrecision, 0, vp);
     856                 :     return num_to(cx, num_toPrecision, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0,
     857               0 :                   args);
     858                 : }
     859                 : 
     860                 : static JSFunctionSpec number_methods[] = {
     861                 : #if JS_HAS_TOSOURCE
     862                 :     JS_FN(js_toSource_str,       num_toSource,          0, 0),
     863                 : #endif
     864                 :     JS_FN(js_toString_str,       num_toString,          1, 0),
     865                 :     JS_FN(js_toLocaleString_str, num_toLocaleString,    0, 0),
     866                 :     JS_FN(js_valueOf_str,        js_num_valueOf,        0, 0),
     867                 :     JS_FN("toFixed",             num_toFixed,           1, 0),
     868                 :     JS_FN("toExponential",       num_toExponential,     1, 0),
     869                 :     JS_FN("toPrecision",         num_toPrecision,       1, 0),
     870                 :     JS_FS_END
     871                 : };
     872                 : 
     873                 : /* NB: Keep this in synch with number_constants[]. */
     874                 : enum nc_slot {
     875                 :     NC_NaN,
     876                 :     NC_POSITIVE_INFINITY,
     877                 :     NC_NEGATIVE_INFINITY,
     878                 :     NC_MAX_VALUE,
     879                 :     NC_MIN_VALUE,
     880                 :     NC_LIMIT
     881                 : };
     882                 : 
     883                 : /*
     884                 :  * Some to most C compilers forbid spelling these at compile time, or barf
     885                 :  * if you try, so all but MAX_VALUE are set up by InitRuntimeNumberState
     886                 :  * using union jsdpun.
     887                 :  */
     888                 : static JSConstDoubleSpec number_constants[] = {
     889                 :     {0,                         js_NaN_str,          0,{0,0,0}},
     890                 :     {0,                         "POSITIVE_INFINITY", 0,{0,0,0}},
     891                 :     {0,                         "NEGATIVE_INFINITY", 0,{0,0,0}},
     892                 :     {1.7976931348623157E+308,   "MAX_VALUE",         0,{0,0,0}},
     893                 :     {0,                         "MIN_VALUE",         0,{0,0,0}},
     894                 :     {0,0,0,{0,0,0}}
     895                 : };
     896                 : 
     897                 : double js_NaN;
     898                 : double js_PositiveInfinity;
     899                 : double js_NegativeInfinity;
     900                 : 
     901                 : #if (defined __GNUC__ && defined __i386__) || \
     902                 :     (defined __SUNPRO_CC && defined __i386)
     903                 : 
     904                 : /*
     905                 :  * Set the exception mask to mask all exceptions and set the FPU precision
     906                 :  * to 53 bit mantissa (64 bit doubles).
     907                 :  */
     908           23449 : inline void FIX_FPU() {
     909                 :     short control;
     910           23449 :     asm("fstcw %0" : "=m" (control) : );
     911           23449 :     control &= ~0x300; // Lower bits 8 and 9 (precision control).
     912           23449 :     control |= 0x2f3;  // Raise bits 0-5 (exception masks) and 9 (64-bit precision).
     913           23449 :     asm("fldcw %0" : : "m" (control) );
     914           23449 : }
     915                 : 
     916                 : #else
     917                 : 
     918                 : #define FIX_FPU() ((void)0)
     919                 : 
     920                 : #endif
     921                 : 
     922                 : namespace js {
     923                 : 
     924                 : bool
     925           19910 : InitRuntimeNumberState(JSRuntime *rt)
     926                 : {
     927           19910 :     FIX_FPU();
     928                 : 
     929                 :     jsdpun u;
     930           19910 :     u.s.hi = JSDOUBLE_HI32_NAN;
     931           19910 :     u.s.lo = JSDOUBLE_LO32_NAN;
     932           19910 :     number_constants[NC_NaN].dval = js_NaN = u.d;
     933           19910 :     rt->NaNValue.setDouble(u.d);
     934                 : 
     935           19910 :     u.s.hi = JSDOUBLE_HI32_EXPMASK;
     936           19910 :     u.s.lo = 0x00000000;
     937           19910 :     number_constants[NC_POSITIVE_INFINITY].dval = js_PositiveInfinity = u.d;
     938           19910 :     rt->positiveInfinityValue.setDouble(u.d);
     939                 : 
     940           19910 :     u.s.hi = JSDOUBLE_HI32_SIGNBIT | JSDOUBLE_HI32_EXPMASK;
     941           19910 :     u.s.lo = 0x00000000;
     942           19910 :     number_constants[NC_NEGATIVE_INFINITY].dval = js_NegativeInfinity = u.d;
     943           19910 :     rt->negativeInfinityValue.setDouble(u.d);
     944                 : 
     945           19910 :     u.s.hi = 0;
     946           19910 :     u.s.lo = 1;
     947           19910 :     number_constants[NC_MIN_VALUE].dval = u.d;
     948                 : 
     949                 :     /* Copy locale-specific separators into the runtime strings. */
     950                 :     const char *thousandsSeparator, *decimalPoint, *grouping;
     951                 : #ifdef HAVE_LOCALECONV
     952           19910 :     struct lconv *locale = localeconv();
     953           19910 :     thousandsSeparator = locale->thousands_sep;
     954           19910 :     decimalPoint = locale->decimal_point;
     955           19910 :     grouping = locale->grouping;
     956                 : #else
     957                 :     thousandsSeparator = getenv("LOCALE_THOUSANDS_SEP");
     958                 :     decimalPoint = getenv("LOCALE_DECIMAL_POINT");
     959                 :     grouping = getenv("LOCALE_GROUPING");
     960                 : #endif
     961           19910 :     if (!thousandsSeparator)
     962               0 :         thousandsSeparator = "'";
     963           19910 :     if (!decimalPoint)
     964               0 :         decimalPoint = ".";
     965           19910 :     if (!grouping)
     966               0 :         grouping = "\3\0";
     967                 : 
     968                 :     /*
     969                 :      * We use single malloc to get the memory for all separator and grouping
     970                 :      * strings.
     971                 :      */
     972           19910 :     size_t thousandsSeparatorSize = strlen(thousandsSeparator) + 1;
     973           19910 :     size_t decimalPointSize = strlen(decimalPoint) + 1;
     974           19910 :     size_t groupingSize = strlen(grouping) + 1;
     975                 : 
     976                 :     char *storage = static_cast<char *>(OffTheBooks::malloc_(thousandsSeparatorSize +
     977                 :                                                              decimalPointSize +
     978           19910 :                                                              groupingSize));
     979           19910 :     if (!storage)
     980               0 :         return false;
     981                 : 
     982           19910 :     js_memcpy(storage, thousandsSeparator, thousandsSeparatorSize);
     983           19910 :     rt->thousandsSeparator = storage;
     984           19910 :     storage += thousandsSeparatorSize;
     985                 : 
     986           19910 :     js_memcpy(storage, decimalPoint, decimalPointSize);
     987           19910 :     rt->decimalSeparator = storage;
     988           19910 :     storage += decimalPointSize;
     989                 : 
     990           19910 :     js_memcpy(storage, grouping, groupingSize);
     991           19910 :     rt->numGrouping = grouping;
     992           19910 :     return true;
     993                 : }
     994                 : 
     995                 : void
     996           19908 : FinishRuntimeNumberState(JSRuntime *rt)
     997                 : {
     998                 :     /*
     999                 :      * The free also releases the memory for decimalSeparator and numGrouping
    1000                 :      * strings.
    1001                 :      */
    1002           19908 :     char *storage = const_cast<char *>(rt->thousandsSeparator);
    1003           19908 :     Foreground::free_(storage);
    1004           19908 : }
    1005                 : 
    1006                 : } /* namespace js */
    1007                 : 
    1008                 : JSObject *
    1009            3539 : js_InitNumberClass(JSContext *cx, JSObject *obj)
    1010                 : {
    1011            3539 :     JS_ASSERT(obj->isNative());
    1012                 : 
    1013                 :     /* XXX must do at least once per new thread, so do it per JSContext... */
    1014            3539 :     FIX_FPU();
    1015                 : 
    1016            3539 :     GlobalObject *global = &obj->asGlobal();
    1017                 : 
    1018            3539 :     JSObject *numberProto = global->createBlankPrototype(cx, &NumberClass);
    1019            3539 :     if (!numberProto)
    1020               0 :         return NULL;
    1021            3539 :     numberProto->asNumber().setPrimitiveValue(0);
    1022                 : 
    1023                 :     JSFunction *ctor = global->createConstructor(cx, Number, &NumberClass,
    1024            3539 :                                                  CLASS_ATOM(cx, Number), 1);
    1025            3539 :     if (!ctor)
    1026               0 :         return NULL;
    1027                 : 
    1028            3539 :     if (!LinkConstructorAndPrototype(cx, ctor, numberProto))
    1029               0 :         return NULL;
    1030                 : 
    1031                 :     /* Add numeric constants (MAX_VALUE, NaN, &c.) to the Number constructor. */
    1032            3539 :     if (!JS_DefineConstDoubles(cx, ctor, number_constants))
    1033               0 :         return NULL;
    1034                 : 
    1035            3539 :     if (!DefinePropertiesAndBrand(cx, numberProto, NULL, number_methods))
    1036               0 :         return NULL;
    1037                 : 
    1038            3539 :     if (!JS_DefineFunctions(cx, global, number_functions))
    1039               0 :         return NULL;
    1040                 : 
    1041                 :     /* ES5 15.1.1.1, 15.1.1.2 */
    1042           10617 :     if (!DefineNativeProperty(cx, global, ATOM_TO_JSID(cx->runtime->atomState.NaNAtom),
    1043                 :                               cx->runtime->NaNValue, JS_PropertyStub, JS_StrictPropertyStub,
    1044            7078 :                               JSPROP_PERMANENT | JSPROP_READONLY, 0, 0) ||
    1045            3539 :         !DefineNativeProperty(cx, global, ATOM_TO_JSID(cx->runtime->atomState.InfinityAtom),
    1046                 :                               cx->runtime->positiveInfinityValue,
    1047                 :                               JS_PropertyStub, JS_StrictPropertyStub,
    1048            7078 :                               JSPROP_PERMANENT | JSPROP_READONLY, 0, 0))
    1049                 :     {
    1050               0 :         return NULL;
    1051                 :     }
    1052                 : 
    1053            3539 :     if (!DefineConstructorAndPrototype(cx, global, JSProto_Number, ctor, numberProto))
    1054               0 :         return NULL;
    1055                 : 
    1056            3539 :     return numberProto;
    1057                 : }
    1058                 : 
    1059                 : namespace v8 {
    1060                 : namespace internal {
    1061                 : extern char* DoubleToCString(double v, char* buffer, int buflen);
    1062                 : }
    1063                 : }
    1064                 : 
    1065                 : namespace js {
    1066                 : 
    1067                 : static char *
    1068          279837 : FracNumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, int base = 10)
    1069                 : {
    1070                 : #ifdef DEBUG
    1071                 :     {
    1072                 :         int32_t _;
    1073          279837 :         JS_ASSERT(!JSDOUBLE_IS_INT32(d, &_));
    1074                 :     }
    1075                 : #endif
    1076                 : 
    1077                 :     char* numStr;
    1078          279837 :     if (base == 10) {
    1079                 :         /*
    1080                 :          * This is V8's implementation of the algorithm described in the
    1081                 :          * following paper:
    1082                 :          *
    1083                 :          *   Printing floating-point numbers quickly and accurately with integers.
    1084                 :          *   Florian Loitsch, PLDI 2010.
    1085                 :          *
    1086                 :          * It fails on a small number of cases, whereupon we fall back to
    1087                 :          * js_dtostr() (which uses David Gay's dtoa).
    1088                 :          */
    1089          279511 :         numStr = v8::internal::DoubleToCString(d, cbuf->sbuf, cbuf->sbufSize);
    1090          279511 :         if (!numStr)
    1091                 :             numStr = js_dtostr(cx->runtime->dtoaState, cbuf->sbuf, cbuf->sbufSize,
    1092           13454 :                                DTOSTR_STANDARD, 0, d);
    1093                 :     } else {
    1094             326 :         numStr = cbuf->dbuf = js_dtobasestr(cx->runtime->dtoaState, base, d);
    1095                 :     }
    1096          279837 :     return numStr;
    1097                 : }
    1098                 : 
    1099                 : char *
    1100           89414 : NumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, int base/* = 10*/)
    1101                 : {
    1102                 :     int32_t i;
    1103           89414 :     return (JSDOUBLE_IS_INT32(d, &i))
    1104           41050 :            ? IntToCString(cbuf, i, base)
    1105          130464 :            : FracNumberToCString(cx, cbuf, d, base);
    1106                 : }
    1107                 : 
    1108                 : }
    1109                 : 
    1110                 : static JSString * JS_FASTCALL
    1111         3132879 : js_NumberToStringWithBase(JSContext *cx, double d, int base)
    1112                 : {
    1113         6265758 :     ToCStringBuf cbuf;
    1114                 :     char *numStr;
    1115                 : 
    1116                 :     /*
    1117                 :      * Caller is responsible for error reporting. When called from trace,
    1118                 :      * returning NULL here will cause us to fall of trace and then retry
    1119                 :      * from the interpreter (which will report the error).
    1120                 :      */
    1121         3132879 :     if (base < 2 || base > 36)
    1122               0 :         return NULL;
    1123                 : 
    1124         3132879 :     JSCompartment *c = cx->compartment;
    1125                 : 
    1126                 :     int32_t i;
    1127         3132879 :     if (JSDOUBLE_IS_INT32(d, &i)) {
    1128          263062 :         if (base == 10 && StaticStrings::hasInt(i))
    1129           13246 :             return cx->runtime->staticStrings.getInt(i);
    1130          249816 :         if (unsigned(i) < unsigned(base)) {
    1131          180260 :             if (i < 10)
    1132           92104 :                 return cx->runtime->staticStrings.getInt(i);
    1133           88156 :             jschar c = 'a' + i - 10;
    1134           88156 :             JS_ASSERT(StaticStrings::hasUnit(c));
    1135           88156 :             return cx->runtime->staticStrings.getUnit(c);
    1136                 :         }
    1137                 : 
    1138           69556 :         if (JSFlatString *str = c->dtoaCache.lookup(base, d))
    1139            3033 :             return str;
    1140                 : 
    1141           66523 :         numStr = IntToCString(&cbuf, i, base);
    1142           66523 :         JS_ASSERT(!cbuf.dbuf && numStr >= cbuf.sbuf && numStr < cbuf.sbuf + cbuf.sbufSize);
    1143                 :     } else {
    1144         2869817 :         if (JSFlatString *str = c->dtoaCache.lookup(base, d))
    1145         2638344 :             return str;
    1146                 : 
    1147          231473 :         numStr = FracNumberToCString(cx, &cbuf, d, base);
    1148          231473 :         if (!numStr) {
    1149               0 :             JS_ReportOutOfMemory(cx);
    1150               0 :             return NULL;
    1151                 :         }
    1152          462294 :         JS_ASSERT_IF(base == 10,
    1153          693767 :                      !cbuf.dbuf && numStr >= cbuf.sbuf && numStr < cbuf.sbuf + cbuf.sbufSize);
    1154               0 :         JS_ASSERT_IF(base != 10,
    1155          231473 :                      cbuf.dbuf && cbuf.dbuf == numStr);
    1156                 :     }
    1157                 : 
    1158          297996 :     JSFixedString *s = js_NewStringCopyZ(cx, numStr);
    1159          297996 :     c->dtoaCache.cache(base, d, s);
    1160          297996 :     return s;
    1161                 : }
    1162                 : 
    1163                 : JSString * JS_FASTCALL
    1164         2887137 : js_NumberToString(JSContext *cx, double d)
    1165                 : {
    1166         2887137 :     return js_NumberToStringWithBase(cx, d, 10);
    1167                 : }
    1168                 : 
    1169                 : namespace js {
    1170                 : 
    1171                 : JSFixedString *
    1172               0 : NumberToString(JSContext *cx, double d)
    1173                 : {
    1174               0 :     if (JSString *str = js_NumberToStringWithBase(cx, d, 10))
    1175               0 :         return &str->asFixed();
    1176               0 :     return NULL;
    1177                 : }
    1178                 : 
    1179                 : JSFixedString *
    1180             668 : IndexToString(JSContext *cx, uint32_t index)
    1181                 : {
    1182             668 :     if (StaticStrings::hasUint(index))
    1183             638 :         return cx->runtime->staticStrings.getUint(index);
    1184                 : 
    1185              30 :     JSCompartment *c = cx->compartment;
    1186              30 :     if (JSFixedString *str = c->dtoaCache.lookup(10, index))
    1187               0 :         return str;
    1188                 : 
    1189              30 :     JSShortString *str = js_NewGCShortString(cx);
    1190              30 :     if (!str)
    1191               0 :         return NULL;
    1192                 : 
    1193              30 :     jschar *storage = str->inlineStorageBeforeInit();
    1194              30 :     size_t length = JSShortString::MAX_SHORT_LENGTH;
    1195              30 :     const RangedPtr<jschar> end(storage + length, storage, length + 1);
    1196              30 :     *end = '\0';
    1197                 : 
    1198              30 :     RangedPtr<jschar> start = BackfillIndexInCharBuffer(index, end);
    1199                 : 
    1200              30 :     str->initAtOffsetInBuffer(start.get(), end - start);
    1201                 : 
    1202              30 :     c->dtoaCache.cache(10, index, str);
    1203              30 :     return str;
    1204                 : }
    1205                 : 
    1206                 : bool JS_FASTCALL
    1207          670433 : NumberValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb)
    1208                 : {
    1209                 :     /* Convert to C-string. */
    1210         1340866 :     ToCStringBuf cbuf;
    1211                 :     const char *cstr;
    1212          670433 :     if (v.isInt32()) {
    1213          581095 :         cstr = IntToCString(&cbuf, v.toInt32());
    1214                 :     } else {
    1215           89338 :         cstr = NumberToCString(cx, &cbuf, v.toDouble());
    1216           89338 :         if (!cstr) {
    1217               0 :             JS_ReportOutOfMemory(cx);
    1218               0 :             return JS_FALSE;
    1219                 :         }
    1220                 :     }
    1221                 : 
    1222                 :     /*
    1223                 :      * Inflate to jschar string.  The input C-string characters are < 127, so
    1224                 :      * even if jschars are UTF-8, all chars should map to one jschar.
    1225                 :      */
    1226          670433 :     size_t cstrlen = strlen(cstr);
    1227          670433 :     JS_ASSERT(!cbuf.dbuf && cstrlen < cbuf.sbufSize);
    1228          670433 :     return sb.appendInflated(cstr, cstrlen);
    1229                 : }
    1230                 : 
    1231                 : bool
    1232         1303591 : ToNumberSlow(JSContext *cx, Value v, double *out)
    1233                 : {
    1234         1303591 :     JS_ASSERT(!v.isNumber());
    1235         1303591 :     goto skip_int_double;
    1236                 :     for (;;) {
    1237          259757 :         if (v.isNumber()) {
    1238            4055 :             *out = v.toNumber();
    1239            4055 :             return true;
    1240                 :         }
    1241                 :       skip_int_double:
    1242         1559293 :         if (v.isString())
    1243          712590 :             return StringToNumberType<double>(cx, v.toString(), out);
    1244          846703 :         if (v.isBoolean()) {
    1245          149609 :             if (v.toBoolean()) {
    1246           75179 :                 *out = 1.0;
    1247           75179 :                 return true;
    1248                 :             }
    1249           74430 :             *out = 0.0;
    1250           74430 :             return true;
    1251                 :         }
    1252          697094 :         if (v.isNull()) {
    1253           16120 :             *out = 0.0;
    1254           16120 :             return true;
    1255                 :         }
    1256          680974 :         if (v.isUndefined())
    1257          421172 :             break;
    1258                 : 
    1259          259802 :         JS_ASSERT(v.isObject());
    1260          259802 :         if (!ToPrimitive(cx, JSTYPE_NUMBER, &v))
    1261              45 :             return false;
    1262          259757 :         if (v.isObject())
    1263               0 :             break;
    1264                 :     }
    1265                 : 
    1266          421172 :     *out = js_NaN;
    1267          421172 :     return true;
    1268                 : }
    1269                 : 
    1270                 : bool
    1271         1747951 : ToInt32Slow(JSContext *cx, const Value &v, int32_t *out)
    1272                 : {
    1273         1747951 :     JS_ASSERT(!v.isInt32());
    1274                 :     double d;
    1275         1747951 :     if (v.isDouble()) {
    1276         1069475 :         d = v.toDouble();
    1277                 :     } else {
    1278          678476 :         if (!ToNumberSlow(cx, v, &d))
    1279              27 :             return false;
    1280                 :     }
    1281         1747924 :     *out = js_DoubleToECMAInt32(d);
    1282         1747924 :     return true;
    1283                 : }
    1284                 : 
    1285                 : bool
    1286           18581 : ToUint32Slow(JSContext *cx, const Value &v, uint32_t *out)
    1287                 : {
    1288           18581 :     JS_ASSERT(!v.isInt32());
    1289                 :     double d;
    1290           18581 :     if (v.isDouble()) {
    1291           14428 :         d = v.toDouble();
    1292                 :     } else {
    1293            4153 :         if (!ToNumberSlow(cx, v, &d))
    1294               0 :             return false;
    1295                 :     }
    1296           18581 :     *out = js_DoubleToECMAUint32(d);
    1297           18581 :     return true;
    1298                 : }
    1299                 : 
    1300                 : }  /* namespace js */
    1301                 : 
    1302                 : namespace js {
    1303                 : 
    1304                 : bool
    1305               0 : NonstandardToInt32Slow(JSContext *cx, const Value &v, int32_t *out)
    1306                 : {
    1307               0 :     JS_ASSERT(!v.isInt32());
    1308                 :     double d;
    1309               0 :     if (v.isDouble()) {
    1310               0 :         d = v.toDouble();
    1311               0 :     } else if (!ToNumberSlow(cx, v, &d)) {
    1312               0 :         return false;
    1313                 :     }
    1314                 : 
    1315               0 :     if (JSDOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) {
    1316                 :         js_ReportValueError(cx, JSMSG_CANT_CONVERT,
    1317               0 :                             JSDVG_SEARCH_STACK, v, NULL);
    1318               0 :         return false;
    1319                 :     }
    1320               0 :     *out = (int32_t) floor(d + 0.5);  /* Round to nearest */
    1321               0 :     return true;
    1322                 : }
    1323                 : 
    1324                 : bool
    1325             576 : ValueToUint16Slow(JSContext *cx, const Value &v, uint16_t *out)
    1326                 : {
    1327             576 :     JS_ASSERT(!v.isInt32());
    1328                 :     double d;
    1329             576 :     if (v.isDouble()) {
    1330               0 :         d = v.toDouble();
    1331             576 :     } else if (!ToNumberSlow(cx, v, &d)) {
    1332               9 :         return false;
    1333                 :     }
    1334                 : 
    1335             567 :     if (d == 0 || !JSDOUBLE_IS_FINITE(d)) {
    1336              90 :         *out = 0;
    1337              90 :         return true;
    1338                 :     }
    1339                 : 
    1340             477 :     uint16_t u = (uint16_t) d;
    1341             477 :     if ((double)u == d) {
    1342             477 :         *out = u;
    1343             477 :         return true;
    1344                 :     }
    1345                 : 
    1346               0 :     bool neg = (d < 0);
    1347               0 :     d = floor(neg ? -d : d);
    1348               0 :     d = neg ? -d : d;
    1349               0 :     unsigned m = JS_BIT(16);
    1350               0 :     d = fmod(d, (double) m);
    1351               0 :     if (d < 0)
    1352               0 :         d += m;
    1353               0 :     *out = (uint16_t) d;
    1354               0 :     return true;
    1355                 : }
    1356                 : 
    1357                 : }  /* namespace js */
    1358                 : 
    1359                 : JSBool
    1360          624726 : js_strtod(JSContext *cx, const jschar *s, const jschar *send,
    1361                 :           const jschar **ep, double *dp)
    1362                 : {
    1363                 :     size_t i;
    1364                 :     char cbuf[32];
    1365                 :     char *cstr, *istr, *estr;
    1366                 :     JSBool negative;
    1367                 :     double d;
    1368                 : 
    1369          624726 :     const jschar *s1 = SkipSpace(s, send);
    1370          624726 :     size_t length = send - s1;
    1371                 : 
    1372                 :     /* Use cbuf to avoid malloc */
    1373          624726 :     if (length >= sizeof cbuf) {
    1374          254261 :         cstr = (char *) cx->malloc_(length + 1);
    1375          254261 :         if (!cstr)
    1376               0 :            return JS_FALSE;
    1377                 :     } else {
    1378          370465 :         cstr = cbuf;
    1379                 :     }
    1380                 : 
    1381        65049110 :     for (i = 0; i != length; i++) {
    1382        64424384 :         if (s1[i] >> 8)
    1383               0 :             break;
    1384        64424384 :         cstr[i] = (char)s1[i];
    1385                 :     }
    1386          624726 :     cstr[i] = 0;
    1387                 : 
    1388          624726 :     istr = cstr;
    1389          624726 :     if ((negative = (*istr == '-')) != 0 || *istr == '+')
    1390             437 :         istr++;
    1391          624726 :     if (*istr == 'I' && !strncmp(istr, js_Infinity_str, sizeof js_Infinity_str - 1)) {
    1392             172 :         d = negative ? js_NegativeInfinity : js_PositiveInfinity;
    1393             172 :         estr = istr + 8;
    1394                 :     } else {
    1395                 :         int err;
    1396          624554 :         d = js_strtod_harder(cx->runtime->dtoaState, cstr, &estr, &err);
    1397          624554 :         if (d == HUGE_VAL)
    1398              10 :             d = js_PositiveInfinity;
    1399          624544 :         else if (d == -HUGE_VAL)
    1400               0 :             d = js_NegativeInfinity;
    1401                 :     }
    1402                 : 
    1403          624726 :     i = estr - cstr;
    1404          624726 :     if (cstr != cbuf)
    1405          254261 :         cx->free_(cstr);
    1406          624726 :     *ep = i ? s1 + i : s;
    1407          624726 :     *dp = d;
    1408          624726 :     return JS_TRUE;
    1409                 : }

Generated by: LCOV version 1.7