Home | History | Annotate | Download | only in src
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <limits.h>
      6 #include <stdarg.h>
      7 #include <cmath>
      8 
      9 #include "src/v8.h"
     10 
     11 #include "src/assert-scope.h"
     12 #include "src/conversions-inl.h"
     13 #include "src/conversions.h"
     14 #include "src/dtoa.h"
     15 #include "src/factory.h"
     16 #include "src/list-inl.h"
     17 #include "src/strtod.h"
     18 #include "src/utils.h"
     19 
     20 #ifndef _STLP_VENDOR_CSTD
     21 // STLPort doesn't import fpclassify into the std namespace.
     22 using std::fpclassify;
     23 #endif
     24 
     25 namespace v8 {
     26 namespace internal {
     27 
     28 
     29 namespace {
     30 
     31 // C++-style iterator adaptor for StringCharacterStream
     32 // (unlike C++ iterators the end-marker has different type).
     33 class StringCharacterStreamIterator {
     34  public:
     35   class EndMarker {};
     36 
     37   explicit StringCharacterStreamIterator(StringCharacterStream* stream);
     38 
     39   uint16_t operator*() const;
     40   void operator++();
     41   bool operator==(EndMarker const&) const { return end_; }
     42   bool operator!=(EndMarker const& m) const { return !end_; }
     43 
     44  private:
     45   StringCharacterStream* const stream_;
     46   uint16_t current_;
     47   bool end_;
     48 };
     49 
     50 
     51 StringCharacterStreamIterator::StringCharacterStreamIterator(
     52     StringCharacterStream* stream) : stream_(stream) {
     53   ++(*this);
     54 }
     55 
     56 uint16_t StringCharacterStreamIterator::operator*() const {
     57   return current_;
     58 }
     59 
     60 
     61 void StringCharacterStreamIterator::operator++() {
     62   end_ = !stream_->HasMore();
     63   if (!end_) {
     64     current_ = stream_->GetNext();
     65   }
     66 }
     67 }  // End anonymous namespace.
     68 
     69 
     70 double StringToDouble(UnicodeCache* unicode_cache,
     71                       const char* str, int flags, double empty_string_val) {
     72   // We cast to const uint8_t* here to avoid instantiating the
     73   // InternalStringToDouble() template for const char* as well.
     74   const uint8_t* start = reinterpret_cast<const uint8_t*>(str);
     75   const uint8_t* end = start + StrLength(str);
     76   return InternalStringToDouble(unicode_cache, start, end, flags,
     77                                 empty_string_val);
     78 }
     79 
     80 
     81 double StringToDouble(UnicodeCache* unicode_cache,
     82                       Vector<const uint8_t> str,
     83                       int flags,
     84                       double empty_string_val) {
     85   // We cast to const uint8_t* here to avoid instantiating the
     86   // InternalStringToDouble() template for const char* as well.
     87   const uint8_t* start = reinterpret_cast<const uint8_t*>(str.start());
     88   const uint8_t* end = start + str.length();
     89   return InternalStringToDouble(unicode_cache, start, end, flags,
     90                                 empty_string_val);
     91 }
     92 
     93 
     94 double StringToDouble(UnicodeCache* unicode_cache,
     95                       Vector<const uc16> str,
     96                       int flags,
     97                       double empty_string_val) {
     98   const uc16* end = str.start() + str.length();
     99   return InternalStringToDouble(unicode_cache, str.start(), end, flags,
    100                                 empty_string_val);
    101 }
    102 
    103 
    104 // Converts a string into an integer.
    105 double StringToInt(UnicodeCache* unicode_cache,
    106                    Vector<const uint8_t> vector,
    107                    int radix) {
    108   return InternalStringToInt(
    109       unicode_cache, vector.start(), vector.start() + vector.length(), radix);
    110 }
    111 
    112 
    113 double StringToInt(UnicodeCache* unicode_cache,
    114                    Vector<const uc16> vector,
    115                    int radix) {
    116   return InternalStringToInt(
    117       unicode_cache, vector.start(), vector.start() + vector.length(), radix);
    118 }
    119 
    120 
    121 const char* DoubleToCString(double v, Vector<char> buffer) {
    122   switch (fpclassify(v)) {
    123     case FP_NAN: return "NaN";
    124     case FP_INFINITE: return (v < 0.0 ? "-Infinity" : "Infinity");
    125     case FP_ZERO: return "0";
    126     default: {
    127       SimpleStringBuilder builder(buffer.start(), buffer.length());
    128       int decimal_point;
    129       int sign;
    130       const int kV8DtoaBufferCapacity = kBase10MaximalLength + 1;
    131       char decimal_rep[kV8DtoaBufferCapacity];
    132       int length;
    133 
    134       DoubleToAscii(v, DTOA_SHORTEST, 0,
    135                     Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
    136                     &sign, &length, &decimal_point);
    137 
    138       if (sign) builder.AddCharacter('-');
    139 
    140       if (length <= decimal_point && decimal_point <= 21) {
    141         // ECMA-262 section 9.8.1 step 6.
    142         builder.AddString(decimal_rep);
    143         builder.AddPadding('0', decimal_point - length);
    144 
    145       } else if (0 < decimal_point && decimal_point <= 21) {
    146         // ECMA-262 section 9.8.1 step 7.
    147         builder.AddSubstring(decimal_rep, decimal_point);
    148         builder.AddCharacter('.');
    149         builder.AddString(decimal_rep + decimal_point);
    150 
    151       } else if (decimal_point <= 0 && decimal_point > -6) {
    152         // ECMA-262 section 9.8.1 step 8.
    153         builder.AddString("0.");
    154         builder.AddPadding('0', -decimal_point);
    155         builder.AddString(decimal_rep);
    156 
    157       } else {
    158         // ECMA-262 section 9.8.1 step 9 and 10 combined.
    159         builder.AddCharacter(decimal_rep[0]);
    160         if (length != 1) {
    161           builder.AddCharacter('.');
    162           builder.AddString(decimal_rep + 1);
    163         }
    164         builder.AddCharacter('e');
    165         builder.AddCharacter((decimal_point >= 0) ? '+' : '-');
    166         int exponent = decimal_point - 1;
    167         if (exponent < 0) exponent = -exponent;
    168         builder.AddDecimalInteger(exponent);
    169       }
    170     return builder.Finalize();
    171     }
    172   }
    173 }
    174 
    175 
    176 const char* IntToCString(int n, Vector<char> buffer) {
    177   bool negative = false;
    178   if (n < 0) {
    179     // We must not negate the most negative int.
    180     if (n == kMinInt) return DoubleToCString(n, buffer);
    181     negative = true;
    182     n = -n;
    183   }
    184   // Build the string backwards from the least significant digit.
    185   int i = buffer.length();
    186   buffer[--i] = '\0';
    187   do {
    188     buffer[--i] = '0' + (n % 10);
    189     n /= 10;
    190   } while (n);
    191   if (negative) buffer[--i] = '-';
    192   return buffer.start() + i;
    193 }
    194 
    195 
    196 char* DoubleToFixedCString(double value, int f) {
    197   const int kMaxDigitsBeforePoint = 21;
    198   const double kFirstNonFixed = 1e21;
    199   const int kMaxDigitsAfterPoint = 20;
    200   DCHECK(f >= 0);
    201   DCHECK(f <= kMaxDigitsAfterPoint);
    202 
    203   bool negative = false;
    204   double abs_value = value;
    205   if (value < 0) {
    206     abs_value = -value;
    207     negative = true;
    208   }
    209 
    210   // If abs_value has more than kMaxDigitsBeforePoint digits before the point
    211   // use the non-fixed conversion routine.
    212   if (abs_value >= kFirstNonFixed) {
    213     char arr[100];
    214     Vector<char> buffer(arr, arraysize(arr));
    215     return StrDup(DoubleToCString(value, buffer));
    216   }
    217 
    218   // Find a sufficiently precise decimal representation of n.
    219   int decimal_point;
    220   int sign;
    221   // Add space for the '\0' byte.
    222   const int kDecimalRepCapacity =
    223       kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 1;
    224   char decimal_rep[kDecimalRepCapacity];
    225   int decimal_rep_length;
    226   DoubleToAscii(value, DTOA_FIXED, f,
    227                 Vector<char>(decimal_rep, kDecimalRepCapacity),
    228                 &sign, &decimal_rep_length, &decimal_point);
    229 
    230   // Create a representation that is padded with zeros if needed.
    231   int zero_prefix_length = 0;
    232   int zero_postfix_length = 0;
    233 
    234   if (decimal_point <= 0) {
    235     zero_prefix_length = -decimal_point + 1;
    236     decimal_point = 1;
    237   }
    238 
    239   if (zero_prefix_length + decimal_rep_length < decimal_point + f) {
    240     zero_postfix_length = decimal_point + f - decimal_rep_length -
    241                           zero_prefix_length;
    242   }
    243 
    244   unsigned rep_length =
    245       zero_prefix_length + decimal_rep_length + zero_postfix_length;
    246   SimpleStringBuilder rep_builder(rep_length + 1);
    247   rep_builder.AddPadding('0', zero_prefix_length);
    248   rep_builder.AddString(decimal_rep);
    249   rep_builder.AddPadding('0', zero_postfix_length);
    250   char* rep = rep_builder.Finalize();
    251 
    252   // Create the result string by appending a minus and putting in a
    253   // decimal point if needed.
    254   unsigned result_size = decimal_point + f + 2;
    255   SimpleStringBuilder builder(result_size + 1);
    256   if (negative) builder.AddCharacter('-');
    257   builder.AddSubstring(rep, decimal_point);
    258   if (f > 0) {
    259     builder.AddCharacter('.');
    260     builder.AddSubstring(rep + decimal_point, f);
    261   }
    262   DeleteArray(rep);
    263   return builder.Finalize();
    264 }
    265 
    266 
    267 static char* CreateExponentialRepresentation(char* decimal_rep,
    268                                              int exponent,
    269                                              bool negative,
    270                                              int significant_digits) {
    271   bool negative_exponent = false;
    272   if (exponent < 0) {
    273     negative_exponent = true;
    274     exponent = -exponent;
    275   }
    276 
    277   // Leave room in the result for appending a minus, for a period, the
    278   // letter 'e', a minus or a plus depending on the exponent, and a
    279   // three digit exponent.
    280   unsigned result_size = significant_digits + 7;
    281   SimpleStringBuilder builder(result_size + 1);
    282 
    283   if (negative) builder.AddCharacter('-');
    284   builder.AddCharacter(decimal_rep[0]);
    285   if (significant_digits != 1) {
    286     builder.AddCharacter('.');
    287     builder.AddString(decimal_rep + 1);
    288     int rep_length = StrLength(decimal_rep);
    289     builder.AddPadding('0', significant_digits - rep_length);
    290   }
    291 
    292   builder.AddCharacter('e');
    293   builder.AddCharacter(negative_exponent ? '-' : '+');
    294   builder.AddDecimalInteger(exponent);
    295   return builder.Finalize();
    296 }
    297 
    298 
    299 char* DoubleToExponentialCString(double value, int f) {
    300   const int kMaxDigitsAfterPoint = 20;
    301   // f might be -1 to signal that f was undefined in JavaScript.
    302   DCHECK(f >= -1 && f <= kMaxDigitsAfterPoint);
    303 
    304   bool negative = false;
    305   if (value < 0) {
    306     value = -value;
    307     negative = true;
    308   }
    309 
    310   // Find a sufficiently precise decimal representation of n.
    311   int decimal_point;
    312   int sign;
    313   // f corresponds to the digits after the point. There is always one digit
    314   // before the point. The number of requested_digits equals hence f + 1.
    315   // And we have to add one character for the null-terminator.
    316   const int kV8DtoaBufferCapacity = kMaxDigitsAfterPoint + 1 + 1;
    317   // Make sure that the buffer is big enough, even if we fall back to the
    318   // shortest representation (which happens when f equals -1).
    319   DCHECK(kBase10MaximalLength <= kMaxDigitsAfterPoint + 1);
    320   char decimal_rep[kV8DtoaBufferCapacity];
    321   int decimal_rep_length;
    322 
    323   if (f == -1) {
    324     DoubleToAscii(value, DTOA_SHORTEST, 0,
    325                   Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
    326                   &sign, &decimal_rep_length, &decimal_point);
    327     f = decimal_rep_length - 1;
    328   } else {
    329     DoubleToAscii(value, DTOA_PRECISION, f + 1,
    330                   Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
    331                   &sign, &decimal_rep_length, &decimal_point);
    332   }
    333   DCHECK(decimal_rep_length > 0);
    334   DCHECK(decimal_rep_length <= f + 1);
    335 
    336   int exponent = decimal_point - 1;
    337   char* result =
    338       CreateExponentialRepresentation(decimal_rep, exponent, negative, f+1);
    339 
    340   return result;
    341 }
    342 
    343 
    344 char* DoubleToPrecisionCString(double value, int p) {
    345   const int kMinimalDigits = 1;
    346   const int kMaximalDigits = 21;
    347   DCHECK(p >= kMinimalDigits && p <= kMaximalDigits);
    348   USE(kMinimalDigits);
    349 
    350   bool negative = false;
    351   if (value < 0) {
    352     value = -value;
    353     negative = true;
    354   }
    355 
    356   // Find a sufficiently precise decimal representation of n.
    357   int decimal_point;
    358   int sign;
    359   // Add one for the terminating null character.
    360   const int kV8DtoaBufferCapacity = kMaximalDigits + 1;
    361   char decimal_rep[kV8DtoaBufferCapacity];
    362   int decimal_rep_length;
    363 
    364   DoubleToAscii(value, DTOA_PRECISION, p,
    365                 Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
    366                 &sign, &decimal_rep_length, &decimal_point);
    367   DCHECK(decimal_rep_length <= p);
    368 
    369   int exponent = decimal_point - 1;
    370 
    371   char* result = NULL;
    372 
    373   if (exponent < -6 || exponent >= p) {
    374     result =
    375         CreateExponentialRepresentation(decimal_rep, exponent, negative, p);
    376   } else {
    377     // Use fixed notation.
    378     //
    379     // Leave room in the result for appending a minus, a period and in
    380     // the case where decimal_point is not positive for a zero in
    381     // front of the period.
    382     unsigned result_size = (decimal_point <= 0)
    383         ? -decimal_point + p + 3
    384         : p + 2;
    385     SimpleStringBuilder builder(result_size + 1);
    386     if (negative) builder.AddCharacter('-');
    387     if (decimal_point <= 0) {
    388       builder.AddString("0.");
    389       builder.AddPadding('0', -decimal_point);
    390       builder.AddString(decimal_rep);
    391       builder.AddPadding('0', p - decimal_rep_length);
    392     } else {
    393       const int m = Min(decimal_rep_length, decimal_point);
    394       builder.AddSubstring(decimal_rep, m);
    395       builder.AddPadding('0', decimal_point - decimal_rep_length);
    396       if (decimal_point < p) {
    397         builder.AddCharacter('.');
    398         const int extra = negative ? 2 : 1;
    399         if (decimal_rep_length > decimal_point) {
    400           const int len = StrLength(decimal_rep + decimal_point);
    401           const int n = Min(len, p - (builder.position() - extra));
    402           builder.AddSubstring(decimal_rep + decimal_point, n);
    403         }
    404         builder.AddPadding('0', extra + (p - builder.position()));
    405       }
    406     }
    407     result = builder.Finalize();
    408   }
    409 
    410   return result;
    411 }
    412 
    413 
    414 char* DoubleToRadixCString(double value, int radix) {
    415   DCHECK(radix >= 2 && radix <= 36);
    416 
    417   // Character array used for conversion.
    418   static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
    419 
    420   // Buffer for the integer part of the result. 1024 chars is enough
    421   // for max integer value in radix 2.  We need room for a sign too.
    422   static const int kBufferSize = 1100;
    423   char integer_buffer[kBufferSize];
    424   integer_buffer[kBufferSize - 1] = '\0';
    425 
    426   // Buffer for the decimal part of the result.  We only generate up
    427   // to kBufferSize - 1 chars for the decimal part.
    428   char decimal_buffer[kBufferSize];
    429   decimal_buffer[kBufferSize - 1] = '\0';
    430 
    431   // Make sure the value is positive.
    432   bool is_negative = value < 0.0;
    433   if (is_negative) value = -value;
    434 
    435   // Get the integer part and the decimal part.
    436   double integer_part = std::floor(value);
    437   double decimal_part = value - integer_part;
    438 
    439   // Convert the integer part starting from the back.  Always generate
    440   // at least one digit.
    441   int integer_pos = kBufferSize - 2;
    442   do {
    443     double remainder = std::fmod(integer_part, radix);
    444     integer_buffer[integer_pos--] = chars[static_cast<int>(remainder)];
    445     integer_part -= remainder;
    446     integer_part /= radix;
    447   } while (integer_part >= 1.0);
    448   // Sanity check.
    449   DCHECK(integer_pos > 0);
    450   // Add sign if needed.
    451   if (is_negative) integer_buffer[integer_pos--] = '-';
    452 
    453   // Convert the decimal part.  Repeatedly multiply by the radix to
    454   // generate the next char.  Never generate more than kBufferSize - 1
    455   // chars.
    456   //
    457   // TODO(1093998): We will often generate a full decimal_buffer of
    458   // chars because hitting zero will often not happen.  The right
    459   // solution would be to continue until the string representation can
    460   // be read back and yield the original value.  To implement this
    461   // efficiently, we probably have to modify dtoa.
    462   int decimal_pos = 0;
    463   while ((decimal_part > 0.0) && (decimal_pos < kBufferSize - 1)) {
    464     decimal_part *= radix;
    465     decimal_buffer[decimal_pos++] =
    466         chars[static_cast<int>(std::floor(decimal_part))];
    467     decimal_part -= std::floor(decimal_part);
    468   }
    469   decimal_buffer[decimal_pos] = '\0';
    470 
    471   // Compute the result size.
    472   int integer_part_size = kBufferSize - 2 - integer_pos;
    473   // Make room for zero termination.
    474   unsigned result_size = integer_part_size + decimal_pos;
    475   // If the number has a decimal part, leave room for the period.
    476   if (decimal_pos > 0) result_size++;
    477   // Allocate result and fill in the parts.
    478   SimpleStringBuilder builder(result_size + 1);
    479   builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size);
    480   if (decimal_pos > 0) builder.AddCharacter('.');
    481   builder.AddSubstring(decimal_buffer, decimal_pos);
    482   return builder.Finalize();
    483 }
    484 
    485 
    486 double StringToDouble(UnicodeCache* unicode_cache,
    487                       String* string,
    488                       int flags,
    489                       double empty_string_val) {
    490   DisallowHeapAllocation no_gc;
    491   String::FlatContent flat = string->GetFlatContent();
    492   // ECMA-262 section 15.1.2.3, empty string is NaN
    493   if (flat.IsOneByte()) {
    494     return StringToDouble(
    495         unicode_cache, flat.ToOneByteVector(), flags, empty_string_val);
    496   } else {
    497     return StringToDouble(
    498         unicode_cache, flat.ToUC16Vector(), flags, empty_string_val);
    499   }
    500 }
    501 
    502 
    503 } }  // namespace v8::internal
    504