LCOV - app.info - js/src/jsnum.cpp

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