Commit 97981d94 authored by dcarney's avatar dcarney Committed by Commit bot

fix special index parsing

R=verwaest@chromium.org,dslomov@chromium.org

BUG=

Review URL: https://codereview.chromium.org/1038313004

Cr-Commit-Position: refs/heads/master@{#27518}
parent bffde6f4
...@@ -503,53 +503,60 @@ double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string, ...@@ -503,53 +503,60 @@ double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string,
} }
bool IsNonArrayIndexInteger(String* string) { bool IsSpecialIndex(UnicodeCache* unicode_cache, String* string) {
const int kBufferSize = 64; // Max length of canonical double: -X.XXXXXXXXXXXXXXXXX-eXXX
const int kUint32MaxChars = 11; const int kBufferSize = 24;
const int length = string->length();
if (length == 0 || length > kBufferSize) return false;
uint16_t buffer[kBufferSize]; 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; int offset = 0;
const int length = string->length(); if (!IsDecimalDigit(buffer[0])) {
if (length == 0) return false; if (buffer[0] == '-') {
// First iteration, check for minus, 0 followed by anything else, etc. if (length == 1) return false; // Just '-' is bad.
int to = std::min(offset + kUint32MaxChars, length); if (!IsDecimalDigit(buffer[1])) {
{ if (buffer[1] == 'I' && length == 9) {
String::WriteToFlat(string, buffer, offset, to); // Allow matching of '-Infinity' below.
bool negative = false; } else {
if (buffer[offset] == '-') { return false;
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());
} }
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 // Expected fast path: key is an integer.
// or negative. static const int kRepresentableIntegerLength = 15; // (-)XXXXXXXXXXXXXXX
int i = offset; if (length - offset <= kRepresentableIntegerLength) {
while (true) { const int initial_offset = offset;
for (; offset < to; ++offset, ++i) { bool matches = true;
if (!IsDecimalDigit(buffer[i])) return false; for (; offset < length; offset++) {
matches &= IsDecimalDigit(buffer[offset]);
} }
if (offset == length) break; if (matches) {
// Read next chunk. // Match 0 and -0.
to = std::min(offset + kBufferSize, length); if (buffer[initial_offset] == '0') return initial_offset == length - 1;
String::WriteToFlat(string, buffer, offset, to); return true;
i = 0; }
}
// 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; return true;
} }
......
...@@ -237,7 +237,8 @@ inline size_t NumberToSize(Isolate* isolate, ...@@ -237,7 +237,8 @@ inline size_t NumberToSize(Isolate* isolate,
} }
bool IsNonArrayIndexInteger(String* string); // returns DoubleToString(StringToDouble(string)) == string
bool IsSpecialIndex(UnicodeCache* unicode_cache, String* string);
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_CONVERSIONS_H_ #endif // V8_CONVERSIONS_H_
...@@ -6066,7 +6066,8 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() { ...@@ -6066,7 +6066,8 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
bool HOptimizedGraphBuilder::PropertyAccessInfo::IsIntegerIndexedExotic() { bool HOptimizedGraphBuilder::PropertyAccessInfo::IsIntegerIndexedExotic() {
InstanceType instance_type = map_->instance_type(); InstanceType instance_type = map_->instance_type();
return instance_type == JS_TYPED_ARRAY_TYPE && IsNonArrayIndexInteger(*name_); return instance_type == JS_TYPED_ARRAY_TYPE &&
IsSpecialIndex(isolate()->unicode_cache(), *name_);
} }
......
...@@ -364,7 +364,7 @@ bool LookupIterator::IsIntegerIndexedExotic(JSReceiver* holder) { ...@@ -364,7 +364,7 @@ bool LookupIterator::IsIntegerIndexedExotic(JSReceiver* holder) {
if (name()->IsString()) { if (name()->IsString()) {
Handle<String> name_string = Handle<String>::cast(name()); Handle<String> name_string = Handle<String>::cast(name());
if (name_string->length() != 0) { if (name_string->length() != 0) {
result = IsNonArrayIndexInteger(*name_string); result = IsSpecialIndex(isolate_->unicode_cache(), *name_string);
} }
} }
exotic_index_state_ = exotic_index_state_ =
......
...@@ -367,53 +367,42 @@ TEST(BitField64) { ...@@ -367,53 +367,42 @@ TEST(BitField64) {
static void CheckNonArrayIndex(bool expected, const char* chars) { static void CheckNonArrayIndex(bool expected, const char* chars) {
auto isolate = CcTest::i_isolate(); auto isolate = CcTest::i_isolate();
auto string = isolate->factory()->NewStringFromAsciiChecked(chars); auto string = isolate->factory()->NewStringFromAsciiChecked(chars);
CHECK_EQ(expected, IsNonArrayIndexInteger(*string)); CHECK_EQ(expected, IsSpecialIndex(isolate->unicode_cache(), *string));
} }
TEST(NonArrayIndexParsing) { TEST(SpecialIndexParsing) {
auto isolate = CcTest::i_isolate(); auto isolate = CcTest::i_isolate();
HandleScope scope(isolate); HandleScope scope(isolate);
CheckNonArrayIndex(false, ""); CheckNonArrayIndex(false, "");
CheckNonArrayIndex(false, "-"); CheckNonArrayIndex(false, "-");
CheckNonArrayIndex(false, "0"); CheckNonArrayIndex(true, "0");
CheckNonArrayIndex(true, "-0");
CheckNonArrayIndex(false, "01"); CheckNonArrayIndex(false, "01");
CheckNonArrayIndex(false, "-01"); CheckNonArrayIndex(false, "-01");
CheckNonArrayIndex(false, "4294967295"); CheckNonArrayIndex(true, "0.5");
CheckNonArrayIndex(false, "429496.7295"); CheckNonArrayIndex(true, "-0.5");
CheckNonArrayIndex(false, "43s3"); CheckNonArrayIndex(true, "1");
CheckNonArrayIndex(true, "-0");
CheckNonArrayIndex(true, "-1"); CheckNonArrayIndex(true, "-1");
CheckNonArrayIndex(true, "10");
CheckNonArrayIndex(true, "-10");
CheckNonArrayIndex(true, "NaN");
CheckNonArrayIndex(true, "Infinity");
CheckNonArrayIndex(true, "-Infinity");
CheckNonArrayIndex(true, "4294967295");
CheckNonArrayIndex(true, "429496.7295");
CheckNonArrayIndex(true, "1.3333333333333333");
CheckNonArrayIndex(false, "1.3333333333333339");
CheckNonArrayIndex(true, "1.333333333333331e+222");
CheckNonArrayIndex(true, "-1.3333333333333211e+222");
CheckNonArrayIndex(false, "-1.3333333333333311e+222");
CheckNonArrayIndex(true, "429496.7295");
CheckNonArrayIndex(false, "43s3");
CheckNonArrayIndex(true, "4294967296"); CheckNonArrayIndex(true, "4294967296");
CheckNonArrayIndex(true, "-4294967296"); CheckNonArrayIndex(true, "-4294967296");
CheckNonArrayIndex( CheckNonArrayIndex(true, "999999999999999");
true, CheckNonArrayIndex(false, "9999999999999999");
"429496729642949672964294967296429496729642949672964294967296" CheckNonArrayIndex(true, "-999999999999999");
"429496729642949672964294967296429496729642949672964294967296" CheckNonArrayIndex(false, "-9999999999999999");
"429496729642949672964294967296429496729642949672964294967296" CheckNonArrayIndex(false, "42949672964294967296429496729694966");
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296");
CheckNonArrayIndex(
true,
"-429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296"
"429496729642949672964294967296429496729642949672964294967296");
} }
...@@ -530,10 +530,10 @@ function TestTypedArraysWithIllegalIndices() { ...@@ -530,10 +530,10 @@ function TestTypedArraysWithIllegalIndices() {
* assertEquals(undefined, a[-Infinity]); * assertEquals(undefined, a[-Infinity]);
*/ */
a[1.5] = 10; a[1.5] = 10;
assertEquals(10, a[1.5]); assertEquals(undefined, a[1.5]);
var nan = Math.sqrt(-1); var nan = Math.sqrt(-1);
a[nan] = 5; a[nan] = 5;
assertEquals(5, a[nan]); assertEquals(undefined, a[nan]);
var x = 0; var x = 0;
var y = -0; var y = -0;
...@@ -579,10 +579,10 @@ function TestTypedArraysWithIllegalIndicesStrict() { ...@@ -579,10 +579,10 @@ function TestTypedArraysWithIllegalIndicesStrict() {
* assertEquals(undefined, a[-Infinity]); * assertEquals(undefined, a[-Infinity]);
*/ */
a[1.5] = 10; a[1.5] = 10;
assertEquals(10, a[1.5]); assertEquals(undefined, a[1.5]);
var nan = Math.sqrt(-1); var nan = Math.sqrt(-1);
a[nan] = 5; a[nan] = 5;
assertEquals(5, a[nan]); assertEquals(undefined, a[nan]);
var x = 0; var x = 0;
var y = -0; var y = -0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment