V8 Project
conversions.cc
Go to the documentation of this file.
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).
34  public:
35  class EndMarker {};
36 
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:
47  bool end_;
48 };
49 
50 
51 StringCharacterStreamIterator::StringCharacterStreamIterator(
52  StringCharacterStream* stream) : stream_(stream) {
53  ++(*this);
54 }
55 
57  return current_;
58 }
59 
60 
62  end_ = !stream_->HasMore();
63  if (!end_) {
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,
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,
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 
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) {
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
void AddDecimalInteger(int value)
Definition: utils.cc:44
void AddPadding(char c, int count)
Definition: utils.cc:37
void AddSubstring(const char *s, int n)
Definition: utils.cc:29
void AddString(const char *s)
Definition: utils.cc:24
Vector< const uint8_t > ToOneByteVector()
Definition: objects.h:8639
Vector< const uc16 > ToUC16Vector()
Definition: objects.h:8645
T * start() const
Definition: vector.h:47
int length() const
Definition: vector.h:41
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define DCHECK(condition)
Definition: logging.h:205
void USE(T)
Definition: macros.h:322
#define arraysize(array)
Definition: macros.h:86
unsigned short uint16_t
Definition: unicode.cc:23
void DeleteArray(T *array)
Definition: allocation.h:68
const int kBase10MaximalLength
Definition: dtoa.h:27
char * DoubleToRadixCString(double value, int radix)
Definition: conversions.cc:414
static char * CreateExponentialRepresentation(char *decimal_rep, int exponent, bool negative, int significant_digits)
Definition: conversions.cc:267
double InternalStringToDouble(UnicodeCache *unicode_cache, Iterator current, EndMark end, int flags, double empty_string_val)
char * DoubleToFixedCString(double value, int f)
Definition: conversions.cc:196
static LifetimePosition Min(LifetimePosition a, LifetimePosition b)
char * DoubleToExponentialCString(double value, int f)
Definition: conversions.cc:299
char * DoubleToPrecisionCString(double value, int p)
Definition: conversions.cc:344
double StringToInt(UnicodeCache *unicode_cache, Vector< const uint8_t > vector, int radix)
Definition: conversions.cc:105
const int kMinInt
Definition: globals.h:110
void DoubleToAscii(double v, DtoaMode mode, int requested_digits, Vector< char > buffer, int *sign, int *length, int *point)
Definition: dtoa.cc:33
@ DTOA_PRECISION
Definition: dtoa.h:21
@ DTOA_FIXED
Definition: dtoa.h:19
@ DTOA_SHORTEST
Definition: dtoa.h:15
double InternalStringToInt(UnicodeCache *unicode_cache, Iterator current, EndMark end, int radix)
const char * DoubleToCString(double v, Vector< char > buffer)
Definition: conversions.cc:121
uint16_t uc16
Definition: globals.h:184
const char * IntToCString(int n, Vector< char > buffer)
Definition: conversions.cc:176
int StrLength(const char *string)
Definition: vector.h:147
double StringToDouble(UnicodeCache *unicode_cache, const char *str, int flags, double empty_string_val)
Definition: conversions.cc:70
char * StrDup(const char *str)
Definition: allocation.cc:67
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
@ FP_INFINITE
Definition: win32-math.h:21
@ FP_ZERO
Definition: win32-math.h:22
@ FP_NAN
Definition: win32-math.h:20
int fpclassify(double x)