• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/conversions.h"
6 
7 #include <limits.h>
8 #include <stdarg.h>
9 #include <cmath>
10 
11 #include "src/allocation.h"
12 #include "src/assert-scope.h"
13 #include "src/char-predicates-inl.h"
14 #include "src/codegen.h"
15 #include "src/conversions-inl.h"
16 #include "src/dtoa.h"
17 #include "src/factory.h"
18 #include "src/handles.h"
19 #include "src/list-inl.h"
20 #include "src/strtod.h"
21 #include "src/utils.h"
22 
23 #ifndef _STLP_VENDOR_CSTD
24 // STLPort doesn't import fpclassify into the std namespace.
25 using std::fpclassify;
26 #endif
27 
28 namespace v8 {
29 namespace internal {
30 
31 
32 namespace {
33 
34 // C++-style iterator adaptor for StringCharacterStream
35 // (unlike C++ iterators the end-marker has different type).
36 class StringCharacterStreamIterator {
37  public:
38   class EndMarker {};
39 
40   explicit StringCharacterStreamIterator(StringCharacterStream* stream);
41 
42   uint16_t operator*() const;
43   void operator++();
operator ==(EndMarker const &) const44   bool operator==(EndMarker const&) const { return end_; }
operator !=(EndMarker const & m) const45   bool operator!=(EndMarker const& m) const { return !end_; }
46 
47  private:
48   StringCharacterStream* const stream_;
49   uint16_t current_;
50   bool end_;
51 };
52 
53 
StringCharacterStreamIterator(StringCharacterStream * stream)54 StringCharacterStreamIterator::StringCharacterStreamIterator(
55     StringCharacterStream* stream) : stream_(stream) {
56   ++(*this);
57 }
58 
operator *() const59 uint16_t StringCharacterStreamIterator::operator*() const {
60   return current_;
61 }
62 
63 
operator ++()64 void StringCharacterStreamIterator::operator++() {
65   end_ = !stream_->HasMore();
66   if (!end_) {
67     current_ = stream_->GetNext();
68   }
69 }
70 }  // End anonymous namespace.
71 
72 
StringToDouble(UnicodeCache * unicode_cache,const char * str,int flags,double empty_string_val)73 double StringToDouble(UnicodeCache* unicode_cache,
74                       const char* str, int flags, double empty_string_val) {
75   // We cast to const uint8_t* here to avoid instantiating the
76   // InternalStringToDouble() template for const char* as well.
77   const uint8_t* start = reinterpret_cast<const uint8_t*>(str);
78   const uint8_t* end = start + StrLength(str);
79   return InternalStringToDouble(unicode_cache, start, end, flags,
80                                 empty_string_val);
81 }
82 
83 
StringToDouble(UnicodeCache * unicode_cache,Vector<const uint8_t> str,int flags,double empty_string_val)84 double StringToDouble(UnicodeCache* unicode_cache,
85                       Vector<const uint8_t> str,
86                       int flags,
87                       double empty_string_val) {
88   // We cast to const uint8_t* here to avoid instantiating the
89   // InternalStringToDouble() template for const char* as well.
90   const uint8_t* start = reinterpret_cast<const uint8_t*>(str.start());
91   const uint8_t* end = start + str.length();
92   return InternalStringToDouble(unicode_cache, start, end, flags,
93                                 empty_string_val);
94 }
95 
96 
StringToDouble(UnicodeCache * unicode_cache,Vector<const uc16> str,int flags,double empty_string_val)97 double StringToDouble(UnicodeCache* unicode_cache,
98                       Vector<const uc16> str,
99                       int flags,
100                       double empty_string_val) {
101   const uc16* end = str.start() + str.length();
102   return InternalStringToDouble(unicode_cache, str.start(), end, flags,
103                                 empty_string_val);
104 }
105 
106 
107 // Converts a string into an integer.
StringToInt(UnicodeCache * unicode_cache,Vector<const uint8_t> vector,int radix)108 double StringToInt(UnicodeCache* unicode_cache,
109                    Vector<const uint8_t> vector,
110                    int radix) {
111   return InternalStringToInt(
112       unicode_cache, vector.start(), vector.start() + vector.length(), radix);
113 }
114 
115 
StringToInt(UnicodeCache * unicode_cache,Vector<const uc16> vector,int radix)116 double StringToInt(UnicodeCache* unicode_cache,
117                    Vector<const uc16> vector,
118                    int radix) {
119   return InternalStringToInt(
120       unicode_cache, vector.start(), vector.start() + vector.length(), radix);
121 }
122 
123 
DoubleToCString(double v,Vector<char> buffer)124 const char* DoubleToCString(double v, Vector<char> buffer) {
125   switch (fpclassify(v)) {
126     case FP_NAN: return "NaN";
127     case FP_INFINITE: return (v < 0.0 ? "-Infinity" : "Infinity");
128     case FP_ZERO: return "0";
129     default: {
130       SimpleStringBuilder builder(buffer.start(), buffer.length());
131       int decimal_point;
132       int sign;
133       const int kV8DtoaBufferCapacity = kBase10MaximalLength + 1;
134       char decimal_rep[kV8DtoaBufferCapacity];
135       int length;
136 
137       DoubleToAscii(v, DTOA_SHORTEST, 0,
138                     Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
139                     &sign, &length, &decimal_point);
140 
141       if (sign) builder.AddCharacter('-');
142 
143       if (length <= decimal_point && decimal_point <= 21) {
144         // ECMA-262 section 9.8.1 step 6.
145         builder.AddString(decimal_rep);
146         builder.AddPadding('0', decimal_point - length);
147 
148       } else if (0 < decimal_point && decimal_point <= 21) {
149         // ECMA-262 section 9.8.1 step 7.
150         builder.AddSubstring(decimal_rep, decimal_point);
151         builder.AddCharacter('.');
152         builder.AddString(decimal_rep + decimal_point);
153 
154       } else if (decimal_point <= 0 && decimal_point > -6) {
155         // ECMA-262 section 9.8.1 step 8.
156         builder.AddString("0.");
157         builder.AddPadding('0', -decimal_point);
158         builder.AddString(decimal_rep);
159 
160       } else {
161         // ECMA-262 section 9.8.1 step 9 and 10 combined.
162         builder.AddCharacter(decimal_rep[0]);
163         if (length != 1) {
164           builder.AddCharacter('.');
165           builder.AddString(decimal_rep + 1);
166         }
167         builder.AddCharacter('e');
168         builder.AddCharacter((decimal_point >= 0) ? '+' : '-');
169         int exponent = decimal_point - 1;
170         if (exponent < 0) exponent = -exponent;
171         builder.AddDecimalInteger(exponent);
172       }
173       return builder.Finalize();
174     }
175   }
176 }
177 
178 
IntToCString(int n,Vector<char> buffer)179 const char* IntToCString(int n, Vector<char> buffer) {
180   bool negative = false;
181   if (n < 0) {
182     // We must not negate the most negative int.
183     if (n == kMinInt) return DoubleToCString(n, buffer);
184     negative = true;
185     n = -n;
186   }
187   // Build the string backwards from the least significant digit.
188   int i = buffer.length();
189   buffer[--i] = '\0';
190   do {
191     buffer[--i] = '0' + (n % 10);
192     n /= 10;
193   } while (n);
194   if (negative) buffer[--i] = '-';
195   return buffer.start() + i;
196 }
197 
198 
DoubleToFixedCString(double value,int f)199 char* DoubleToFixedCString(double value, int f) {
200   const int kMaxDigitsBeforePoint = 21;
201   const double kFirstNonFixed = 1e21;
202   const int kMaxDigitsAfterPoint = 20;
203   DCHECK(f >= 0);
204   DCHECK(f <= kMaxDigitsAfterPoint);
205 
206   bool negative = false;
207   double abs_value = value;
208   if (value < 0) {
209     abs_value = -value;
210     negative = true;
211   }
212 
213   // If abs_value has more than kMaxDigitsBeforePoint digits before the point
214   // use the non-fixed conversion routine.
215   if (abs_value >= kFirstNonFixed) {
216     char arr[100];
217     Vector<char> buffer(arr, arraysize(arr));
218     return StrDup(DoubleToCString(value, buffer));
219   }
220 
221   // Find a sufficiently precise decimal representation of n.
222   int decimal_point;
223   int sign;
224   // Add space for the '\0' byte.
225   const int kDecimalRepCapacity =
226       kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 1;
227   char decimal_rep[kDecimalRepCapacity];
228   int decimal_rep_length;
229   DoubleToAscii(value, DTOA_FIXED, f,
230                 Vector<char>(decimal_rep, kDecimalRepCapacity),
231                 &sign, &decimal_rep_length, &decimal_point);
232 
233   // Create a representation that is padded with zeros if needed.
234   int zero_prefix_length = 0;
235   int zero_postfix_length = 0;
236 
237   if (decimal_point <= 0) {
238     zero_prefix_length = -decimal_point + 1;
239     decimal_point = 1;
240   }
241 
242   if (zero_prefix_length + decimal_rep_length < decimal_point + f) {
243     zero_postfix_length = decimal_point + f - decimal_rep_length -
244                           zero_prefix_length;
245   }
246 
247   unsigned rep_length =
248       zero_prefix_length + decimal_rep_length + zero_postfix_length;
249   SimpleStringBuilder rep_builder(rep_length + 1);
250   rep_builder.AddPadding('0', zero_prefix_length);
251   rep_builder.AddString(decimal_rep);
252   rep_builder.AddPadding('0', zero_postfix_length);
253   char* rep = rep_builder.Finalize();
254 
255   // Create the result string by appending a minus and putting in a
256   // decimal point if needed.
257   unsigned result_size = decimal_point + f + 2;
258   SimpleStringBuilder builder(result_size + 1);
259   if (negative) builder.AddCharacter('-');
260   builder.AddSubstring(rep, decimal_point);
261   if (f > 0) {
262     builder.AddCharacter('.');
263     builder.AddSubstring(rep + decimal_point, f);
264   }
265   DeleteArray(rep);
266   return builder.Finalize();
267 }
268 
269 
CreateExponentialRepresentation(char * decimal_rep,int exponent,bool negative,int significant_digits)270 static char* CreateExponentialRepresentation(char* decimal_rep,
271                                              int exponent,
272                                              bool negative,
273                                              int significant_digits) {
274   bool negative_exponent = false;
275   if (exponent < 0) {
276     negative_exponent = true;
277     exponent = -exponent;
278   }
279 
280   // Leave room in the result for appending a minus, for a period, the
281   // letter 'e', a minus or a plus depending on the exponent, and a
282   // three digit exponent.
283   unsigned result_size = significant_digits + 7;
284   SimpleStringBuilder builder(result_size + 1);
285 
286   if (negative) builder.AddCharacter('-');
287   builder.AddCharacter(decimal_rep[0]);
288   if (significant_digits != 1) {
289     builder.AddCharacter('.');
290     builder.AddString(decimal_rep + 1);
291     int rep_length = StrLength(decimal_rep);
292     builder.AddPadding('0', significant_digits - rep_length);
293   }
294 
295   builder.AddCharacter('e');
296   builder.AddCharacter(negative_exponent ? '-' : '+');
297   builder.AddDecimalInteger(exponent);
298   return builder.Finalize();
299 }
300 
301 
DoubleToExponentialCString(double value,int f)302 char* DoubleToExponentialCString(double value, int f) {
303   const int kMaxDigitsAfterPoint = 20;
304   // f might be -1 to signal that f was undefined in JavaScript.
305   DCHECK(f >= -1 && f <= kMaxDigitsAfterPoint);
306 
307   bool negative = false;
308   if (value < 0) {
309     value = -value;
310     negative = true;
311   }
312 
313   // Find a sufficiently precise decimal representation of n.
314   int decimal_point;
315   int sign;
316   // f corresponds to the digits after the point. There is always one digit
317   // before the point. The number of requested_digits equals hence f + 1.
318   // And we have to add one character for the null-terminator.
319   const int kV8DtoaBufferCapacity = kMaxDigitsAfterPoint + 1 + 1;
320   // Make sure that the buffer is big enough, even if we fall back to the
321   // shortest representation (which happens when f equals -1).
322   DCHECK(kBase10MaximalLength <= kMaxDigitsAfterPoint + 1);
323   char decimal_rep[kV8DtoaBufferCapacity];
324   int decimal_rep_length;
325 
326   if (f == -1) {
327     DoubleToAscii(value, DTOA_SHORTEST, 0,
328                   Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
329                   &sign, &decimal_rep_length, &decimal_point);
330     f = decimal_rep_length - 1;
331   } else {
332     DoubleToAscii(value, DTOA_PRECISION, f + 1,
333                   Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
334                   &sign, &decimal_rep_length, &decimal_point);
335   }
336   DCHECK(decimal_rep_length > 0);
337   DCHECK(decimal_rep_length <= f + 1);
338 
339   int exponent = decimal_point - 1;
340   char* result =
341       CreateExponentialRepresentation(decimal_rep, exponent, negative, f+1);
342 
343   return result;
344 }
345 
346 
DoubleToPrecisionCString(double value,int p)347 char* DoubleToPrecisionCString(double value, int p) {
348   const int kMinimalDigits = 1;
349   const int kMaximalDigits = 21;
350   DCHECK(p >= kMinimalDigits && p <= kMaximalDigits);
351   USE(kMinimalDigits);
352 
353   bool negative = false;
354   if (value < 0) {
355     value = -value;
356     negative = true;
357   }
358 
359   // Find a sufficiently precise decimal representation of n.
360   int decimal_point;
361   int sign;
362   // Add one for the terminating null character.
363   const int kV8DtoaBufferCapacity = kMaximalDigits + 1;
364   char decimal_rep[kV8DtoaBufferCapacity];
365   int decimal_rep_length;
366 
367   DoubleToAscii(value, DTOA_PRECISION, p,
368                 Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
369                 &sign, &decimal_rep_length, &decimal_point);
370   DCHECK(decimal_rep_length <= p);
371 
372   int exponent = decimal_point - 1;
373 
374   char* result = NULL;
375 
376   if (exponent < -6 || exponent >= p) {
377     result =
378         CreateExponentialRepresentation(decimal_rep, exponent, negative, p);
379   } else {
380     // Use fixed notation.
381     //
382     // Leave room in the result for appending a minus, a period and in
383     // the case where decimal_point is not positive for a zero in
384     // front of the period.
385     unsigned result_size = (decimal_point <= 0)
386         ? -decimal_point + p + 3
387         : p + 2;
388     SimpleStringBuilder builder(result_size + 1);
389     if (negative) builder.AddCharacter('-');
390     if (decimal_point <= 0) {
391       builder.AddString("0.");
392       builder.AddPadding('0', -decimal_point);
393       builder.AddString(decimal_rep);
394       builder.AddPadding('0', p - decimal_rep_length);
395     } else {
396       const int m = Min(decimal_rep_length, decimal_point);
397       builder.AddSubstring(decimal_rep, m);
398       builder.AddPadding('0', decimal_point - decimal_rep_length);
399       if (decimal_point < p) {
400         builder.AddCharacter('.');
401         const int extra = negative ? 2 : 1;
402         if (decimal_rep_length > decimal_point) {
403           const int len = StrLength(decimal_rep + decimal_point);
404           const int n = Min(len, p - (builder.position() - extra));
405           builder.AddSubstring(decimal_rep + decimal_point, n);
406         }
407         builder.AddPadding('0', extra + (p - builder.position()));
408       }
409     }
410     result = builder.Finalize();
411   }
412 
413   return result;
414 }
415 
DoubleToRadixCString(double value,int radix)416 char* DoubleToRadixCString(double value, int radix) {
417   DCHECK(radix >= 2 && radix <= 36);
418   DCHECK(std::isfinite(value));
419   DCHECK_NE(0.0, value);
420   // Character array used for conversion.
421   static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
422 
423   // Temporary buffer for the result. We start with the decimal point in the
424   // middle and write to the left for the integer part and to the right for the
425   // fractional part. 1024 characters for the exponent and 52 for the mantissa
426   // either way, with additional space for sign, decimal point and string
427   // termination should be sufficient.
428   static const int kBufferSize = 2200;
429   char buffer[kBufferSize];
430   int integer_cursor = kBufferSize / 2;
431   int fraction_cursor = integer_cursor;
432 
433   bool negative = value < 0;
434   if (negative) value = -value;
435 
436   // Split the value into an integer part and a fractional part.
437   double integer = std::floor(value);
438   double fraction = value - integer;
439   // We only compute fractional digits up to the input double's precision.
440   double delta = 0.5 * (Double(value).NextDouble() - value);
441   delta = std::max(Double(0.0).NextDouble(), delta);
442   DCHECK_GT(delta, 0.0);
443   if (fraction > delta) {
444     // Insert decimal point.
445     buffer[fraction_cursor++] = '.';
446     do {
447       // Shift up by one digit.
448       fraction *= radix;
449       delta *= radix;
450       // Write digit.
451       int digit = static_cast<int>(fraction);
452       buffer[fraction_cursor++] = chars[digit];
453       // Calculate remainder.
454       fraction -= digit;
455       // Round to even.
456       if (fraction > 0.5 || (fraction == 0.5 && (digit & 1))) {
457         if (fraction + delta > 1) {
458           // We need to back trace already written digits in case of carry-over.
459           while (true) {
460             fraction_cursor--;
461             if (fraction_cursor == kBufferSize / 2) {
462               CHECK_EQ('.', buffer[fraction_cursor]);
463               // Carry over to the integer part.
464               integer += 1;
465               break;
466             }
467             char c = buffer[fraction_cursor];
468             // Reconstruct digit.
469             int digit = c > '9' ? (c - 'a' + 10) : (c - '0');
470             if (digit + 1 < radix) {
471               buffer[fraction_cursor++] = chars[digit + 1];
472               break;
473             }
474           }
475           break;
476         }
477       }
478     } while (fraction > delta);
479   }
480 
481   // Compute integer digits. Fill unrepresented digits with zero.
482   while (Double(integer / radix).Exponent() > 0) {
483     integer /= radix;
484     buffer[--integer_cursor] = '0';
485   }
486   do {
487     double remainder = modulo(integer, radix);
488     buffer[--integer_cursor] = chars[static_cast<int>(remainder)];
489     integer = (integer - remainder) / radix;
490   } while (integer > 0);
491 
492   // Add sign and terminate string.
493   if (negative) buffer[--integer_cursor] = '-';
494   buffer[fraction_cursor++] = '\0';
495   DCHECK_LT(fraction_cursor, kBufferSize);
496   DCHECK_LE(0, integer_cursor);
497   // Allocate new string as return value.
498   char* result = NewArray<char>(fraction_cursor - integer_cursor);
499   memcpy(result, buffer + integer_cursor, fraction_cursor - integer_cursor);
500   return result;
501 }
502 
503 
504 // ES6 18.2.4 parseFloat(string)
StringToDouble(UnicodeCache * unicode_cache,Handle<String> string,int flags,double empty_string_val)505 double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string,
506                       int flags, double empty_string_val) {
507   Handle<String> flattened = String::Flatten(string);
508   {
509     DisallowHeapAllocation no_gc;
510     String::FlatContent flat = flattened->GetFlatContent();
511     DCHECK(flat.IsFlat());
512     if (flat.IsOneByte()) {
513       return StringToDouble(unicode_cache, flat.ToOneByteVector(), flags,
514                             empty_string_val);
515     } else {
516       return StringToDouble(unicode_cache, flat.ToUC16Vector(), flags,
517                             empty_string_val);
518     }
519   }
520 }
521 
522 
IsSpecialIndex(UnicodeCache * unicode_cache,String * string)523 bool IsSpecialIndex(UnicodeCache* unicode_cache, String* string) {
524   // Max length of canonical double: -X.XXXXXXXXXXXXXXXXX-eXXX
525   const int kBufferSize = 24;
526   const int length = string->length();
527   if (length == 0 || length > kBufferSize) return false;
528   uint16_t buffer[kBufferSize];
529   String::WriteToFlat(string, buffer, 0, length);
530   // If the first char is not a digit or a '-' or we can't match 'NaN' or
531   // '(-)Infinity', bailout immediately.
532   int offset = 0;
533   if (!IsDecimalDigit(buffer[0])) {
534     if (buffer[0] == '-') {
535       if (length == 1) return false;  // Just '-' is bad.
536       if (!IsDecimalDigit(buffer[1])) {
537         if (buffer[1] == 'I' && length == 9) {
538           // Allow matching of '-Infinity' below.
539         } else {
540           return false;
541         }
542       }
543       offset++;
544     } else if (buffer[0] == 'I' && length == 8) {
545       // Allow matching of 'Infinity' below.
546     } else if (buffer[0] == 'N' && length == 3) {
547       // Match NaN.
548       return buffer[1] == 'a' && buffer[2] == 'N';
549     } else {
550       return false;
551     }
552   }
553   // Expected fast path: key is an integer.
554   static const int kRepresentableIntegerLength = 15;  // (-)XXXXXXXXXXXXXXX
555   if (length - offset <= kRepresentableIntegerLength) {
556     const int initial_offset = offset;
557     bool matches = true;
558     for (; offset < length; offset++) {
559       matches &= IsDecimalDigit(buffer[offset]);
560     }
561     if (matches) {
562       // Match 0 and -0.
563       if (buffer[initial_offset] == '0') return initial_offset == length - 1;
564       return true;
565     }
566   }
567   // Slow path: test DoubleToString(StringToDouble(string)) == string.
568   Vector<const uint16_t> vector(buffer, length);
569   double d = StringToDouble(unicode_cache, vector, NO_FLAGS);
570   if (std::isnan(d)) return false;
571   // Compute reverse string.
572   char reverse_buffer[kBufferSize + 1];  // Result will be /0 terminated.
573   Vector<char> reverse_vector(reverse_buffer, arraysize(reverse_buffer));
574   const char* reverse_string = DoubleToCString(d, reverse_vector);
575   for (int i = 0; i < length; ++i) {
576     if (static_cast<uint16_t>(reverse_string[i]) != buffer[i]) return false;
577   }
578   return true;
579 }
580 }  // namespace internal
581 }  // namespace v8
582