Rewrite MakeDay function from JS to C++.
authoroleg@chromium.org <oleg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 2 Mar 2010 13:29:26 +0000 (13:29 +0000)
committeroleg@chromium.org <oleg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 2 Mar 2010 13:29:26 +0000 (13:29 +0000)
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
src/macros.py
src/runtime.cc
src/runtime.h

index 7d8f458..0ed59a7 100644 (file)
@@ -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);
 }
 
 
index ccc2037..9da2552 100644 (file)
@@ -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.
index d7770a7..e0011dd 100644 (file)
@@ -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);
index 18aada4..e4dc54b 100644 (file)
@@ -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) \