OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <limits.h> | 5 #include <limits.h> |
6 #include <stdarg.h> | 6 #include <stdarg.h> |
7 #include <cmath> | 7 #include <cmath> |
8 | 8 |
9 #include "src/v8.h" | 9 #include "src/v8.h" |
10 | 10 |
(...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
496 return StringToDouble(unicode_cache, flat.ToOneByteVector(), flags, | 496 return StringToDouble(unicode_cache, flat.ToOneByteVector(), flags, |
497 empty_string_val); | 497 empty_string_val); |
498 } else { | 498 } else { |
499 return StringToDouble(unicode_cache, flat.ToUC16Vector(), flags, | 499 return StringToDouble(unicode_cache, flat.ToUC16Vector(), flags, |
500 empty_string_val); | 500 empty_string_val); |
501 } | 501 } |
502 } | 502 } |
503 } | 503 } |
504 | 504 |
505 | 505 |
506 bool IsNonArrayIndexInteger(String* string) { | 506 bool IsSpecialIndex(UnicodeCache* unicode_cache, String* string) { |
507 const int kBufferSize = 64; | 507 // Max length of canonical double: -X.XXXXXXXXXXXXXXXXX-eXXX |
508 const int kUint32MaxChars = 11; | 508 const int kBufferSize = 24; |
| 509 const int length = string->length(); |
| 510 if (length == 0 || length > kBufferSize) return false; |
509 uint16_t buffer[kBufferSize]; | 511 uint16_t buffer[kBufferSize]; |
| 512 String::WriteToFlat(string, buffer, 0, length); |
| 513 // If the first char is not a digit or a '-' or we can't match 'NaN' or |
| 514 // '(-)Infinity', bailout immediately. |
510 int offset = 0; | 515 int offset = 0; |
511 const int length = string->length(); | 516 if (!IsDecimalDigit(buffer[0])) { |
512 if (length == 0) return false; | 517 if (buffer[0] == '-') { |
513 // First iteration, check for minus, 0 followed by anything else, etc. | 518 if (length == 1) return false; // Just '-' is bad. |
514 int to = std::min(offset + kUint32MaxChars, length); | 519 if (!IsDecimalDigit(buffer[1])) { |
515 { | 520 if (buffer[1] == 'I' && length == 9) { |
516 String::WriteToFlat(string, buffer, offset, to); | 521 // Allow matching of '-Infinity' below. |
517 bool negative = false; | 522 } else { |
518 if (buffer[offset] == '-') { | 523 return false; |
519 negative = true; | 524 } |
520 ++offset; | |
521 if (offset == to) return false; // Just '-' is bad. | |
522 } | |
523 if (buffer[offset] == '0') { | |
524 return to == 2 && negative; // Match just '-0'. | |
525 } | |
526 // Process positive integers. | |
527 if (!negative) { | |
528 uint64_t acc = 0; | |
529 for (; offset < to; ++offset) { | |
530 uint64_t digit = buffer[offset] - '0'; | |
531 if (digit > 9) return false; | |
532 acc = 10 * acc + digit; | |
533 } | 525 } |
534 // String is consumed. Evaluate what we have. | 526 offset++; |
535 if (offset == length) { | 527 } else if (buffer[0] == 'I' && length == 8) { |
536 return acc > | 528 // Allow matching of 'Infinity' below. |
537 static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()); | 529 } else if (buffer[0] == 'N' && length == 3) { |
538 } | 530 // Match NaN. |
| 531 return buffer[1] == 'a' && buffer[2] == 'N'; |
| 532 } else { |
| 533 return false; |
539 } | 534 } |
540 } | 535 } |
541 // Consume rest of string. If we get here, we're way out of uint32_t bounds | 536 // Expected fast path: key is an integer. |
542 // or negative. | 537 static const int kRepresentableIntegerLength = 15; // (-)XXXXXXXXXXXXXXX |
543 int i = offset; | 538 if (length - offset <= kRepresentableIntegerLength) { |
544 while (true) { | 539 const int initial_offset = offset; |
545 for (; offset < to; ++offset, ++i) { | 540 bool matches = true; |
546 if (!IsDecimalDigit(buffer[i])) return false; | 541 for (; offset < length; offset++) { |
| 542 matches &= IsDecimalDigit(buffer[offset]); |
547 } | 543 } |
548 if (offset == length) break; | 544 if (matches) { |
549 // Read next chunk. | 545 // Match 0 and -0. |
550 to = std::min(offset + kBufferSize, length); | 546 if (buffer[initial_offset] == '0') return initial_offset == length - 1; |
551 String::WriteToFlat(string, buffer, offset, to); | 547 return true; |
552 i = 0; | 548 } |
| 549 } |
| 550 // Slow path: test DoubleToString(StringToDouble(string)) == string. |
| 551 Vector<const uint16_t> vector(buffer, length); |
| 552 double d = StringToDouble(unicode_cache, vector, NO_FLAGS); |
| 553 if (std::isnan(d)) return false; |
| 554 // Compute reverse string. |
| 555 char reverse_buffer[kBufferSize + 1]; // Result will be /0 terminated. |
| 556 Vector<char> reverse_vector(reverse_buffer, arraysize(reverse_buffer)); |
| 557 const char* reverse_string = DoubleToCString(d, reverse_vector); |
| 558 for (int i = 0; i < length; ++i) { |
| 559 if (static_cast<uint16_t>(reverse_string[i]) != buffer[i]) return false; |
553 } | 560 } |
554 return true; | 561 return true; |
555 } | 562 } |
556 } } // namespace v8::internal | 563 } } // namespace v8::internal |
OLD | NEW |