Index: src/conversions.cc |
diff --git a/src/conversions.cc b/src/conversions.cc |
index 82a521bd90844775746707cd529f5535ebb912a7..32de34c6a7c70f23fba112ceee51071908846488 100644 |
--- a/src/conversions.cc |
+++ b/src/conversions.cc |
@@ -503,53 +503,60 @@ double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string, |
} |
-bool IsNonArrayIndexInteger(String* string) { |
- const int kBufferSize = 64; |
- const int kUint32MaxChars = 11; |
+bool IsSpecialIndex(UnicodeCache* unicode_cache, String* string) { |
+ // Max length of canonical double: -X.XXXXXXXXXXXXXXXXX-eXXX |
+ const int kBufferSize = 24; |
+ const int length = string->length(); |
+ if (length == 0 || length > kBufferSize) return false; |
uint16_t buffer[kBufferSize]; |
+ String::WriteToFlat(string, buffer, 0, length); |
+ // If the first char is not a digit or a '-' or we can't match 'NaN' or |
+ // '(-)Infinity', bailout immediately. |
int offset = 0; |
- const int length = string->length(); |
- if (length == 0) return false; |
- // First iteration, check for minus, 0 followed by anything else, etc. |
- int to = std::min(offset + kUint32MaxChars, length); |
- { |
- String::WriteToFlat(string, buffer, offset, to); |
- bool negative = false; |
- if (buffer[offset] == '-') { |
- negative = true; |
- ++offset; |
- if (offset == to) return false; // Just '-' is bad. |
- } |
- if (buffer[offset] == '0') { |
- return to == 2 && negative; // Match just '-0'. |
- } |
- // Process positive integers. |
- if (!negative) { |
- uint64_t acc = 0; |
- for (; offset < to; ++offset) { |
- uint64_t digit = buffer[offset] - '0'; |
- if (digit > 9) return false; |
- acc = 10 * acc + digit; |
- } |
- // String is consumed. Evaluate what we have. |
- if (offset == length) { |
- return acc > |
- static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()); |
+ if (!IsDecimalDigit(buffer[0])) { |
+ if (buffer[0] == '-') { |
+ if (length == 1) return false; // Just '-' is bad. |
+ if (!IsDecimalDigit(buffer[1])) { |
+ if (buffer[1] == 'I' && length == 9) { |
+ // Allow matching of '-Infinity' below. |
+ } else { |
+ return false; |
+ } |
} |
+ offset++; |
+ } else if (buffer[0] == 'I' && length == 8) { |
+ // Allow matching of 'Infinity' below. |
+ } else if (buffer[0] == 'N' && length == 3) { |
+ // Match NaN. |
+ return buffer[1] == 'a' && buffer[2] == 'N'; |
+ } else { |
+ return false; |
} |
} |
- // Consume rest of string. If we get here, we're way out of uint32_t bounds |
- // or negative. |
- int i = offset; |
- while (true) { |
- for (; offset < to; ++offset, ++i) { |
- if (!IsDecimalDigit(buffer[i])) return false; |
+ // Expected fast path: key is an integer. |
+ static const int kRepresentableIntegerLength = 15; // (-)XXXXXXXXXXXXXXX |
+ if (length - offset <= kRepresentableIntegerLength) { |
+ const int initial_offset = offset; |
+ bool matches = true; |
+ for (; offset < length; offset++) { |
+ matches &= IsDecimalDigit(buffer[offset]); |
} |
- if (offset == length) break; |
- // Read next chunk. |
- to = std::min(offset + kBufferSize, length); |
- String::WriteToFlat(string, buffer, offset, to); |
- i = 0; |
+ if (matches) { |
+ // Match 0 and -0. |
+ if (buffer[initial_offset] == '0') return initial_offset == length - 1; |
+ return true; |
+ } |
+ } |
+ // Slow path: test DoubleToString(StringToDouble(string)) == string. |
+ Vector<const uint16_t> vector(buffer, length); |
+ double d = StringToDouble(unicode_cache, vector, NO_FLAGS); |
+ if (std::isnan(d)) return false; |
+ // Compute reverse string. |
+ char reverse_buffer[kBufferSize + 1]; // Result will be /0 terminated. |
+ Vector<char> reverse_vector(reverse_buffer, arraysize(reverse_buffer)); |
+ const char* reverse_string = DoubleToCString(d, reverse_vector); |
+ for (int i = 0; i < length; ++i) { |
+ if (static_cast<uint16_t>(reverse_string[i]) != buffer[i]) return false; |
} |
return true; |
} |