Fix: make string indexing work with Infinity.

NumberToUint32 that I was trying to use maps -0 to +0 (as desired) but
also maps +/-Infinity to +0, which made +/-Infinity a valid string
index. I fixed it by introducing a new runtime function with the right
semantics.

TEST=LayoutTests/fast/js/char-at.html,mjsunit/string-charat.js

Review URL: http://codereview.chromium.org/2223003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4734 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
vitalyr@chromium.org 2010-05-26 16:11:30 +00:00
parent ad0e38909f
commit 64bc39a726
6 changed files with 27 additions and 15 deletions

View File

@ -9284,11 +9284,7 @@ void StringCharCodeAtGenerator::GenerateSlow(
__ Push(object_, index_, result_);
__ push(index_); // Consumed by runtime conversion function.
if (index_flags_ == STRING_INDEX_IS_NUMBER) {
// Strictly speaking, NumberToInteger should be called here, but
// our string lengths don't exceed 32 bits and using ToUint32 maps
// -0 to 0, which is what is required by the spec when accessing
// strings.
__ CallRuntime(Runtime::kNumberToJSUint32, 1);
__ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
} else {
ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
// NumberToSmi discards numbers that are not exact integers.

View File

@ -12655,11 +12655,7 @@ void StringCharCodeAtGenerator::GenerateSlow(
__ push(result_);
__ push(index_); // Consumed by runtime conversion function.
if (index_flags_ == STRING_INDEX_IS_NUMBER) {
// Strictly speaking, NumberToInteger should be called here, but
// our string lengths don't exceed 32 bits and using ToUint32 maps
// -0 to 0, which is what is required by the spec when accessing
// strings.
__ CallRuntime(Runtime::kNumberToJSUint32, 1);
__ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
} else {
ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
// NumberToSmi discards numbers that are not exact integers.

View File

@ -5287,6 +5287,25 @@ static Object* Runtime_NumberToInteger(Arguments args) {
}
static Object* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_DOUBLE_CHECKED(number, args[0]);
// We do not include 0 so that we don't have to treat +0 / -0 cases.
if (number > 0 && number <= Smi::kMaxValue) {
return Smi::FromInt(static_cast<int>(number));
}
double double_value = DoubleToInteger(number);
// Map both -0 and +0 to +0.
if (double_value == 0) double_value = 0;
return Heap::NumberFromDouble(double_value);
}
static Object* Runtime_NumberToJSUint32(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);

View File

@ -102,6 +102,7 @@ namespace internal {
F(NumberToString, 1, 1) \
F(NumberToStringSkipCache, 1, 1) \
F(NumberToInteger, 1, 1) \
F(NumberToIntegerMapMinusZero, 1, 1) \
F(NumberToJSUint32, 1, 1) \
F(NumberToJSInt32, 1, 1) \
F(NumberToSmi, 1, 1) \

View File

@ -10935,11 +10935,7 @@ void StringCharCodeAtGenerator::GenerateSlow(
__ push(result_);
__ push(index_); // Consumed by runtime conversion function.
if (index_flags_ == STRING_INDEX_IS_NUMBER) {
// Strictly speaking, NumberToInteger should be called here, but
// our string lengths don't exceed 32 bits and using ToUint32 maps
// -0 to 0, which is what is required by the spec when accessing
// strings.
__ CallRuntime(Runtime::kNumberToJSUint32, 1);
__ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
} else {
ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
// NumberToSmi discards numbers that are not exact integers.

View File

@ -41,6 +41,8 @@ function basicTest() {
assertEquals("", s.charAt(-1));
assertEquals("", s.charAt(4));
assertEquals("", s.charAt(slowIndexOutOfRange));
assertEquals("", s.charAt(1/0));
assertEquals("", s.charAt(-1/0));
assertEquals("t", s.charAt(0));
assertEquals("t", s.charAt(-0.0));
assertEquals("t", s.charAt(0.4));
@ -67,6 +69,8 @@ function basicTest() {
assertTrue(isNaN(s.charCodeAt(-1)));
assertTrue(isNaN(s.charCodeAt(4)));
assertTrue(isNaN(s.charCodeAt(slowIndexOutOfRange)));
assertTrue(isNaN(s.charCodeAt(1/0)));
assertTrue(isNaN(s.charCodeAt(-1/0)));
}
basicTest();