Commit 1b673208 authored by ager@chromium.org's avatar ager@chromium.org

Perform more aggressive time to NaN conversions. Our internal date

methods rely on the time values passed in being within a certain range
- not significantly larger than the the ECMA 262 specified time
range. When creating a time, always make it NaN if there is no way
that it can be within range even after UTC conversion.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6048 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent b20f0968
...@@ -81,12 +81,12 @@ function TimeFromYear(year) { ...@@ -81,12 +81,12 @@ function TimeFromYear(year) {
function InLeapYear(time) { function InLeapYear(time) {
return DaysInYear(YEAR_FROM_TIME(time)) == 366 ? 1 : 0; return DaysInYear(YearFromTime(time)) == 366 ? 1 : 0;
} }
function DayWithinYear(time) { function DayWithinYear(time) {
return DAY(time) - DayFromYear(YEAR_FROM_TIME(time)); return DAY(time) - DayFromYear(YearFromTime(time));
} }
...@@ -114,9 +114,9 @@ function EquivalentTime(t) { ...@@ -114,9 +114,9 @@ function EquivalentTime(t) {
// the actual year if it is in the range 1970..2037 // the actual year if it is in the range 1970..2037
if (t >= 0 && t <= 2.1e12) return t; if (t >= 0 && t <= 2.1e12) return t;
var day = MakeDay(EquivalentYear(YEAR_FROM_TIME(t)), var day = MakeDay(EquivalentYear(YearFromTime(t)),
MONTH_FROM_TIME(t), MonthFromTime(t),
DATE_FROM_TIME(t)); DateFromTime(t));
return MakeDate(day, TimeWithinDay(t)); return MakeDate(day, TimeWithinDay(t));
} }
...@@ -253,9 +253,6 @@ var ltcache = { ...@@ -253,9 +253,6 @@ var ltcache = {
function LocalTimeNoCheck(time) { function LocalTimeNoCheck(time) {
var ltc = ltcache; var ltc = ltcache;
if (%_ObjectEquals(time, ltc.key)) return ltc.val; if (%_ObjectEquals(time, ltc.key)) return ltc.val;
if (time < -MAX_TIME_MS || time > MAX_TIME_MS) {
return $NaN;
}
// Inline the DST offset cache checks for speed. // Inline the DST offset cache checks for speed.
// The cache is hit, or DaylightSavingsOffset is called, // The cache is hit, or DaylightSavingsOffset is called,
...@@ -371,16 +368,21 @@ function MakeDay(year, month, date) { ...@@ -371,16 +368,21 @@ function MakeDay(year, month, date) {
// ECMA 262 - 15.9.1.13 // ECMA 262 - 15.9.1.13
function MakeDate(day, time) { function MakeDate(day, time) {
if (!$isFinite(day)) return $NaN; var time = day * msPerDay + time;
if (!$isFinite(time)) return $NaN; // Some of our runtime funtions for computing UTC(time) rely on
return day * msPerDay + time; // times not being significantly larger than MAX_TIME_MS. If there
// is no way that the time can be within range even after UTC
// conversion we return NaN immediately instead of relying on
// TimeClip to do it.
if ($abs(time) > MAX_TIME_BEFORE_UTC) return $NaN;
return time;
} }
// ECMA 262 - 15.9.1.14 // ECMA 262 - 15.9.1.14
function TimeClip(time) { function TimeClip(time) {
if (!$isFinite(time)) return $NaN; if (!$isFinite(time)) return $NaN;
if ($abs(time) > 8.64E15) return $NaN; if ($abs(time) > MAX_TIME_MS) return $NaN;
return TO_INTEGER(time); return TO_INTEGER(time);
} }
...@@ -424,7 +426,7 @@ var Date_cache = { ...@@ -424,7 +426,7 @@ var Date_cache = {
value = DateParse(year); value = DateParse(year);
if (!NUMBER_IS_NAN(value)) { if (!NUMBER_IS_NAN(value)) {
cache.time = value; cache.time = value;
cache.year = YEAR_FROM_TIME(LocalTimeNoCheck(value)); cache.year = YearFromTime(LocalTimeNoCheck(value));
cache.string = year; cache.string = year;
} }
} }
...@@ -642,7 +644,7 @@ function DateGetFullYear() { ...@@ -642,7 +644,7 @@ function DateGetFullYear() {
if (NUMBER_IS_NAN(t)) return t; if (NUMBER_IS_NAN(t)) return t;
var cache = Date_cache; var cache = Date_cache;
if (cache.time === t) return cache.year; if (cache.time === t) return cache.year;
return YEAR_FROM_TIME(LocalTimeNoCheck(t)); return YearFromTime(LocalTimeNoCheck(t));
} }
...@@ -650,7 +652,7 @@ function DateGetFullYear() { ...@@ -650,7 +652,7 @@ function DateGetFullYear() {
function DateGetUTCFullYear() { function DateGetUTCFullYear() {
var t = DATE_VALUE(this); var t = DATE_VALUE(this);
if (NUMBER_IS_NAN(t)) return t; if (NUMBER_IS_NAN(t)) return t;
return YEAR_FROM_TIME(t); return YearFromTime(t);
} }
...@@ -658,7 +660,7 @@ function DateGetUTCFullYear() { ...@@ -658,7 +660,7 @@ function DateGetUTCFullYear() {
function DateGetMonth() { function DateGetMonth() {
var t = DATE_VALUE(this); var t = DATE_VALUE(this);
if (NUMBER_IS_NAN(t)) return t; if (NUMBER_IS_NAN(t)) return t;
return MONTH_FROM_TIME(LocalTimeNoCheck(t)); return MonthFromTime(LocalTimeNoCheck(t));
} }
...@@ -666,7 +668,7 @@ function DateGetMonth() { ...@@ -666,7 +668,7 @@ function DateGetMonth() {
function DateGetUTCMonth() { function DateGetUTCMonth() {
var t = DATE_VALUE(this); var t = DATE_VALUE(this);
if (NUMBER_IS_NAN(t)) return t; if (NUMBER_IS_NAN(t)) return t;
return MONTH_FROM_TIME(t); return MonthFromTime(t);
} }
...@@ -674,7 +676,7 @@ function DateGetUTCMonth() { ...@@ -674,7 +676,7 @@ function DateGetUTCMonth() {
function DateGetDate() { function DateGetDate() {
var t = DATE_VALUE(this); var t = DATE_VALUE(this);
if (NUMBER_IS_NAN(t)) return t; if (NUMBER_IS_NAN(t)) return t;
return DATE_FROM_TIME(LocalTimeNoCheck(t)); return DateFromTime(LocalTimeNoCheck(t));
} }
...@@ -869,7 +871,7 @@ function DateSetUTCHours(hour, min, sec, ms) { ...@@ -869,7 +871,7 @@ function DateSetUTCHours(hour, min, sec, ms) {
function DateSetDate(date) { function DateSetDate(date) {
var t = LocalTime(DATE_VALUE(this)); var t = LocalTime(DATE_VALUE(this));
date = ToNumber(date); date = ToNumber(date);
var day = MakeDay(YEAR_FROM_TIME(t), MONTH_FROM_TIME(t), date); var day = MakeDay(YearFromTime(t), MonthFromTime(t), date);
return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t))))); return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
} }
...@@ -878,7 +880,7 @@ function DateSetDate(date) { ...@@ -878,7 +880,7 @@ function DateSetDate(date) {
function DateSetUTCDate(date) { function DateSetUTCDate(date) {
var t = DATE_VALUE(this); var t = DATE_VALUE(this);
date = ToNumber(date); date = ToNumber(date);
var day = MakeDay(YEAR_FROM_TIME(t), MONTH_FROM_TIME(t), date); var day = MakeDay(YearFromTime(t), MonthFromTime(t), date);
return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t)))); return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
} }
...@@ -888,7 +890,7 @@ function DateSetMonth(month, date) { ...@@ -888,7 +890,7 @@ function DateSetMonth(month, date) {
var t = LocalTime(DATE_VALUE(this)); var t = LocalTime(DATE_VALUE(this));
month = ToNumber(month); month = ToNumber(month);
date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date); date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
var day = MakeDay(YEAR_FROM_TIME(t), month, date); var day = MakeDay(YearFromTime(t), month, date);
return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t))))); return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
} }
...@@ -898,7 +900,7 @@ function DateSetUTCMonth(month, date) { ...@@ -898,7 +900,7 @@ function DateSetUTCMonth(month, date) {
var t = DATE_VALUE(this); var t = DATE_VALUE(this);
month = ToNumber(month); month = ToNumber(month);
date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date); date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
var day = MakeDay(YEAR_FROM_TIME(t), month, date); var day = MakeDay(YearFromTime(t), month, date);
return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t)))); return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
} }
...@@ -909,8 +911,8 @@ function DateSetFullYear(year, month, date) { ...@@ -909,8 +911,8 @@ function DateSetFullYear(year, month, date) {
t = NUMBER_IS_NAN(t) ? 0 : LocalTimeNoCheck(t); t = NUMBER_IS_NAN(t) ? 0 : LocalTimeNoCheck(t);
year = ToNumber(year); year = ToNumber(year);
var argc = %_ArgumentsLength(); var argc = %_ArgumentsLength();
month = argc < 2 ? MONTH_FROM_TIME(t) : ToNumber(month); month = argc < 2 ? MonthFromTime(t) : ToNumber(month);
date = argc < 3 ? DATE_FROM_TIME(t) : ToNumber(date); date = argc < 3 ? DateFromTime(t) : ToNumber(date);
var day = MakeDay(year, month, date); var day = MakeDay(year, month, date);
return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t))))); return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
} }
...@@ -922,8 +924,8 @@ function DateSetUTCFullYear(year, month, date) { ...@@ -922,8 +924,8 @@ function DateSetUTCFullYear(year, month, date) {
if (NUMBER_IS_NAN(t)) t = 0; if (NUMBER_IS_NAN(t)) t = 0;
var argc = %_ArgumentsLength(); var argc = %_ArgumentsLength();
year = ToNumber(year); year = ToNumber(year);
month = argc < 2 ? MONTH_FROM_TIME(t) : ToNumber(month); month = argc < 2 ? MonthFromTime(t) : ToNumber(month);
date = argc < 3 ? DATE_FROM_TIME(t) : ToNumber(date); date = argc < 3 ? DateFromTime(t) : ToNumber(date);
var day = MakeDay(year, month, date); var day = MakeDay(year, month, date);
return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t)))); return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
} }
...@@ -935,9 +937,9 @@ function DateToUTCString() { ...@@ -935,9 +937,9 @@ function DateToUTCString() {
if (NUMBER_IS_NAN(t)) return kInvalidDate; if (NUMBER_IS_NAN(t)) return kInvalidDate;
// Return UTC string of the form: Sat, 31 Jan 1970 23:00:00 GMT // Return UTC string of the form: Sat, 31 Jan 1970 23:00:00 GMT
return WeekDays[WeekDay(t)] + ', ' return WeekDays[WeekDay(t)] + ', '
+ TwoDigitString(DATE_FROM_TIME(t)) + ' ' + TwoDigitString(DateFromTime(t)) + ' '
+ Months[MONTH_FROM_TIME(t)] + ' ' + Months[MonthFromTime(t)] + ' '
+ YEAR_FROM_TIME(t) + ' ' + YearFromTime(t) + ' '
+ TimeString(t) + ' GMT'; + TimeString(t) + ' GMT';
} }
...@@ -946,7 +948,7 @@ function DateToUTCString() { ...@@ -946,7 +948,7 @@ function DateToUTCString() {
function DateGetYear() { function DateGetYear() {
var t = DATE_VALUE(this); var t = DATE_VALUE(this);
if (NUMBER_IS_NAN(t)) return $NaN; if (NUMBER_IS_NAN(t)) return $NaN;
return YEAR_FROM_TIME(LocalTimeNoCheck(t)) - 1900; return YearFromTime(LocalTimeNoCheck(t)) - 1900;
} }
...@@ -958,7 +960,7 @@ function DateSetYear(year) { ...@@ -958,7 +960,7 @@ function DateSetYear(year) {
if (NUMBER_IS_NAN(year)) return %_SetValueOf(this, $NaN); if (NUMBER_IS_NAN(year)) return %_SetValueOf(this, $NaN);
year = (0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99) year = (0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
? 1900 + TO_INTEGER(year) : year; ? 1900 + TO_INTEGER(year) : year;
var day = MakeDay(year, MONTH_FROM_TIME(t), DATE_FROM_TIME(t)); var day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t))))); return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
} }
......
...@@ -140,15 +140,14 @@ macro NUMBER_OF_CAPTURES(array) = ((array)[0]); ...@@ -140,15 +140,14 @@ macro NUMBER_OF_CAPTURES(array) = ((array)[0]);
# Limit according to ECMA 262 15.9.1.1 # Limit according to ECMA 262 15.9.1.1
const MAX_TIME_MS = 8640000000000000; const MAX_TIME_MS = 8640000000000000;
# Limit which is MAX_TIME_MS + msPerMonth.
const MAX_TIME_BEFORE_UTC = 8640002592000000;
# Gets the value of a Date object. If arg is not a Date object # Gets the value of a Date object. If arg is not a Date object
# a type error is thrown. # a type error is thrown.
macro DATE_VALUE(arg) = (%_ClassOf(arg) === 'Date' ? %_ValueOf(arg) : ThrowDateTypeError()); macro DATE_VALUE(arg) = (%_ClassOf(arg) === 'Date' ? %_ValueOf(arg) : ThrowDateTypeError());
macro DAY(time) = ($floor(time / 86400000)); macro DAY(time) = ($floor(time / 86400000));
macro MONTH_FROM_TIME(time) = (MonthFromTime(time)); macro NAN_OR_DATE_FROM_TIME(time) = (NUMBER_IS_NAN(time) ? time : DateFromTime(time));
macro DATE_FROM_TIME(time) = (DateFromTime(time));
macro NAN_OR_DATE_FROM_TIME(time) = (NUMBER_IS_NAN(time) ? time : DATE_FROM_TIME(time));
macro YEAR_FROM_TIME(time) = (YearFromTime(time));
macro HOUR_FROM_TIME(time) = (Modulo($floor(time / 3600000), 24)); macro HOUR_FROM_TIME(time) = (Modulo($floor(time / 3600000), 24));
macro MIN_FROM_TIME(time) = (Modulo($floor(time / 60000), 60)); macro MIN_FROM_TIME(time) = (Modulo($floor(time / 60000), 60));
macro NAN_OR_MIN_FROM_TIME(time) = (NUMBER_IS_NAN(time) ? time : MIN_FROM_TIME(time)); macro NAN_OR_MIN_FROM_TIME(time) = (NUMBER_IS_NAN(time) ? time : MIN_FROM_TIME(time));
......
...@@ -167,8 +167,8 @@ assertDoesNotThrow("new Date(-0x40000001, -0x40000001, -0x40000001," + ...@@ -167,8 +167,8 @@ assertDoesNotThrow("new Date(-0x40000001, -0x40000001, -0x40000001," +
// Modified test from WebKit // Modified test from WebKit
// LayoutTests/fast/js/script-tests/date-utc-timeclip.js: // LayoutTests/fast/js/script-tests/date-utc-timeclip.js:
assertEquals(Date.UTC(275760, 8, 12, 23, 59, 59, 999), 8639999999999999); assertEquals(8639999999999999, Date.UTC(275760, 8, 12, 23, 59, 59, 999));
assertEquals(Date.UTC(275760, 8, 13), 8640000000000000); assertEquals(8640000000000000, Date.UTC(275760, 8, 13));
assertTrue(isNaN(Date.UTC(275760, 8, 13, 0, 0, 0, 1))); assertTrue(isNaN(Date.UTC(275760, 8, 13, 0, 0, 0, 1)));
assertTrue(isNaN(Date.UTC(275760, 8, 14))); assertTrue(isNaN(Date.UTC(275760, 8, 14)));
...@@ -176,3 +176,14 @@ assertEquals(Date.UTC(-271821, 3, 20, 0, 0, 0, 1), -8639999999999999); ...@@ -176,3 +176,14 @@ assertEquals(Date.UTC(-271821, 3, 20, 0, 0, 0, 1), -8639999999999999);
assertEquals(Date.UTC(-271821, 3, 20), -8640000000000000); assertEquals(Date.UTC(-271821, 3, 20), -8640000000000000);
assertTrue(isNaN(Date.UTC(-271821, 3, 19, 23, 59, 59, 999))); assertTrue(isNaN(Date.UTC(-271821, 3, 19, 23, 59, 59, 999)));
assertTrue(isNaN(Date.UTC(-271821, 3, 19))); assertTrue(isNaN(Date.UTC(-271821, 3, 19)));
// Test creation of large date values.
d = new Date(1969, 12, 1, 99999999999);
assertTrue(isNaN(d.getTime()));
d = new Date(1969, 12, 1, -99999999999);
assertTrue(isNaN(d.getTime()));
d = new Date(1969, 12, 1, Infinity);
assertTrue(isNaN(d.getTime()));
d = new Date(1969, 12, 1, -Infinity);
assertTrue(isNaN(d.getTime()));
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