OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 10 matching lines...) Expand all Loading... |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include <stdarg.h> | 28 #include <stdarg.h> |
29 #include <limits.h> | 29 #include <limits.h> |
30 | 30 |
31 #include "v8.h" | |
32 | |
33 #include "conversions-inl.h" | 31 #include "conversions-inl.h" |
34 #include "dtoa.h" | 32 #include "dtoa.h" |
35 #include "factory.h" | |
36 #include "scanner-base.h" | 33 #include "scanner-base.h" |
37 #include "strtod.h" | 34 #include "strtod.h" |
| 35 #include "utils.h" |
38 | 36 |
39 namespace v8 { | 37 namespace v8 { |
40 namespace internal { | 38 namespace internal { |
41 | 39 |
42 namespace { | |
43 | |
44 // C++-style iterator adaptor for StringInputBuffer | |
45 // (unlike C++ iterators the end-marker has different type). | |
46 class StringInputBufferIterator { | |
47 public: | |
48 class EndMarker {}; | |
49 | |
50 explicit StringInputBufferIterator(StringInputBuffer* buffer); | |
51 | |
52 int operator*() const; | |
53 void operator++(); | |
54 bool operator==(EndMarker const&) const { return end_; } | |
55 bool operator!=(EndMarker const& m) const { return !end_; } | |
56 | |
57 private: | |
58 StringInputBuffer* const buffer_; | |
59 int current_; | |
60 bool end_; | |
61 }; | |
62 | |
63 | |
64 StringInputBufferIterator::StringInputBufferIterator( | |
65 StringInputBuffer* buffer) : buffer_(buffer) { | |
66 ++(*this); | |
67 } | |
68 | |
69 int StringInputBufferIterator::operator*() const { | |
70 return current_; | |
71 } | |
72 | |
73 | |
74 void StringInputBufferIterator::operator++() { | |
75 end_ = !buffer_->has_more(); | |
76 if (!end_) { | |
77 current_ = buffer_->GetNext(); | |
78 } | |
79 } | |
80 } | |
81 | |
82 | |
83 template <class Iterator, class EndMark> | |
84 static bool SubStringEquals(Iterator* current, | |
85 EndMark end, | |
86 const char* substring) { | |
87 ASSERT(**current == *substring); | |
88 for (substring++; *substring != '\0'; substring++) { | |
89 ++*current; | |
90 if (*current == end || **current != *substring) return false; | |
91 } | |
92 ++*current; | |
93 return true; | |
94 } | |
95 | |
96 | |
97 // Maximum number of significant digits in decimal representation. | |
98 // The longest possible double in decimal representation is | |
99 // (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074 | |
100 // (768 digits). If we parse a number whose first digits are equal to a | |
101 // mean of 2 adjacent doubles (that could have up to 769 digits) the result | |
102 // must be rounded to the bigger one unless the tail consists of zeros, so | |
103 // we don't need to preserve all the digits. | |
104 const int kMaxSignificantDigits = 772; | |
105 | |
106 | |
107 static const double JUNK_STRING_VALUE = OS::nan_value(); | |
108 | |
109 | |
110 // Returns true if a nonspace found and false if the end has reached. | |
111 template <class Iterator, class EndMark> | |
112 static inline bool AdvanceToNonspace(UnicodeCache* unicode_cache, | |
113 Iterator* current, | |
114 EndMark end) { | |
115 while (*current != end) { | |
116 if (!unicode_cache->IsWhiteSpace(**current)) return true; | |
117 ++*current; | |
118 } | |
119 return false; | |
120 } | |
121 | |
122 | |
123 static bool isDigit(int x, int radix) { | |
124 return (x >= '0' && x <= '9' && x < '0' + radix) | |
125 || (radix > 10 && x >= 'a' && x < 'a' + radix - 10) | |
126 || (radix > 10 && x >= 'A' && x < 'A' + radix - 10); | |
127 } | |
128 | |
129 | |
130 static double SignedZero(bool negative) { | |
131 return negative ? -0.0 : 0.0; | |
132 } | |
133 | |
134 | |
135 // Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end. | |
136 template <int radix_log_2, class Iterator, class EndMark> | |
137 static double InternalStringToIntDouble(UnicodeCache* unicode_cache, | |
138 Iterator current, | |
139 EndMark end, | |
140 bool negative, | |
141 bool allow_trailing_junk) { | |
142 ASSERT(current != end); | |
143 | |
144 // Skip leading 0s. | |
145 while (*current == '0') { | |
146 ++current; | |
147 if (current == end) return SignedZero(negative); | |
148 } | |
149 | |
150 int64_t number = 0; | |
151 int exponent = 0; | |
152 const int radix = (1 << radix_log_2); | |
153 | |
154 do { | |
155 int digit; | |
156 if (*current >= '0' && *current <= '9' && *current < '0' + radix) { | |
157 digit = static_cast<char>(*current) - '0'; | |
158 } else if (radix > 10 && *current >= 'a' && *current < 'a' + radix - 10) { | |
159 digit = static_cast<char>(*current) - 'a' + 10; | |
160 } else if (radix > 10 && *current >= 'A' && *current < 'A' + radix - 10) { | |
161 digit = static_cast<char>(*current) - 'A' + 10; | |
162 } else { | |
163 if (allow_trailing_junk || | |
164 !AdvanceToNonspace(unicode_cache, ¤t, end)) { | |
165 break; | |
166 } else { | |
167 return JUNK_STRING_VALUE; | |
168 } | |
169 } | |
170 | |
171 number = number * radix + digit; | |
172 int overflow = static_cast<int>(number >> 53); | |
173 if (overflow != 0) { | |
174 // Overflow occurred. Need to determine which direction to round the | |
175 // result. | |
176 int overflow_bits_count = 1; | |
177 while (overflow > 1) { | |
178 overflow_bits_count++; | |
179 overflow >>= 1; | |
180 } | |
181 | |
182 int dropped_bits_mask = ((1 << overflow_bits_count) - 1); | |
183 int dropped_bits = static_cast<int>(number) & dropped_bits_mask; | |
184 number >>= overflow_bits_count; | |
185 exponent = overflow_bits_count; | |
186 | |
187 bool zero_tail = true; | |
188 while (true) { | |
189 ++current; | |
190 if (current == end || !isDigit(*current, radix)) break; | |
191 zero_tail = zero_tail && *current == '0'; | |
192 exponent += radix_log_2; | |
193 } | |
194 | |
195 if (!allow_trailing_junk && | |
196 AdvanceToNonspace(unicode_cache, ¤t, end)) { | |
197 return JUNK_STRING_VALUE; | |
198 } | |
199 | |
200 int middle_value = (1 << (overflow_bits_count - 1)); | |
201 if (dropped_bits > middle_value) { | |
202 number++; // Rounding up. | |
203 } else if (dropped_bits == middle_value) { | |
204 // Rounding to even to consistency with decimals: half-way case rounds | |
205 // up if significant part is odd and down otherwise. | |
206 if ((number & 1) != 0 || !zero_tail) { | |
207 number++; // Rounding up. | |
208 } | |
209 } | |
210 | |
211 // Rounding up may cause overflow. | |
212 if ((number & ((int64_t)1 << 53)) != 0) { | |
213 exponent++; | |
214 number >>= 1; | |
215 } | |
216 break; | |
217 } | |
218 ++current; | |
219 } while (current != end); | |
220 | |
221 ASSERT(number < ((int64_t)1 << 53)); | |
222 ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number); | |
223 | |
224 if (exponent == 0) { | |
225 if (negative) { | |
226 if (number == 0) return -0.0; | |
227 number = -number; | |
228 } | |
229 return static_cast<double>(number); | |
230 } | |
231 | |
232 ASSERT(number != 0); | |
233 // The double could be constructed faster from number (mantissa), exponent | |
234 // and sign. Assuming it's a rare case more simple code is used. | |
235 return static_cast<double>(negative ? -number : number) * pow(2.0, exponent); | |
236 } | |
237 | |
238 | |
239 template <class Iterator, class EndMark> | |
240 static double InternalStringToInt(UnicodeCache* unicode_cache, | |
241 Iterator current, | |
242 EndMark end, | |
243 int radix) { | |
244 const bool allow_trailing_junk = true; | |
245 const double empty_string_val = JUNK_STRING_VALUE; | |
246 | |
247 if (!AdvanceToNonspace(unicode_cache, ¤t, end)) { | |
248 return empty_string_val; | |
249 } | |
250 | |
251 bool negative = false; | |
252 bool leading_zero = false; | |
253 | |
254 if (*current == '+') { | |
255 // Ignore leading sign; skip following spaces. | |
256 ++current; | |
257 if (current == end) { | |
258 return JUNK_STRING_VALUE; | |
259 } | |
260 } else if (*current == '-') { | |
261 ++current; | |
262 if (current == end) { | |
263 return JUNK_STRING_VALUE; | |
264 } | |
265 negative = true; | |
266 } | |
267 | |
268 if (radix == 0) { | |
269 // Radix detection. | |
270 if (*current == '0') { | |
271 ++current; | |
272 if (current == end) return SignedZero(negative); | |
273 if (*current == 'x' || *current == 'X') { | |
274 radix = 16; | |
275 ++current; | |
276 if (current == end) return JUNK_STRING_VALUE; | |
277 } else { | |
278 radix = 8; | |
279 leading_zero = true; | |
280 } | |
281 } else { | |
282 radix = 10; | |
283 } | |
284 } else if (radix == 16) { | |
285 if (*current == '0') { | |
286 // Allow "0x" prefix. | |
287 ++current; | |
288 if (current == end) return SignedZero(negative); | |
289 if (*current == 'x' || *current == 'X') { | |
290 ++current; | |
291 if (current == end) return JUNK_STRING_VALUE; | |
292 } else { | |
293 leading_zero = true; | |
294 } | |
295 } | |
296 } | |
297 | |
298 if (radix < 2 || radix > 36) return JUNK_STRING_VALUE; | |
299 | |
300 // Skip leading zeros. | |
301 while (*current == '0') { | |
302 leading_zero = true; | |
303 ++current; | |
304 if (current == end) return SignedZero(negative); | |
305 } | |
306 | |
307 if (!leading_zero && !isDigit(*current, radix)) { | |
308 return JUNK_STRING_VALUE; | |
309 } | |
310 | |
311 if (IsPowerOf2(radix)) { | |
312 switch (radix) { | |
313 case 2: | |
314 return InternalStringToIntDouble<1>( | |
315 unicode_cache, current, end, negative, allow_trailing_junk); | |
316 case 4: | |
317 return InternalStringToIntDouble<2>( | |
318 unicode_cache, current, end, negative, allow_trailing_junk); | |
319 case 8: | |
320 return InternalStringToIntDouble<3>( | |
321 unicode_cache, current, end, negative, allow_trailing_junk); | |
322 | |
323 case 16: | |
324 return InternalStringToIntDouble<4>( | |
325 unicode_cache, current, end, negative, allow_trailing_junk); | |
326 | |
327 case 32: | |
328 return InternalStringToIntDouble<5>( | |
329 unicode_cache, current, end, negative, allow_trailing_junk); | |
330 default: | |
331 UNREACHABLE(); | |
332 } | |
333 } | |
334 | |
335 if (radix == 10) { | |
336 // Parsing with strtod. | |
337 const int kMaxSignificantDigits = 309; // Doubles are less than 1.8e308. | |
338 // The buffer may contain up to kMaxSignificantDigits + 1 digits and a zero | |
339 // end. | |
340 const int kBufferSize = kMaxSignificantDigits + 2; | |
341 char buffer[kBufferSize]; | |
342 int buffer_pos = 0; | |
343 while (*current >= '0' && *current <= '9') { | |
344 if (buffer_pos <= kMaxSignificantDigits) { | |
345 // If the number has more than kMaxSignificantDigits it will be parsed | |
346 // as infinity. | |
347 ASSERT(buffer_pos < kBufferSize); | |
348 buffer[buffer_pos++] = static_cast<char>(*current); | |
349 } | |
350 ++current; | |
351 if (current == end) break; | |
352 } | |
353 | |
354 if (!allow_trailing_junk && | |
355 AdvanceToNonspace(unicode_cache, ¤t, end)) { | |
356 return JUNK_STRING_VALUE; | |
357 } | |
358 | |
359 ASSERT(buffer_pos < kBufferSize); | |
360 buffer[buffer_pos] = '\0'; | |
361 Vector<const char> buffer_vector(buffer, buffer_pos); | |
362 return negative ? -Strtod(buffer_vector, 0) : Strtod(buffer_vector, 0); | |
363 } | |
364 | |
365 // The following code causes accumulating rounding error for numbers greater | |
366 // than ~2^56. It's explicitly allowed in the spec: "if R is not 2, 4, 8, 10, | |
367 // 16, or 32, then mathInt may be an implementation-dependent approximation to | |
368 // the mathematical integer value" (15.1.2.2). | |
369 | |
370 int lim_0 = '0' + (radix < 10 ? radix : 10); | |
371 int lim_a = 'a' + (radix - 10); | |
372 int lim_A = 'A' + (radix - 10); | |
373 | |
374 // NOTE: The code for computing the value may seem a bit complex at | |
375 // first glance. It is structured to use 32-bit multiply-and-add | |
376 // loops as long as possible to avoid loosing precision. | |
377 | |
378 double v = 0.0; | |
379 bool done = false; | |
380 do { | |
381 // Parse the longest part of the string starting at index j | |
382 // possible while keeping the multiplier, and thus the part | |
383 // itself, within 32 bits. | |
384 unsigned int part = 0, multiplier = 1; | |
385 while (true) { | |
386 int d; | |
387 if (*current >= '0' && *current < lim_0) { | |
388 d = *current - '0'; | |
389 } else if (*current >= 'a' && *current < lim_a) { | |
390 d = *current - 'a' + 10; | |
391 } else if (*current >= 'A' && *current < lim_A) { | |
392 d = *current - 'A' + 10; | |
393 } else { | |
394 done = true; | |
395 break; | |
396 } | |
397 | |
398 // Update the value of the part as long as the multiplier fits | |
399 // in 32 bits. When we can't guarantee that the next iteration | |
400 // will not overflow the multiplier, we stop parsing the part | |
401 // by leaving the loop. | |
402 const unsigned int kMaximumMultiplier = 0xffffffffU / 36; | |
403 uint32_t m = multiplier * radix; | |
404 if (m > kMaximumMultiplier) break; | |
405 part = part * radix + d; | |
406 multiplier = m; | |
407 ASSERT(multiplier > part); | |
408 | |
409 ++current; | |
410 if (current == end) { | |
411 done = true; | |
412 break; | |
413 } | |
414 } | |
415 | |
416 // Update the value and skip the part in the string. | |
417 v = v * multiplier + part; | |
418 } while (!done); | |
419 | |
420 if (!allow_trailing_junk && | |
421 AdvanceToNonspace(unicode_cache, ¤t, end)) { | |
422 return JUNK_STRING_VALUE; | |
423 } | |
424 | |
425 return negative ? -v : v; | |
426 } | |
427 | |
428 | |
429 // Converts a string to a double value. Assumes the Iterator supports | |
430 // the following operations: | |
431 // 1. current == end (other ops are not allowed), current != end. | |
432 // 2. *current - gets the current character in the sequence. | |
433 // 3. ++current (advances the position). | |
434 template <class Iterator, class EndMark> | |
435 static double InternalStringToDouble(UnicodeCache* unicode_cache, | |
436 Iterator current, | |
437 EndMark end, | |
438 int flags, | |
439 double empty_string_val) { | |
440 // To make sure that iterator dereferencing is valid the following | |
441 // convention is used: | |
442 // 1. Each '++current' statement is followed by check for equality to 'end'. | |
443 // 2. If AdvanceToNonspace returned false then current == end. | |
444 // 3. If 'current' becomes be equal to 'end' the function returns or goes to | |
445 // 'parsing_done'. | |
446 // 4. 'current' is not dereferenced after the 'parsing_done' label. | |
447 // 5. Code before 'parsing_done' may rely on 'current != end'. | |
448 if (!AdvanceToNonspace(unicode_cache, ¤t, end)) { | |
449 return empty_string_val; | |
450 } | |
451 | |
452 const bool allow_trailing_junk = (flags & ALLOW_TRAILING_JUNK) != 0; | |
453 | |
454 // The longest form of simplified number is: "-<significant digits>'.1eXXX\0". | |
455 const int kBufferSize = kMaxSignificantDigits + 10; | |
456 char buffer[kBufferSize]; // NOLINT: size is known at compile time. | |
457 int buffer_pos = 0; | |
458 | |
459 // Exponent will be adjusted if insignificant digits of the integer part | |
460 // or insignificant leading zeros of the fractional part are dropped. | |
461 int exponent = 0; | |
462 int significant_digits = 0; | |
463 int insignificant_digits = 0; | |
464 bool nonzero_digit_dropped = false; | |
465 bool fractional_part = false; | |
466 | |
467 bool negative = false; | |
468 | |
469 if (*current == '+') { | |
470 // Ignore leading sign. | |
471 ++current; | |
472 if (current == end) return JUNK_STRING_VALUE; | |
473 } else if (*current == '-') { | |
474 ++current; | |
475 if (current == end) return JUNK_STRING_VALUE; | |
476 negative = true; | |
477 } | |
478 | |
479 static const char kInfinitySymbol[] = "Infinity"; | |
480 if (*current == kInfinitySymbol[0]) { | |
481 if (!SubStringEquals(¤t, end, kInfinitySymbol)) { | |
482 return JUNK_STRING_VALUE; | |
483 } | |
484 | |
485 if (!allow_trailing_junk && | |
486 AdvanceToNonspace(unicode_cache, ¤t, end)) { | |
487 return JUNK_STRING_VALUE; | |
488 } | |
489 | |
490 ASSERT(buffer_pos == 0); | |
491 return negative ? -V8_INFINITY : V8_INFINITY; | |
492 } | |
493 | |
494 bool leading_zero = false; | |
495 if (*current == '0') { | |
496 ++current; | |
497 if (current == end) return SignedZero(negative); | |
498 | |
499 leading_zero = true; | |
500 | |
501 // It could be hexadecimal value. | |
502 if ((flags & ALLOW_HEX) && (*current == 'x' || *current == 'X')) { | |
503 ++current; | |
504 if (current == end || !isDigit(*current, 16)) { | |
505 return JUNK_STRING_VALUE; // "0x". | |
506 } | |
507 | |
508 return InternalStringToIntDouble<4>(unicode_cache, | |
509 current, | |
510 end, | |
511 negative, | |
512 allow_trailing_junk); | |
513 } | |
514 | |
515 // Ignore leading zeros in the integer part. | |
516 while (*current == '0') { | |
517 ++current; | |
518 if (current == end) return SignedZero(negative); | |
519 } | |
520 } | |
521 | |
522 bool octal = leading_zero && (flags & ALLOW_OCTALS) != 0; | |
523 | |
524 // Copy significant digits of the integer part (if any) to the buffer. | |
525 while (*current >= '0' && *current <= '9') { | |
526 if (significant_digits < kMaxSignificantDigits) { | |
527 ASSERT(buffer_pos < kBufferSize); | |
528 buffer[buffer_pos++] = static_cast<char>(*current); | |
529 significant_digits++; | |
530 // Will later check if it's an octal in the buffer. | |
531 } else { | |
532 insignificant_digits++; // Move the digit into the exponential part. | |
533 nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; | |
534 } | |
535 octal = octal && *current < '8'; | |
536 ++current; | |
537 if (current == end) goto parsing_done; | |
538 } | |
539 | |
540 if (significant_digits == 0) { | |
541 octal = false; | |
542 } | |
543 | |
544 if (*current == '.') { | |
545 if (octal && !allow_trailing_junk) return JUNK_STRING_VALUE; | |
546 if (octal) goto parsing_done; | |
547 | |
548 ++current; | |
549 if (current == end) { | |
550 if (significant_digits == 0 && !leading_zero) { | |
551 return JUNK_STRING_VALUE; | |
552 } else { | |
553 goto parsing_done; | |
554 } | |
555 } | |
556 | |
557 if (significant_digits == 0) { | |
558 // octal = false; | |
559 // Integer part consists of 0 or is absent. Significant digits start after | |
560 // leading zeros (if any). | |
561 while (*current == '0') { | |
562 ++current; | |
563 if (current == end) return SignedZero(negative); | |
564 exponent--; // Move this 0 into the exponent. | |
565 } | |
566 } | |
567 | |
568 // We don't emit a '.', but adjust the exponent instead. | |
569 fractional_part = true; | |
570 | |
571 // There is a fractional part. | |
572 while (*current >= '0' && *current <= '9') { | |
573 if (significant_digits < kMaxSignificantDigits) { | |
574 ASSERT(buffer_pos < kBufferSize); | |
575 buffer[buffer_pos++] = static_cast<char>(*current); | |
576 significant_digits++; | |
577 exponent--; | |
578 } else { | |
579 // Ignore insignificant digits in the fractional part. | |
580 nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; | |
581 } | |
582 ++current; | |
583 if (current == end) goto parsing_done; | |
584 } | |
585 } | |
586 | |
587 if (!leading_zero && exponent == 0 && significant_digits == 0) { | |
588 // If leading_zeros is true then the string contains zeros. | |
589 // If exponent < 0 then string was [+-]\.0*... | |
590 // If significant_digits != 0 the string is not equal to 0. | |
591 // Otherwise there are no digits in the string. | |
592 return JUNK_STRING_VALUE; | |
593 } | |
594 | |
595 // Parse exponential part. | |
596 if (*current == 'e' || *current == 'E') { | |
597 if (octal) return JUNK_STRING_VALUE; | |
598 ++current; | |
599 if (current == end) { | |
600 if (allow_trailing_junk) { | |
601 goto parsing_done; | |
602 } else { | |
603 return JUNK_STRING_VALUE; | |
604 } | |
605 } | |
606 char sign = '+'; | |
607 if (*current == '+' || *current == '-') { | |
608 sign = static_cast<char>(*current); | |
609 ++current; | |
610 if (current == end) { | |
611 if (allow_trailing_junk) { | |
612 goto parsing_done; | |
613 } else { | |
614 return JUNK_STRING_VALUE; | |
615 } | |
616 } | |
617 } | |
618 | |
619 if (current == end || *current < '0' || *current > '9') { | |
620 if (allow_trailing_junk) { | |
621 goto parsing_done; | |
622 } else { | |
623 return JUNK_STRING_VALUE; | |
624 } | |
625 } | |
626 | |
627 const int max_exponent = INT_MAX / 2; | |
628 ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2); | |
629 int num = 0; | |
630 do { | |
631 // Check overflow. | |
632 int digit = *current - '0'; | |
633 if (num >= max_exponent / 10 | |
634 && !(num == max_exponent / 10 && digit <= max_exponent % 10)) { | |
635 num = max_exponent; | |
636 } else { | |
637 num = num * 10 + digit; | |
638 } | |
639 ++current; | |
640 } while (current != end && *current >= '0' && *current <= '9'); | |
641 | |
642 exponent += (sign == '-' ? -num : num); | |
643 } | |
644 | |
645 if (!allow_trailing_junk && | |
646 AdvanceToNonspace(unicode_cache, ¤t, end)) { | |
647 return JUNK_STRING_VALUE; | |
648 } | |
649 | |
650 parsing_done: | |
651 exponent += insignificant_digits; | |
652 | |
653 if (octal) { | |
654 return InternalStringToIntDouble<3>(unicode_cache, | |
655 buffer, | |
656 buffer + buffer_pos, | |
657 negative, | |
658 allow_trailing_junk); | |
659 } | |
660 | |
661 if (nonzero_digit_dropped) { | |
662 buffer[buffer_pos++] = '1'; | |
663 exponent--; | |
664 } | |
665 | |
666 ASSERT(buffer_pos < kBufferSize); | |
667 buffer[buffer_pos] = '\0'; | |
668 | |
669 double converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent); | |
670 return negative ? -converted : converted; | |
671 } | |
672 | 40 |
673 | 41 |
674 double StringToDouble(UnicodeCache* unicode_cache, | 42 double StringToDouble(UnicodeCache* unicode_cache, |
675 String* str, int flags, double empty_string_val) { | |
676 StringShape shape(str); | |
677 if (shape.IsSequentialAscii()) { | |
678 const char* begin = SeqAsciiString::cast(str)->GetChars(); | |
679 const char* end = begin + str->length(); | |
680 return InternalStringToDouble(unicode_cache, begin, end, flags, | |
681 empty_string_val); | |
682 } else if (shape.IsSequentialTwoByte()) { | |
683 const uc16* begin = SeqTwoByteString::cast(str)->GetChars(); | |
684 const uc16* end = begin + str->length(); | |
685 return InternalStringToDouble(unicode_cache, begin, end, flags, | |
686 empty_string_val); | |
687 } else { | |
688 StringInputBuffer buffer(str); | |
689 return InternalStringToDouble(unicode_cache, | |
690 StringInputBufferIterator(&buffer), | |
691 StringInputBufferIterator::EndMarker(), | |
692 flags, | |
693 empty_string_val); | |
694 } | |
695 } | |
696 | |
697 | |
698 double StringToInt(UnicodeCache* unicode_cache, | |
699 String* str, | |
700 int radix) { | |
701 StringShape shape(str); | |
702 if (shape.IsSequentialAscii()) { | |
703 const char* begin = SeqAsciiString::cast(str)->GetChars(); | |
704 const char* end = begin + str->length(); | |
705 return InternalStringToInt(unicode_cache, begin, end, radix); | |
706 } else if (shape.IsSequentialTwoByte()) { | |
707 const uc16* begin = SeqTwoByteString::cast(str)->GetChars(); | |
708 const uc16* end = begin + str->length(); | |
709 return InternalStringToInt(unicode_cache, begin, end, radix); | |
710 } else { | |
711 StringInputBuffer buffer(str); | |
712 return InternalStringToInt(unicode_cache, | |
713 StringInputBufferIterator(&buffer), | |
714 StringInputBufferIterator::EndMarker(), | |
715 radix); | |
716 } | |
717 } | |
718 | |
719 | |
720 double StringToDouble(UnicodeCache* unicode_cache, | |
721 const char* str, int flags, double empty_string_val) { | 43 const char* str, int flags, double empty_string_val) { |
722 const char* end = str + StrLength(str); | 44 const char* end = str + StrLength(str); |
723 return InternalStringToDouble(unicode_cache, str, end, flags, | 45 return InternalStringToDouble(unicode_cache, str, end, flags, |
724 empty_string_val); | 46 empty_string_val); |
725 } | 47 } |
726 | 48 |
727 | 49 |
728 double StringToDouble(UnicodeCache* unicode_cache, | 50 double StringToDouble(UnicodeCache* unicode_cache, |
729 Vector<const char> str, | 51 Vector<const char> str, |
730 int flags, | 52 int flags, |
(...skipping 12 matching lines...) Expand all Loading... |
743 empty_string_val); | 65 empty_string_val); |
744 } | 66 } |
745 | 67 |
746 | 68 |
747 const char* DoubleToCString(double v, Vector<char> buffer) { | 69 const char* DoubleToCString(double v, Vector<char> buffer) { |
748 switch (fpclassify(v)) { | 70 switch (fpclassify(v)) { |
749 case FP_NAN: return "NaN"; | 71 case FP_NAN: return "NaN"; |
750 case FP_INFINITE: return (v < 0.0 ? "-Infinity" : "Infinity"); | 72 case FP_INFINITE: return (v < 0.0 ? "-Infinity" : "Infinity"); |
751 case FP_ZERO: return "0"; | 73 case FP_ZERO: return "0"; |
752 default: { | 74 default: { |
753 StringBuilder builder(buffer.start(), buffer.length()); | 75 SimpleStringBuilder builder(buffer.start(), buffer.length()); |
754 int decimal_point; | 76 int decimal_point; |
755 int sign; | 77 int sign; |
756 const int kV8DtoaBufferCapacity = kBase10MaximalLength + 1; | 78 const int kV8DtoaBufferCapacity = kBase10MaximalLength + 1; |
757 char decimal_rep[kV8DtoaBufferCapacity]; | 79 char decimal_rep[kV8DtoaBufferCapacity]; |
758 int length; | 80 int length; |
759 | 81 |
760 DoubleToAscii(v, DTOA_SHORTEST, 0, | 82 DoubleToAscii(v, DTOA_SHORTEST, 0, |
761 Vector<char>(decimal_rep, kV8DtoaBufferCapacity), | 83 Vector<char>(decimal_rep, kV8DtoaBufferCapacity), |
762 &sign, &length, &decimal_point); | 84 &sign, &length, &decimal_point); |
763 | 85 |
(...skipping 20 matching lines...) Expand all Loading... |
784 // ECMA-262 section 9.8.1 step 9 and 10 combined. | 106 // ECMA-262 section 9.8.1 step 9 and 10 combined. |
785 builder.AddCharacter(decimal_rep[0]); | 107 builder.AddCharacter(decimal_rep[0]); |
786 if (length != 1) { | 108 if (length != 1) { |
787 builder.AddCharacter('.'); | 109 builder.AddCharacter('.'); |
788 builder.AddString(decimal_rep + 1); | 110 builder.AddString(decimal_rep + 1); |
789 } | 111 } |
790 builder.AddCharacter('e'); | 112 builder.AddCharacter('e'); |
791 builder.AddCharacter((decimal_point >= 0) ? '+' : '-'); | 113 builder.AddCharacter((decimal_point >= 0) ? '+' : '-'); |
792 int exponent = decimal_point - 1; | 114 int exponent = decimal_point - 1; |
793 if (exponent < 0) exponent = -exponent; | 115 if (exponent < 0) exponent = -exponent; |
794 builder.AddFormatted("%d", exponent); | 116 builder.AddDecimalInteger(exponent); |
795 } | 117 } |
796 return builder.Finalize(); | 118 return builder.Finalize(); |
797 } | 119 } |
798 } | 120 } |
799 } | 121 } |
800 | 122 |
801 | 123 |
802 const char* IntToCString(int n, Vector<char> buffer) { | 124 const char* IntToCString(int n, Vector<char> buffer) { |
803 bool negative = false; | 125 bool negative = false; |
804 if (n < 0) { | 126 if (n < 0) { |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
862 decimal_point = 1; | 184 decimal_point = 1; |
863 } | 185 } |
864 | 186 |
865 if (zero_prefix_length + decimal_rep_length < decimal_point + f) { | 187 if (zero_prefix_length + decimal_rep_length < decimal_point + f) { |
866 zero_postfix_length = decimal_point + f - decimal_rep_length - | 188 zero_postfix_length = decimal_point + f - decimal_rep_length - |
867 zero_prefix_length; | 189 zero_prefix_length; |
868 } | 190 } |
869 | 191 |
870 unsigned rep_length = | 192 unsigned rep_length = |
871 zero_prefix_length + decimal_rep_length + zero_postfix_length; | 193 zero_prefix_length + decimal_rep_length + zero_postfix_length; |
872 StringBuilder rep_builder(rep_length + 1); | 194 SimpleStringBuilder rep_builder(rep_length + 1); |
873 rep_builder.AddPadding('0', zero_prefix_length); | 195 rep_builder.AddPadding('0', zero_prefix_length); |
874 rep_builder.AddString(decimal_rep); | 196 rep_builder.AddString(decimal_rep); |
875 rep_builder.AddPadding('0', zero_postfix_length); | 197 rep_builder.AddPadding('0', zero_postfix_length); |
876 char* rep = rep_builder.Finalize(); | 198 char* rep = rep_builder.Finalize(); |
877 | 199 |
878 // Create the result string by appending a minus and putting in a | 200 // Create the result string by appending a minus and putting in a |
879 // decimal point if needed. | 201 // decimal point if needed. |
880 unsigned result_size = decimal_point + f + 2; | 202 unsigned result_size = decimal_point + f + 2; |
881 StringBuilder builder(result_size + 1); | 203 SimpleStringBuilder builder(result_size + 1); |
882 if (negative) builder.AddCharacter('-'); | 204 if (negative) builder.AddCharacter('-'); |
883 builder.AddSubstring(rep, decimal_point); | 205 builder.AddSubstring(rep, decimal_point); |
884 if (f > 0) { | 206 if (f > 0) { |
885 builder.AddCharacter('.'); | 207 builder.AddCharacter('.'); |
886 builder.AddSubstring(rep + decimal_point, f); | 208 builder.AddSubstring(rep + decimal_point, f); |
887 } | 209 } |
888 DeleteArray(rep); | 210 DeleteArray(rep); |
889 return builder.Finalize(); | 211 return builder.Finalize(); |
890 } | 212 } |
891 | 213 |
892 | 214 |
893 static char* CreateExponentialRepresentation(char* decimal_rep, | 215 static char* CreateExponentialRepresentation(char* decimal_rep, |
894 int exponent, | 216 int exponent, |
895 bool negative, | 217 bool negative, |
896 int significant_digits) { | 218 int significant_digits) { |
897 bool negative_exponent = false; | 219 bool negative_exponent = false; |
898 if (exponent < 0) { | 220 if (exponent < 0) { |
899 negative_exponent = true; | 221 negative_exponent = true; |
900 exponent = -exponent; | 222 exponent = -exponent; |
901 } | 223 } |
902 | 224 |
903 // Leave room in the result for appending a minus, for a period, the | 225 // Leave room in the result for appending a minus, for a period, the |
904 // letter 'e', a minus or a plus depending on the exponent, and a | 226 // letter 'e', a minus or a plus depending on the exponent, and a |
905 // three digit exponent. | 227 // three digit exponent. |
906 unsigned result_size = significant_digits + 7; | 228 unsigned result_size = significant_digits + 7; |
907 StringBuilder builder(result_size + 1); | 229 SimpleStringBuilder builder(result_size + 1); |
908 | 230 |
909 if (negative) builder.AddCharacter('-'); | 231 if (negative) builder.AddCharacter('-'); |
910 builder.AddCharacter(decimal_rep[0]); | 232 builder.AddCharacter(decimal_rep[0]); |
911 if (significant_digits != 1) { | 233 if (significant_digits != 1) { |
912 builder.AddCharacter('.'); | 234 builder.AddCharacter('.'); |
913 builder.AddString(decimal_rep + 1); | 235 builder.AddString(decimal_rep + 1); |
914 int rep_length = StrLength(decimal_rep); | 236 int rep_length = StrLength(decimal_rep); |
915 builder.AddPadding('0', significant_digits - rep_length); | 237 builder.AddPadding('0', significant_digits - rep_length); |
916 } | 238 } |
917 | 239 |
918 builder.AddCharacter('e'); | 240 builder.AddCharacter('e'); |
919 builder.AddCharacter(negative_exponent ? '-' : '+'); | 241 builder.AddCharacter(negative_exponent ? '-' : '+'); |
920 builder.AddFormatted("%d", exponent); | 242 builder.AddDecimalInteger(exponent); |
921 return builder.Finalize(); | 243 return builder.Finalize(); |
922 } | 244 } |
923 | 245 |
924 | 246 |
925 | 247 |
926 char* DoubleToExponentialCString(double value, int f) { | 248 char* DoubleToExponentialCString(double value, int f) { |
927 const int kMaxDigitsAfterPoint = 20; | 249 const int kMaxDigitsAfterPoint = 20; |
928 // f might be -1 to signal that f was undefined in JavaScript. | 250 // f might be -1 to signal that f was undefined in JavaScript. |
929 ASSERT(f >= -1 && f <= kMaxDigitsAfterPoint); | 251 ASSERT(f >= -1 && f <= kMaxDigitsAfterPoint); |
930 | 252 |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1002 CreateExponentialRepresentation(decimal_rep, exponent, negative, p); | 324 CreateExponentialRepresentation(decimal_rep, exponent, negative, p); |
1003 } else { | 325 } else { |
1004 // Use fixed notation. | 326 // Use fixed notation. |
1005 // | 327 // |
1006 // Leave room in the result for appending a minus, a period and in | 328 // Leave room in the result for appending a minus, a period and in |
1007 // the case where decimal_point is not positive for a zero in | 329 // the case where decimal_point is not positive for a zero in |
1008 // front of the period. | 330 // front of the period. |
1009 unsigned result_size = (decimal_point <= 0) | 331 unsigned result_size = (decimal_point <= 0) |
1010 ? -decimal_point + p + 3 | 332 ? -decimal_point + p + 3 |
1011 : p + 2; | 333 : p + 2; |
1012 StringBuilder builder(result_size + 1); | 334 SimpleStringBuilder builder(result_size + 1); |
1013 if (negative) builder.AddCharacter('-'); | 335 if (negative) builder.AddCharacter('-'); |
1014 if (decimal_point <= 0) { | 336 if (decimal_point <= 0) { |
1015 builder.AddString("0."); | 337 builder.AddString("0."); |
1016 builder.AddPadding('0', -decimal_point); | 338 builder.AddPadding('0', -decimal_point); |
1017 builder.AddString(decimal_rep); | 339 builder.AddString(decimal_rep); |
1018 builder.AddPadding('0', p - decimal_rep_length); | 340 builder.AddPadding('0', p - decimal_rep_length); |
1019 } else { | 341 } else { |
1020 const int m = Min(decimal_rep_length, decimal_point); | 342 const int m = Min(decimal_rep_length, decimal_point); |
1021 builder.AddSubstring(decimal_rep, m); | 343 builder.AddSubstring(decimal_rep, m); |
1022 builder.AddPadding('0', decimal_point - decimal_rep_length); | 344 builder.AddPadding('0', decimal_point - decimal_rep_length); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1094 } | 416 } |
1095 decimal_buffer[decimal_pos] = '\0'; | 417 decimal_buffer[decimal_pos] = '\0'; |
1096 | 418 |
1097 // Compute the result size. | 419 // Compute the result size. |
1098 int integer_part_size = kBufferSize - 2 - integer_pos; | 420 int integer_part_size = kBufferSize - 2 - integer_pos; |
1099 // Make room for zero termination. | 421 // Make room for zero termination. |
1100 unsigned result_size = integer_part_size + decimal_pos; | 422 unsigned result_size = integer_part_size + decimal_pos; |
1101 // If the number has a decimal part, leave room for the period. | 423 // If the number has a decimal part, leave room for the period. |
1102 if (decimal_pos > 0) result_size++; | 424 if (decimal_pos > 0) result_size++; |
1103 // Allocate result and fill in the parts. | 425 // Allocate result and fill in the parts. |
1104 StringBuilder builder(result_size + 1); | 426 SimpleStringBuilder builder(result_size + 1); |
1105 builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size); | 427 builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size); |
1106 if (decimal_pos > 0) builder.AddCharacter('.'); | 428 if (decimal_pos > 0) builder.AddCharacter('.'); |
1107 builder.AddSubstring(decimal_buffer, decimal_pos); | 429 builder.AddSubstring(decimal_buffer, decimal_pos); |
1108 return builder.Finalize(); | 430 return builder.Finalize(); |
1109 } | 431 } |
1110 | 432 |
1111 | 433 |
1112 static Mutex* dtoa_lock_one = OS::CreateMutex(); | 434 static Mutex* dtoa_lock_one = OS::CreateMutex(); |
1113 static Mutex* dtoa_lock_zero = OS::CreateMutex(); | 435 static Mutex* dtoa_lock_zero = OS::CreateMutex(); |
1114 | 436 |
1115 | 437 |
1116 } } // namespace v8::internal | 438 } } // namespace v8::internal |
1117 | 439 |
1118 | 440 |
1119 extern "C" { | 441 extern "C" { |
1120 void ACQUIRE_DTOA_LOCK(int n) { | 442 void ACQUIRE_DTOA_LOCK(int n) { |
1121 ASSERT(n == 0 || n == 1); | 443 ASSERT(n == 0 || n == 1); |
1122 (n == 0 ? v8::internal::dtoa_lock_zero : v8::internal::dtoa_lock_one)->Lock(); | 444 (n == 0 ? v8::internal::dtoa_lock_zero : v8::internal::dtoa_lock_one)->Lock(); |
1123 } | 445 } |
1124 | 446 |
1125 | 447 |
1126 void FREE_DTOA_LOCK(int n) { | 448 void FREE_DTOA_LOCK(int n) { |
1127 ASSERT(n == 0 || n == 1); | 449 ASSERT(n == 0 || n == 1); |
1128 (n == 0 ? v8::internal::dtoa_lock_zero : v8::internal::dtoa_lock_one)-> | 450 (n == 0 ? v8::internal::dtoa_lock_zero : v8::internal::dtoa_lock_one)-> |
1129 Unlock(); | 451 Unlock(); |
1130 } | 452 } |
1131 } | 453 } |
OLD | NEW |