Fix error handling in Date.prototype.toISOString.

This fixes Date.prototyoe.toISOString to throw a RangeError exception
for invalid time values. It also includes a fix to removes the arbitrary
(and completely bogus) range limit on the date value during construction
of a Date object. Note that we still have bogus range limits on the year
and month values.

R=lrn@chromium.org
BUG=v8:1792
TEST=mjsunit/date,test262/15.9.5.43-0-*

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9829 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f077a41b
......@@ -351,13 +351,12 @@ function MakeDay(year, month, date) {
date = TO_INTEGER_MAP_MINUS_ZERO(date);
if (year < kMinYear || year > kMaxYear ||
month < kMinMonth || month > kMaxMonth ||
date < kMinDate || date > kMaxDate) {
month < kMinMonth || month > kMaxMonth) {
return $NaN;
}
// Now we rely on year, month and date being SMIs.
return %DateMakeDay(year, month, date);
// Now we rely on year and month being SMIs.
return %DateMakeDay(year, month) + date - 1;
}
......@@ -978,9 +977,10 @@ function PadInt(n, digits) {
}
// ECMA 262 - 15.9.5.43
function DateToISOString() {
var t = DATE_VALUE(this);
if (NUMBER_IS_NAN(t)) return kInvalidDate;
if (NUMBER_IS_NAN(t)) throw MakeRangeError("invalid_time_value", []);
var year = this.getUTCFullYear();
var year_string;
if (year >= 0 && year <= 9999) {
......
......@@ -82,8 +82,6 @@ const kMinYear = -1000000;
const kMaxYear = 1000000;
const kMinMonth = -10000000;
const kMaxMonth = 10000000;
const kMinDate = -100000000;
const kMaxDate = 100000000;
# Native cache ids.
const STRING_TO_REGEXP_CACHE_ID = 0;
......
......@@ -198,6 +198,7 @@ function FormatMessage(message) {
// RangeError
"invalid_array_length", ["Invalid array length"],
"stack_overflow", ["Maximum call stack size exceeded"],
"invalid_time_value", ["Invalid time value"],
// SyntaxError
"unable_to_parse", ["Parse error"],
"invalid_regexp_flags", ["Invalid flags supplied to RegExp constructor '", "%0", "'"],
......
......@@ -7490,7 +7490,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
}
static int MakeDay(int year, int month, int day) {
static int MakeDay(int year, int month) {
static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
181, 212, 243, 273, 304, 334};
static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
......@@ -7527,23 +7527,22 @@ static int MakeDay(int year, int month, int day) {
year1 / 400 -
base_day;
if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
return day_from_year + day_from_month[month] + day - 1;
if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
return day_from_year + day_from_month[month];
}
return day_from_year + day_from_month_leap[month] + day - 1;
return day_from_year + day_from_month_leap[month];
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
NoHandleAllocation ha;
ASSERT(args.length() == 3);
ASSERT(args.length() == 2);
CONVERT_SMI_ARG_CHECKED(year, 0);
CONVERT_SMI_ARG_CHECKED(month, 1);
CONVERT_SMI_ARG_CHECKED(date, 2);
return Smi::FromInt(MakeDay(year, month, date));
return Smi::FromInt(MakeDay(year, month));
}
......@@ -7772,7 +7771,7 @@ static inline void DateYMDFromTimeAfter1970(int date,
month = kMonthInYear[date];
day = kDayInYear[date];
ASSERT(MakeDay(year, month, day) == save_date);
ASSERT(MakeDay(year, month) + day - 1 == save_date);
}
......@@ -7786,7 +7785,7 @@ static inline void DateYMDFromTimeSlow(int date,
year = 400 * (date / kDaysIn400Years) - kYearsOffset;
date %= kDaysIn400Years;
ASSERT(MakeDay(year, 0, 1) + date == save_date);
ASSERT(MakeDay(year, 0) + date == save_date);
date--;
int yd1 = date / kDaysIn100Years;
......@@ -7809,8 +7808,8 @@ static inline void DateYMDFromTimeSlow(int date,
ASSERT(is_leap || (date >= 0));
ASSERT((date < 365) || (is_leap && (date < 366)));
ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
if (is_leap) {
day = kDayInYear[2*365 + 1 + date];
......@@ -7820,7 +7819,7 @@ static inline void DateYMDFromTimeSlow(int date,
month = kMonthInYear[date];
}
ASSERT(MakeDay(year, month, day) == save_date);
ASSERT(MakeDay(year, month) + day - 1 == save_date);
}
......
......@@ -246,7 +246,7 @@ namespace internal {
F(DateLocalTimezone, 1, 1) \
F(DateLocalTimeOffset, 0, 1) \
F(DateDaylightSavingsOffset, 1, 1) \
F(DateMakeDay, 3, 1) \
F(DateMakeDay, 2, 1) \
F(DateYMDFromTime, 2, 1) \
\
/* Numbers */ \
......
......@@ -157,7 +157,7 @@ testToLocaleTimeString();
// Test that -0 is treated correctly in MakeDay.
var d = new Date();
assertDoesNotThrow("d.setDate(-0)");
assertDoesNotThrow("new Date(-0, -0, -0, -0, -0, -0. -0)");
assertDoesNotThrow("new Date(-0, -0, -0, -0, -0, -0, -0)");
assertDoesNotThrow("new Date(0x40000000, 0x40000000, 0x40000000," +
"0x40000000, 0x40000000, 0x40000000, 0x40000000)")
assertDoesNotThrow("new Date(-0x40000001, -0x40000001, -0x40000001," +
......@@ -178,7 +178,7 @@ assertTrue(isNaN(Date.UTC(-271821, 3, 19, 23, 59, 59, 999)));
assertTrue(isNaN(Date.UTC(-271821, 3, 19)));
// Test creation of large date values.
// Test creation with large date values.
d = new Date(1969, 12, 1, 99999999999);
assertTrue(isNaN(d.getTime()));
d = new Date(1969, 12, 1, -99999999999);
......@@ -188,6 +188,17 @@ assertTrue(isNaN(d.getTime()));
d = new Date(1969, 12, 1, -Infinity);
assertTrue(isNaN(d.getTime()));
// Test creation with obscure date values.
var timezoneOffset = new Date().getTimezoneOffset();
d = new Date(1970, 0, 1 + 100000001, -24, -timezoneOffset);
assertFalse(isNaN(d.getTime()));
assertEquals(8640000000000000, d.getTime())
d = new Date(1970, 0, 1 - 100000001, 24, -timezoneOffset);
assertFalse(isNaN(d.getTime()));
assertEquals(-8640000000000000, d.getTime())
// Parsing ES5 ISO-8601 dates.
// When TZ is omitted, it defaults to 'Z' meaning UTC.
......
......@@ -131,12 +131,6 @@ S15.3_A3_T3: FAIL
##################### DELIBERATE INCOMPATIBILITIES #####################
# 15.9.5.43-0-9 and 15.9.5.43-0-10. V8 doesn't throw RangeError
# from Date.prototype.toISOString when string is not a finite number.
# This is compatible with Firefox and Safari.
15.9.5.43-0-9: PASS || FAIL
15.9.5.43-0-10: PASS || FAIL
# We deliberately treat arguments to parseInt() with a leading zero as
# octal numbers in order to not break the web.
S15.1.2.2_A5.1_T1: FAIL_OK
......@@ -478,24 +472,6 @@ S15.4.4.3_A2_T1: FAIL_OK
# Bug? Array.prototype.reduceRight - decreasing length of array does not delete
# non-configurable properties
15.4.4.22-9-b-29: FAIL
# Bug? Date.prototype.toISOString - RangeError is thrown when value of date is
# Date(1970, 0, -99999999, 0, 0, 0, -1), the time zone is UTC(0)
15.9.5.43-0-8: FAIL
# Bug? Date.prototype.toISOString - RangeError is not thrown when value of date
# is Date(1970, 0, 100000001, 0, 0, 0, -1), the time zone is UTC(0)
15.9.5.43-0-11: FAIL
# Bug? Date.prototype.toISOString - RangeError is not thrown when value of date
# is Date(1970, 0, 100000001, 0, 0, 0, 0), the time zone is UTC(0)
15.9.5.43-0-12: FAIL
# Bug? Date.prototype.toISOString - RangeError is thrown when value of date is
# Date(1970, 0, 100000001, 0, 0, 0, 1), the time zone is UTC(0)
15.9.5.43-0-13: FAIL
# Bug? Date.prototype.toISOString - when value of year is -Infinity
# Date.prototype.toISOString throw the RangeError
15.9.5.43-0-14: FAIL
# Bug? Date.prototype.toISOString - value of year is Infinity
# Date.prototype.toISOString throw the RangeError
15.9.5.43-0-15: FAIL
############################ SKIPPED TESTS #############################
......
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