• 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 <stdarg.h>
6 #include <limits.h>
7 #include <cmath>
8 
9 #include "src/v8.h"
10 
11 #include "src/assert-scope.h"
12 #include "src/conversions.h"
13 #include "src/conversions-inl.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++();
operator ==(EndMarker const &) const41   bool operator==(EndMarker const&) const { return end_; }
operator !=(EndMarker const & m) const42   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 
StringCharacterStreamIterator(StringCharacterStream * stream)51 StringCharacterStreamIterator::StringCharacterStreamIterator(
52     StringCharacterStream* stream) : stream_(stream) {
53   ++(*this);
54 }
55 
operator *() const56 uint16_t StringCharacterStreamIterator::operator*() const {
57   return current_;
58 }
59 
60 
operator ++()61 void StringCharacterStreamIterator::operator++() {
62   end_ = !stream_->HasMore();
63   if (!end_) {
64     current_ = stream_->GetNext();
65   }
66 }
67 }  // End anonymous namespace.
68 
69 
StringToDouble(UnicodeCache * unicode_cache,const char * str,int flags,double empty_string_val)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 
StringToDouble(UnicodeCache * unicode_cache,Vector<const uint8_t> str,int flags,double empty_string_val)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 
StringToDouble(UnicodeCache * unicode_cache,Vector<const uc16> str,int flags,double empty_string_val)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.
StringToInt(UnicodeCache * unicode_cache,Vector<const uint8_t> vector,int radix)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 
StringToInt(UnicodeCache * unicode_cache,Vector<const uc16> vector,int radix)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 
DoubleToCString(double v,Vector<char> buffer)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 
IntToCString(int n,Vector<char> buffer)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 
DoubleToFixedCString(double value,int f)196 char* DoubleToFixedCString(double value, int f) {
197   const int kMaxDigitsBeforePoint = 21;
198   const double kFirstNonFixed = 1e21;
199   const int kMaxDigitsAfterPoint = 20;
200   ASSERT(f >= 0);
201   ASSERT(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, ARRAY_SIZE(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 
CreateExponentialRepresentation(char * decimal_rep,int exponent,bool negative,int significant_digits)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 
DoubleToExponentialCString(double value,int f)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   ASSERT(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   ASSERT(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   ASSERT(decimal_rep_length > 0);
334   ASSERT(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 
DoubleToPrecisionCString(double value,int p)344 char* DoubleToPrecisionCString(double value, int p) {
345   const int kMinimalDigits = 1;
346   const int kMaximalDigits = 21;
347   ASSERT(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   ASSERT(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 
DoubleToRadixCString(double value,int radix)414 char* DoubleToRadixCString(double value, int radix) {
415   ASSERT(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   ASSERT(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 
StringToDouble(UnicodeCache * unicode_cache,String * string,int flags,double empty_string_val)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.IsAscii()) {
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