From b021997f81c524c262ffeb19f5c74bd0437a475e Mon Sep 17 00:00:00 2001 From: "oleg@chromium.org" Date: Tue, 2 Mar 2010 13:29:26 +0000 Subject: [PATCH] Rewrite MakeDay function from JS to C++. Review URL: http://codereview.chromium.org/661366 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3997 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/date-delay.js | 31 +++++++++++++------------------ src/macros.py | 10 ++++++++++ src/runtime.cc | 33 +++++++++++++++++++++++++++++++++ src/runtime.h | 1 + 4 files changed, 57 insertions(+), 18 deletions(-) diff --git a/src/date-delay.js b/src/date-delay.js index 7d8f45888f..0ed59a7030 100644 --- a/src/date-delay.js +++ b/src/date-delay.js @@ -113,8 +113,13 @@ function EquivalentTime(t) { // we must do this, but for compatibility with other browsers, we use // the actual year if it is in the range 1970..2037 if (t >= 0 && t <= 2.1e12) return t; - var day = MakeDay(EquivalentYear(YEAR_FROM_TIME(t)), MONTH_FROM_TIME(t), DATE_FROM_TIME(t)); - return TimeClip(MakeDate(day, TimeWithinDay(t))); + + // We call the function from runtime.cc directly to avoid extra checks which + // are unneeded. + var day = %DateMakeDay(EquivalentYear(YEAR_FROM_TIME(t)), + MONTH_FROM_TIME(t), + DATE_FROM_TIME(t)); + return MakeDate(day, TimeWithinDay(t)); } @@ -257,14 +262,6 @@ function TimeInYear(year) { } -// Compute modified Julian day from year, month, date. -function ToJulianDay(year, month, date) { - var jy = (month > 1) ? year : year - 1; - var jm = (month > 1) ? month + 2 : month + 14; - var ja = FLOOR(jy / 100); - return FLOOR(FLOOR(365.25*jy) + FLOOR(30.6001*jm) + date + 1720995) + 2 - ja + FLOOR(0.25*ja); -} - var four_year_cycle_table = CalculateDateTable(); @@ -359,20 +356,18 @@ function FromJulianDay(julian) { function MakeDay(year, month, date) { if (!$isFinite(year) || !$isFinite(month) || !$isFinite(date)) return $NaN; - // Conversion to integers. year = TO_INTEGER(year); month = TO_INTEGER(month); date = TO_INTEGER(date); - // Overflow months into year. - year = year + FLOOR(month/12); - month = month % 12; - if (month < 0) { - month += 12; + if (year < kMinYear || year > kMaxYear || + month < kMinMonth || month > kMaxMonth || + date < kMinDate || date > kMaxDate) { + return $NaN; } - // Return days relative to Jan 1 1970. - return ToJulianDay(year, month, date) - kDayZeroInJulianDay; + // Now we rely on year, month and date being SMIs. + return %DateMakeDay(year, month, date); } diff --git a/src/macros.py b/src/macros.py index ccc2037f23..9da2552479 100644 --- a/src/macros.py +++ b/src/macros.py @@ -73,6 +73,16 @@ const kDayMask = 0x01f; const kYearShift = 9; const kMonthShift = 5; +# Limits for parts of the date, so that we support all the dates that +# ECMA 262 - 15.9.1.1 requires us to, but at the same time be sure that +# the date (days since 1970) is in SMI range. +const kMinYear = -1000000; +const kMaxYear = 1000000; +const kMinMonth = -10000000; +const kMaxMonth = 10000000; +const kMinDate = -100000000; +const kMaxDate = 100000000; + # Type query macros. # # Note: We have special support for typeof(foo) === 'bar' in the compiler. diff --git a/src/runtime.cc b/src/runtime.cc index d7770a73a3..e0011dd31c 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -4941,6 +4941,39 @@ static Object* Runtime_Math_tan(Arguments args) { } +static Object* Runtime_DateMakeDay(Arguments args) { + NoHandleAllocation ha; + ASSERT(args.length() == 3); + + CONVERT_SMI_CHECKED(year, args[0]); + CONVERT_SMI_CHECKED(month, args[1]); + CONVERT_SMI_CHECKED(date, args[2]); + + 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, + 182, 213, 244, 274, 305, 335}; + + year += month / 12; + month %= 12; + if (month < 0) { + year--; + month += 12; + } + + static const int base_day = 365*1969 + 1969/4 - 1969/100 + 1969/400; + int year1 = year - 1; + int day_from_year = 365 * year1 + year1 / 4 - year1 / 100 + year1 / 400 - + base_day; + + if (year % 4 || (year % 100 == 0 && year % 400 != 0)) { + return Smi::FromInt(day_from_year + day_from_month[month] + date - 1); + } else { + return Smi::FromInt(day_from_year + day_from_month_leap[month] + date - 1); + } +} + + static Object* Runtime_NewArgumentsFast(Arguments args) { NoHandleAllocation ha; ASSERT(args.length() == 3); diff --git a/src/runtime.h b/src/runtime.h index 18aada4968..e4dc54b99e 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -202,6 +202,7 @@ namespace internal { F(DateLocalTimezone, 1, 1) \ F(DateLocalTimeOffset, 0, 1) \ F(DateDaylightSavingsOffset, 1, 1) \ + F(DateMakeDay, 3, 1) \ \ /* Numbers */ \ F(NumberIsFinite, 1, 1) \