LCOV - code coverage report
Current view: top level - js/src - jsdtoa.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 54 277 19.5 %
Date: 2017-07-14 16:53:18 Functions: 4 9 44.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /*
       8             :  * Portable double to alphanumeric string and back converters.
       9             :  */
      10             : 
      11             : #include "jsdtoa.h"
      12             : 
      13             : #include "jsprf.h"
      14             : #include "jstypes.h"
      15             : #include "jsutil.h"
      16             : 
      17             : using namespace js;
      18             : 
      19             : #if MOZ_LITTLE_ENDIAN
      20             : #define IEEE_8087
      21             : #else
      22             : #define IEEE_MC68k
      23             : #endif
      24             : 
      25             : #ifndef Long
      26             : #define Long int32_t
      27             : #endif
      28             : 
      29             : #ifndef ULong
      30             : #define ULong uint32_t
      31             : #endif
      32             : 
      33             : /*
      34             : #ifndef Llong
      35             : #define Llong int64_t
      36             : #endif
      37             : 
      38             : #ifndef ULlong
      39             : #define ULlong uint64_t
      40             : #endif
      41             : */
      42             : 
      43             : // dtoa.c requires that MALLOC be infallible. Furthermore, its allocations are
      44             : // few and small. So AutoEnterOOMUnsafeRegion is appropriate here.
      45           7 : static inline void* dtoa_malloc(size_t size)
      46             : {
      47          14 :     AutoEnterOOMUnsafeRegion oomUnsafe;
      48           7 :     void* p = js_malloc(size);
      49           7 :     if (!p)
      50           0 :         oomUnsafe.crash("dtoa_malloc");
      51             : 
      52          14 :     return p;
      53             : }
      54             : 
      55           0 : static inline void dtoa_free(void* p)
      56             : {
      57           0 :   return js_free(p);
      58             : }
      59             : 
      60             : #define NO_GLOBAL_STATE
      61             : #define NO_ERRNO
      62             : #define Omit_Private_Memory // This saves memory for the workloads we see.
      63             : #define MALLOC dtoa_malloc
      64             : #define FREE dtoa_free
      65             : #include "dtoa.c"
      66             : 
      67             : /* Mapping of JSDToStrMode -> js_dtoa mode */
      68             : static const uint8_t dtoaModes[] = {
      69             :     0,   /* DTOSTR_STANDARD */
      70             :     0,   /* DTOSTR_STANDARD_EXPONENTIAL, */
      71             :     3,   /* DTOSTR_FIXED, */
      72             :     2,   /* DTOSTR_EXPONENTIAL, */
      73             :     2};  /* DTOSTR_PRECISION */
      74             : 
      75             : double
      76         108 : js_strtod_harder(DtoaState* state, const char* s00, char** se, int* err)
      77             : {
      78             :     double retval;
      79         108 :     if (err)
      80         108 :         *err = 0;
      81         108 :     retval = _strtod(state, s00, se);
      82         108 :     return retval;
      83             : }
      84             : 
      85             : char*
      86          14 : js_dtostr(DtoaState* state, char* buffer, size_t bufferSize, JSDToStrMode mode, int precision,
      87             :           double dinput)
      88             : {
      89             :     U d;
      90             :     int decPt;        /* Offset of decimal point from first digit */
      91             :     int sign;         /* Nonzero if the sign bit was set in d */
      92             :     int nDigits;      /* Number of significand digits returned by js_dtoa */
      93             :     char* numBegin;   /* Pointer to the digits returned by js_dtoa */
      94          14 :     char* numEnd = 0; /* Pointer past the digits returned by js_dtoa */
      95             : 
      96          14 :     MOZ_ASSERT(bufferSize >= (size_t)(mode <= DTOSTR_STANDARD_EXPONENTIAL
      97             :                                      ? DTOSTR_STANDARD_BUFFER_SIZE
      98             :                                      : DTOSTR_VARIABLE_BUFFER_SIZE(precision)));
      99             : 
     100             :     /*
     101             :      * Change mode here rather than below because the buffer may not be large
     102             :      * enough to hold a large integer.
     103             :      */
     104          14 :     if (mode == DTOSTR_FIXED && (dinput >= 1e21 || dinput <= -1e21))
     105           0 :         mode = DTOSTR_STANDARD;
     106             : 
     107          14 :     dval(d) = dinput;
     108          14 :     numBegin = dtoa(PASS_STATE d, dtoaModes[mode], precision, &decPt, &sign, &numEnd);
     109          14 :     if (!numBegin) {
     110           0 :         return nullptr;
     111             :     }
     112             : 
     113          14 :     nDigits = numEnd - numBegin;
     114          14 :     MOZ_ASSERT((size_t) nDigits <= bufferSize - 2);
     115          14 :     if ((size_t) nDigits > bufferSize - 2) {
     116           0 :         return nullptr;
     117             :     }
     118             : 
     119          14 :     js_memcpy(buffer + 2, numBegin, nDigits);
     120          14 :     freedtoa(PASS_STATE numBegin);
     121          14 :     numBegin = buffer + 2; /* +2 leaves space for sign and/or decimal point */
     122          14 :     numEnd = numBegin + nDigits;
     123          14 :     *numEnd = '\0';
     124             : 
     125             :     /* If Infinity, -Infinity, or NaN, return the string regardless of mode. */
     126          14 :     if (decPt != 9999) {
     127          14 :         bool exponentialNotation = false;
     128          14 :         int minNDigits = 0;  /* Min number of significant digits required */
     129             :         char* p;
     130             :         char* q;
     131             : 
     132          14 :         switch (mode) {
     133             :             case DTOSTR_STANDARD:
     134           0 :                 if (decPt < -5 || decPt > 21)
     135           0 :                     exponentialNotation = true;
     136             :                 else
     137           0 :                     minNDigits = decPt;
     138           0 :                 break;
     139             : 
     140             :             case DTOSTR_FIXED:
     141          14 :                 if (precision >= 0)
     142          14 :                     minNDigits = decPt + precision;
     143             :                 else
     144           0 :                     minNDigits = decPt;
     145          14 :                 break;
     146             : 
     147             :             case DTOSTR_EXPONENTIAL:
     148           0 :                 MOZ_ASSERT(precision > 0);
     149           0 :                 minNDigits = precision;
     150             :                 MOZ_FALLTHROUGH;
     151             :             case DTOSTR_STANDARD_EXPONENTIAL:
     152           0 :                 exponentialNotation = true;
     153           0 :                 break;
     154             : 
     155             :             case DTOSTR_PRECISION:
     156           0 :                 MOZ_ASSERT(precision > 0);
     157           0 :                 minNDigits = precision;
     158           0 :                 if (decPt < -5 || decPt > precision)
     159           0 :                     exponentialNotation = true;
     160           0 :                 break;
     161             :         }
     162             : 
     163             :         /* If the number has fewer than minNDigits, end-pad it with zeros. */
     164          14 :         if (nDigits < minNDigits) {
     165          14 :             p = numBegin + minNDigits;
     166          14 :             nDigits = minNDigits;
     167          14 :             do {
     168          28 :                 *numEnd++ = '0';
     169          28 :             } while (numEnd != p);
     170          14 :             *numEnd = '\0';
     171             :         }
     172             : 
     173          14 :         if (exponentialNotation) {
     174             :             /* Insert a decimal point if more than one significand digit */
     175           0 :             if (nDigits != 1) {
     176           0 :                 numBegin--;
     177           0 :                 numBegin[0] = numBegin[1];
     178           0 :                 numBegin[1] = '.';
     179             :             }
     180           0 :             snprintf(numEnd, bufferSize - (numEnd - buffer), "e%+d", decPt-1);
     181          14 :         } else if (decPt != nDigits) {
     182             :             /* Some kind of a fraction in fixed notation */
     183          14 :             MOZ_ASSERT(decPt <= nDigits);
     184          14 :             if (decPt > 0) {
     185             :                 /* dd...dd . dd...dd */
     186          14 :                 p = --numBegin;
     187          28 :                 do {
     188          14 :                     *p = p[1];
     189          14 :                     p++;
     190          28 :                 } while (--decPt);
     191          14 :                 *p = '.';
     192             :             } else {
     193             :                 /* 0 . 00...00dd...dd */
     194           0 :                 p = numEnd;
     195           0 :                 numEnd += 1 - decPt;
     196           0 :                 q = numEnd;
     197           0 :                 MOZ_ASSERT(numEnd < buffer + bufferSize);
     198           0 :                 *numEnd = '\0';
     199           0 :                 while (p != numBegin)
     200           0 :                     *--q = *--p;
     201           0 :                 for (p = numBegin + 1; p != q; p++)
     202           0 :                     *p = '0';
     203           0 :                 *numBegin = '.';
     204           0 :                 *--numBegin = '0';
     205             :             }
     206             :         }
     207             :     }
     208             : 
     209             :     /* If negative and neither -0.0 nor NaN, output a leading '-'. */
     210          14 :     if (sign &&
     211          14 :             !(word0(d) == Sign_bit && word1(d) == 0) &&
     212           0 :             !((word0(d) & Exp_mask) == Exp_mask &&
     213           0 :               (word1(d) || (word0(d) & Frac_mask)))) {
     214           0 :         *--numBegin = '-';
     215             :     }
     216          14 :     return numBegin;
     217             : }
     218             : 
     219             : 
     220             : /* Let b = floor(b / divisor), and return the remainder.  b must be nonnegative.
     221             :  * divisor must be between 1 and 65536.
     222             :  * This function cannot run out of memory. */
     223             : static uint32_t
     224           0 : divrem(Bigint* b, uint32_t divisor)
     225             : {
     226           0 :     int32_t n = b->wds;
     227           0 :     uint32_t remainder = 0;
     228             :     ULong* bx;
     229             :     ULong* bp;
     230             : 
     231           0 :     MOZ_ASSERT(divisor > 0 && divisor <= 65536);
     232             : 
     233           0 :     if (!n)
     234           0 :         return 0; /* b is zero */
     235           0 :     bx = b->x;
     236           0 :     bp = bx + n;
     237           0 :     do {
     238           0 :         ULong a = *--bp;
     239           0 :         ULong dividend = remainder << 16 | a >> 16;
     240           0 :         ULong quotientHi = dividend / divisor;
     241             :         ULong quotientLo;
     242             : 
     243           0 :         remainder = dividend - quotientHi*divisor;
     244           0 :         MOZ_ASSERT(quotientHi <= 0xFFFF && remainder < divisor);
     245           0 :         dividend = remainder << 16 | (a & 0xFFFF);
     246           0 :         quotientLo = dividend / divisor;
     247           0 :         remainder = dividend - quotientLo*divisor;
     248           0 :         MOZ_ASSERT(quotientLo <= 0xFFFF && remainder < divisor);
     249           0 :         *bp = quotientHi << 16 | quotientLo;
     250           0 :     } while (bp != bx);
     251             :     /* Decrease the size of the number if its most significant word is now zero. */
     252           0 :     if (bx[n-1] == 0)
     253           0 :         b->wds--;
     254           0 :     return remainder;
     255             : }
     256             : 
     257             : /* Return floor(b/2^k) and set b to be the remainder.  The returned quotient must be less than 2^32. */
     258           0 : static uint32_t quorem2(Bigint* b, int32_t k)
     259             : {
     260             :     ULong mask;
     261             :     ULong result;
     262             :     ULong* bx;
     263             :     ULong* bxe;
     264             :     int32_t w;
     265           0 :     int32_t n = k >> 5;
     266           0 :     k &= 0x1F;
     267           0 :     mask = (1<<k) - 1;
     268             : 
     269           0 :     w = b->wds - n;
     270           0 :     if (w <= 0)
     271           0 :         return 0;
     272           0 :     MOZ_ASSERT(w <= 2);
     273           0 :     bx = b->x;
     274           0 :     bxe = bx + n;
     275           0 :     result = *bxe >> k;
     276           0 :     *bxe &= mask;
     277           0 :     if (w == 2) {
     278           0 :         MOZ_ASSERT(!(bxe[1] & ~mask));
     279           0 :         if (k)
     280           0 :             result |= bxe[1] << (32 - k);
     281             :     }
     282           0 :     n++;
     283           0 :     while (!*bxe && bxe != bx) {
     284           0 :         n--;
     285           0 :         bxe--;
     286             :     }
     287           0 :     b->wds = n;
     288           0 :     return result;
     289             : }
     290             : 
     291             : 
     292             : /* "-0.0000...(1073 zeros after decimal point)...0001\0" is the longest string that we could produce,
     293             :  * which occurs when printing -5e-324 in binary.  We could compute a better estimate of the size of
     294             :  * the output string and malloc fewer bytes depending on d and base, but why bother? */
     295             : #define DTOBASESTR_BUFFER_SIZE 1078
     296             : #define BASEDIGIT(digit) ((char)(((digit) >= 10) ? 'a' - 10 + (digit) : '0' + (digit)))
     297             : 
     298             : char*
     299           0 : js_dtobasestr(DtoaState* state, int base, double dinput)
     300             : {
     301             :     U d;
     302             :     char* buffer;        /* The output string */
     303             :     char* p;             /* Pointer to current position in the buffer */
     304             :     char* pInt;          /* Pointer to the beginning of the integer part of the string */
     305             :     char* q;
     306             :     uint32_t digit;
     307             :     U di;                /* d truncated to an integer */
     308             :     U df;                /* The fractional part of d */
     309             : 
     310           0 :     MOZ_ASSERT(base >= 2 && base <= 36);
     311             : 
     312           0 :     dval(d) = dinput;
     313           0 :     buffer = (char*) js_malloc(DTOBASESTR_BUFFER_SIZE);
     314           0 :     if (!buffer)
     315           0 :         return nullptr;
     316           0 :     p = buffer;
     317             : 
     318           0 :     if (dval(d) < 0.0
     319             : #if defined(XP_WIN)
     320             :         && !((word0(d) & Exp_mask) == Exp_mask && ((word0(d) & Frac_mask) || word1(d))) /* Visual C++ doesn't know how to compare against NaN */
     321             : #endif
     322             :        ) {
     323           0 :         *p++ = '-';
     324           0 :         dval(d) = -dval(d);
     325             :     }
     326             : 
     327             :     /* Check for Infinity and NaN */
     328           0 :     if ((word0(d) & Exp_mask) == Exp_mask) {
     329           0 :         strcpy(p, !word1(d) && !(word0(d) & Frac_mask) ? "Infinity" : "NaN");
     330           0 :         return buffer;
     331             :     }
     332             : 
     333             :     /* Output the integer part of d with the digits in reverse order. */
     334           0 :     pInt = p;
     335           0 :     dval(di) = floor(dval(d));
     336           0 :     if (dval(di) <= 4294967295.0) {
     337           0 :         uint32_t n = (uint32_t)dval(di);
     338           0 :         if (n)
     339           0 :             do {
     340           0 :                 uint32_t m = n / base;
     341           0 :                 digit = n - m*base;
     342           0 :                 n = m;
     343           0 :                 MOZ_ASSERT(digit < (uint32_t)base);
     344           0 :                 *p++ = BASEDIGIT(digit);
     345           0 :             } while (n);
     346           0 :         else *p++ = '0';
     347             :     } else {
     348             :         int e;
     349             :         int bits;  /* Number of significant bits in di; not used. */
     350           0 :         Bigint* b = d2b(PASS_STATE di, &e, &bits);
     351           0 :         if (!b)
     352           0 :             goto nomem1;
     353           0 :         b = lshift(PASS_STATE b, e);
     354           0 :         if (!b) {
     355             :           nomem1:
     356           0 :             Bfree(PASS_STATE b);
     357           0 :             js_free(buffer);
     358           0 :             return nullptr;
     359             :         }
     360           0 :         do {
     361           0 :             digit = divrem(b, base);
     362           0 :             MOZ_ASSERT(digit < (uint32_t)base);
     363           0 :             *p++ = BASEDIGIT(digit);
     364           0 :         } while (b->wds);
     365           0 :         Bfree(PASS_STATE b);
     366             :     }
     367             :     /* Reverse the digits of the integer part of d. */
     368           0 :     q = p-1;
     369           0 :     while (q > pInt) {
     370           0 :         char ch = *pInt;
     371           0 :         *pInt++ = *q;
     372           0 :         *q-- = ch;
     373             :     }
     374             : 
     375           0 :     dval(df) = dval(d) - dval(di);
     376           0 :     if (dval(df) != 0.0) {
     377             :         /* We have a fraction. */
     378             :         int e, bbits;
     379             :         int32_t s2, done;
     380           0 :         Bigint* b = nullptr;
     381           0 :         Bigint* s = nullptr;
     382           0 :         Bigint* mlo = nullptr;
     383           0 :         Bigint* mhi = nullptr;
     384             : 
     385           0 :         *p++ = '.';
     386           0 :         b = d2b(PASS_STATE df, &e, &bbits);
     387           0 :         if (!b) {
     388             :           nomem2:
     389           0 :             Bfree(PASS_STATE b);
     390           0 :             Bfree(PASS_STATE s);
     391           0 :             if (mlo != mhi)
     392           0 :                 Bfree(PASS_STATE mlo);
     393           0 :             Bfree(PASS_STATE mhi);
     394           0 :             js_free(buffer);
     395           0 :             return nullptr;
     396             :         }
     397           0 :         MOZ_ASSERT(e < 0);
     398             :         /* At this point df = b * 2^e.  e must be less than zero because 0 < df < 1. */
     399             : 
     400           0 :         s2 = -(int32_t)(word0(d) >> Exp_shift1 & Exp_mask>>Exp_shift1);
     401             : #ifndef Sudden_Underflow
     402           0 :         if (!s2)
     403           0 :             s2 = -1;
     404             : #endif
     405           0 :         s2 += Bias + P;
     406             :         /* 1/2^s2 = (nextDouble(d) - d)/2 */
     407           0 :         MOZ_ASSERT(-s2 < e);
     408           0 :         mlo = i2b(PASS_STATE 1);
     409           0 :         if (!mlo)
     410           0 :             goto nomem2;
     411           0 :         mhi = mlo;
     412           0 :         if (!word1(d) && !(word0(d) & Bndry_mask)
     413             : #ifndef Sudden_Underflow
     414           0 :             && word0(d) & (Exp_mask & Exp_mask << 1)
     415             : #endif
     416             :             ) {
     417             :             /* The special case.  Here we want to be within a quarter of the last input
     418             :                significant digit instead of one half of it when the output string's value is less than d.  */
     419           0 :             s2 += Log2P;
     420           0 :             mhi = i2b(PASS_STATE 1<<Log2P);
     421           0 :             if (!mhi)
     422           0 :                 goto nomem2;
     423             :         }
     424           0 :         b = lshift(PASS_STATE b, e + s2);
     425           0 :         if (!b)
     426           0 :             goto nomem2;
     427           0 :         s = i2b(PASS_STATE 1);
     428           0 :         if (!s)
     429           0 :             goto nomem2;
     430           0 :         s = lshift(PASS_STATE s, s2);
     431           0 :         if (!s)
     432           0 :             goto nomem2;
     433             :         /* At this point we have the following:
     434             :          *   s = 2^s2;
     435             :          *   1 > df = b/2^s2 > 0;
     436             :          *   (d - prevDouble(d))/2 = mlo/2^s2;
     437             :          *   (nextDouble(d) - d)/2 = mhi/2^s2. */
     438             : 
     439           0 :         done = false;
     440           0 :         do {
     441             :             int32_t j, j1;
     442             :             Bigint* delta;
     443             : 
     444           0 :             b = multadd(PASS_STATE b, base, 0);
     445           0 :             if (!b)
     446           0 :                 goto nomem2;
     447           0 :             digit = quorem2(b, s2);
     448           0 :             if (mlo == mhi) {
     449           0 :                 mlo = mhi = multadd(PASS_STATE mlo, base, 0);
     450           0 :                 if (!mhi)
     451           0 :                     goto nomem2;
     452             :             }
     453             :             else {
     454           0 :                 mlo = multadd(PASS_STATE mlo, base, 0);
     455           0 :                 if (!mlo)
     456           0 :                     goto nomem2;
     457           0 :                 mhi = multadd(PASS_STATE mhi, base, 0);
     458           0 :                 if (!mhi)
     459           0 :                     goto nomem2;
     460             :             }
     461             : 
     462             :             /* Do we yet have the shortest string that will round to d? */
     463           0 :             j = cmp(b, mlo);
     464             :             /* j is b/2^s2 compared with mlo/2^s2. */
     465           0 :             delta = diff(PASS_STATE s, mhi);
     466           0 :             if (!delta)
     467           0 :                 goto nomem2;
     468           0 :             j1 = delta->sign ? 1 : cmp(b, delta);
     469           0 :             Bfree(PASS_STATE delta);
     470             :             /* j1 is b/2^s2 compared with 1 - mhi/2^s2. */
     471             : 
     472             : #ifndef ROUND_BIASED
     473           0 :             if (j1 == 0 && !(word1(d) & 1)) {
     474           0 :                 if (j > 0)
     475           0 :                     digit++;
     476           0 :                 done = true;
     477             :             } else
     478             : #endif
     479           0 :             if (j < 0 || (j == 0
     480             : #ifndef ROUND_BIASED
     481           0 :                 && !(word1(d) & 1)
     482             : #endif
     483             :                 )) {
     484           0 :                 if (j1 > 0) {
     485             :                     /* Either dig or dig+1 would work here as the least significant digit.
     486             :                        Use whichever would produce an output value closer to d. */
     487           0 :                     b = lshift(PASS_STATE b, 1);
     488           0 :                     if (!b)
     489           0 :                         goto nomem2;
     490           0 :                     j1 = cmp(b, s);
     491           0 :                     if (j1 > 0) /* The even test (|| (j1 == 0 && (digit & 1))) is not here because it messes up odd base output
     492             :                                  * such as 3.5 in base 3.  */
     493           0 :                         digit++;
     494             :                 }
     495           0 :                 done = true;
     496           0 :             } else if (j1 > 0) {
     497           0 :                 digit++;
     498           0 :                 done = true;
     499             :             }
     500           0 :             MOZ_ASSERT(digit < (uint32_t)base);
     501           0 :             *p++ = BASEDIGIT(digit);
     502           0 :         } while (!done);
     503           0 :         Bfree(PASS_STATE b);
     504           0 :         Bfree(PASS_STATE s);
     505           0 :         if (mlo != mhi)
     506           0 :             Bfree(PASS_STATE mlo);
     507           0 :         Bfree(PASS_STATE mhi);
     508             :     }
     509           0 :     MOZ_ASSERT(p < buffer + DTOBASESTR_BUFFER_SIZE);
     510           0 :     *p = '\0';
     511           0 :     return buffer;
     512             : }
     513             : 
     514             : DtoaState*
     515           3 : js::NewDtoaState()
     516             : {
     517           3 :     return newdtoa();
     518             : }
     519             : 
     520             : void
     521           0 : js::DestroyDtoaState(DtoaState* state)
     522             : {
     523           0 :     destroydtoa(state);
     524           0 : }
     525             : 
     526             : /* Cleanup pollution from dtoa.c */
     527             : #undef Bias

Generated by: LCOV version 1.13