diff --git a/src/conversions.h b/src/conversions.h index 70559c9e9d..e12cf5cdfc 100644 --- a/src/conversions.h +++ b/src/conversions.h @@ -57,13 +57,21 @@ inline double SignedZero(bool negative) { } +// The fast double-to-(unsigned-)int conversion routine does not guarantee +// rounding towards zero. +// For NaN and values outside the int range, return INT_MIN or INT_MAX. +inline int FastD2IChecked(double x) { + if (!(x >= INT_MIN)) return INT_MIN; // Negation to catch NaNs. + if (x > INT_MAX) return INT_MAX; + return static_cast(x); +} + + // The fast double-to-(unsigned-)int conversion routine does not guarantee // rounding towards zero. // The result is unspecified if x is infinite or NaN, or if the rounded // integer value is outside the range of type int. inline int FastD2I(double x) { - // The static_cast convertion from double to int used to be slow, but - // as new benchmarks show, now it is much faster than lrint(). return static_cast(x); } diff --git a/src/elements.cc b/src/elements.cc index f0e1414de4..4cb50a461d 100644 --- a/src/elements.cc +++ b/src/elements.cc @@ -800,7 +800,7 @@ class FastElementsAccessor } } else { // Otherwise, fill the unused tail with holes. - int old_length = FastD2I(array->length()->Number()); + int old_length = FastD2IChecked(array->length()->Number()); for (int i = length; i < old_length; i++) { backing_store->set_the_hole(i); } diff --git a/src/runtime.cc b/src/runtime.cc index f7bd0e4ad7..2aaa249752 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -3755,8 +3755,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) { } else { CONVERT_DOUBLE_ARG_CHECKED(from_number, 1); CONVERT_DOUBLE_ARG_CHECKED(to_number, 2); - start = FastD2I(from_number); - end = FastD2I(to_number); + start = FastD2IChecked(from_number); + end = FastD2IChecked(to_number); } RUNTIME_ASSERT(end >= start); RUNTIME_ASSERT(start >= 0); @@ -4224,7 +4224,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) { return *isolate->factory()->infinity_symbol(); } CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); - int f = FastD2I(f_number); + int f = FastD2IChecked(f_number); RUNTIME_ASSERT(f >= 0); char* str = DoubleToFixedCString(value, f); MaybeObject* res = @@ -4249,7 +4249,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) { return *isolate->factory()->infinity_symbol(); } CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); - int f = FastD2I(f_number); + int f = FastD2IChecked(f_number); RUNTIME_ASSERT(f >= -1 && f <= 20); char* str = DoubleToExponentialCString(value, f); MaybeObject* res = @@ -4274,7 +4274,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) { return *isolate->factory()->infinity_symbol(); } CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); - int f = FastD2I(f_number); + int f = FastD2IChecked(f_number); RUNTIME_ASSERT(f >= 1 && f <= 21); char* str = DoubleToPrecisionCString(value, f); MaybeObject* res = diff --git a/test/cctest/test-utils.cc b/test/cctest/test-utils.cc index df8ff72e4f..6cd931da4e 100644 --- a/test/cctest/test-utils.cc +++ b/test/cctest/test-utils.cc @@ -55,6 +55,22 @@ TEST(Utils1) { CHECK_EQ(-2, -8 >> 2); CHECK_EQ(-2, static_cast(-8) >> 2); CHECK_EQ(-2, static_cast(static_cast(-8) >> 2)); + + CHECK_EQ(-1000000, FastD2IChecked(-1000000.0)); + CHECK_EQ(-1, FastD2IChecked(-1.0)); + CHECK_EQ(0, FastD2IChecked(0.0)); + CHECK_EQ(1, FastD2IChecked(1.0)); + CHECK_EQ(1000000, FastD2IChecked(1000000.0)); + + CHECK_EQ(-1000000, FastD2IChecked(-1000000.123)); + CHECK_EQ(-1, FastD2IChecked(-1.234)); + CHECK_EQ(0, FastD2IChecked(0.345)); + CHECK_EQ(1, FastD2IChecked(1.234)); + CHECK_EQ(1000000, FastD2IChecked(1000000.123)); + + CHECK_EQ(INT_MAX, FastD2IChecked(1.0e100)); + CHECK_EQ(INT_MIN, FastD2IChecked(-1.0e100)); + CHECK_EQ(INT_MIN, FastD2IChecked(NAN)); }