Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (251851 => 251852)
--- trunk/Source/_javascript_Core/ChangeLog 2019-10-31 16:01:25 UTC (rev 251851)
+++ trunk/Source/_javascript_Core/ChangeLog 2019-10-31 16:14:03 UTC (rev 251852)
@@ -1,3 +1,26 @@
+2019-10-31 Yusuke Suzuki <[email protected]>
+
+ [JSC] DateMath should have TimeClipped version
+ https://bugs.webkit.org/show_bug.cgi?id=203550
+
+ Reviewed by Saam Barati.
+
+ Removing `using namespace WTF;` in Date related files in JSC.
+
+ * runtime/DateConstructor.cpp:
+ * runtime/DateConversion.cpp:
+ (JSC::formatDateTime):
+ * runtime/DateInstance.cpp:
+ * runtime/DatePrototype.cpp:
+ * runtime/JSDateMath.cpp:
+ (JSC::localTimeOffset):
+ (JSC::timeToMS):
+ (JSC::gregorianDateTimeToMS):
+ (JSC::msToGregorianDateTime):
+ (JSC::parseDate):
+ (JSC::msToSeconds): Deleted.
+ (JSC::msToWeekDay): Deleted.
+
2019-10-30 Peng Liu <[email protected]>
[Picture-in-Picture Web API] Enable the support for iOS
Modified: trunk/Source/_javascript_Core/runtime/DateConstructor.cpp (251851 => 251852)
--- trunk/Source/_javascript_Core/runtime/DateConstructor.cpp 2019-10-31 16:01:25 UTC (rev 251851)
+++ trunk/Source/_javascript_Core/runtime/DateConstructor.cpp 2019-10-31 16:14:03 UTC (rev 251852)
@@ -55,8 +55,6 @@
namespace JSC {
-using namespace WTF;
-
const ClassInfo DateConstructor::s_info = { "Function", &InternalFunction::s_info, &dateConstructorTable, nullptr, CREATE_METHOD_TABLE(DateConstructor) };
/* Source for DateConstructor.lut.h
Modified: trunk/Source/_javascript_Core/runtime/DateConversion.cpp (251851 => 251852)
--- trunk/Source/_javascript_Core/runtime/DateConversion.cpp 2019-10-31 16:01:25 UTC (rev 251851)
+++ trunk/Source/_javascript_Core/runtime/DateConversion.cpp 2019-10-31 16:14:03 UTC (rev 251852)
@@ -36,8 +36,6 @@
namespace JSC {
-using namespace WTF;
-
template<int width>
static inline void appendNumber(StringBuilder& builder, int value)
{
@@ -68,16 +66,16 @@
StringBuilder builder;
if (appendDate) {
- builder.append(weekdayName[(t.weekDay() + 6) % 7]);
+ builder.append(WTF::weekdayName[(t.weekDay() + 6) % 7]);
if (asUTCVariant) {
builder.appendLiteral(", ");
appendNumber<2>(builder, t.monthDay());
builder.append(' ');
- builder.append(monthName[t.month()]);
+ builder.append(WTF::monthName[t.month()]);
} else {
builder.append(' ');
- builder.append(monthName[t.month()]);
+ builder.append(WTF::monthName[t.month()]);
builder.append(' ');
appendNumber<2>(builder, t.monthDay());
}
Modified: trunk/Source/_javascript_Core/runtime/DateInstance.cpp (251851 => 251852)
--- trunk/Source/_javascript_Core/runtime/DateInstance.cpp 2019-10-31 16:01:25 UTC (rev 251851)
+++ trunk/Source/_javascript_Core/runtime/DateInstance.cpp 2019-10-31 16:14:03 UTC (rev 251852)
@@ -30,8 +30,6 @@
namespace JSC {
-using namespace WTF;
-
const ClassInfo DateInstance::s_info = {"Date", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DateInstance)};
DateInstance::DateInstance(VM& vm, Structure* structure)
Modified: trunk/Source/_javascript_Core/runtime/DatePrototype.cpp (251851 => 251852)
--- trunk/Source/_javascript_Core/runtime/DatePrototype.cpp 2019-10-31 16:01:25 UTC (rev 251851)
+++ trunk/Source/_javascript_Core/runtime/DatePrototype.cpp 2019-10-31 16:14:03 UTC (rev 251852)
@@ -69,8 +69,6 @@
namespace JSC {
-using namespace WTF;
-
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(JSGlobalObject*, CallFrame*);
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(JSGlobalObject*, CallFrame*);
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(JSGlobalObject*, CallFrame*);
Modified: trunk/Source/_javascript_Core/runtime/JSDateMath.cpp (251851 => 251852)
--- trunk/Source/_javascript_Core/runtime/JSDateMath.cpp 2019-10-31 16:01:25 UTC (rev 251851)
+++ trunk/Source/_javascript_Core/runtime/JSDateMath.cpp 2019-10-31 16:14:03 UTC (rev 251852)
@@ -100,30 +100,6 @@
namespace JSC {
-using namespace WTF;
-
-static inline double timeToMS(double hour, double min, double sec, double ms)
-{
- return (((hour * minutesPerHour + min) * secondsPerMinute + sec) * msPerSecond + ms);
-}
-
-static inline int msToSeconds(double ms)
-{
- double result = fmod(floor(ms / msPerSecond), secondsPerMinute);
- if (result < 0)
- result += secondsPerMinute;
- return static_cast<int>(result);
-}
-
-// 0: Sunday, 1: Monday, etc.
-static inline int msToWeekDay(double ms)
-{
- int wd = (static_cast<int>(msToDays(ms)) + 4) % 7;
- if (wd < 0)
- wd += 7;
- return wd;
-}
-
// Get the combined UTC + DST offset for the time passed in.
//
// NOTE: The implementation relies on the fact that no time zones have
@@ -152,7 +128,7 @@
// the offset in the cache, we grow the cached time interval
// and return the offset.
cache.end = newEnd;
- cache.increment = msPerMonth;
+ cache.increment = WTF::msPerMonth;
return endOffset;
}
LocalTimeOffset offset = calculateLocalTimeOffset(ms, inputTimeType);
@@ -163,7 +139,7 @@
// the interval to reflect this and reset the increment.
cache.start = ms;
cache.end = newEnd;
- cache.increment = msPerMonth;
+ cache.increment = WTF::msPerMonth;
} else {
// The interval contains a DST offset change and the given time is
// before it. Adjust the increment to avoid a linear search for
@@ -184,10 +160,15 @@
cache.offset = offset;
cache.start = ms;
cache.end = ms;
- cache.increment = msPerMonth;
+ cache.increment = WTF::msPerMonth;
return offset;
}
+static inline double timeToMS(double hour, double min, double sec, double ms)
+{
+ return (((hour * WTF::minutesPerHour + min) * WTF::secondsPerMinute + sec) * WTF::msPerSecond + ms);
+}
+
double gregorianDateTimeToMS(VM& vm, const GregorianDateTime& t, double milliSeconds, WTF::TimeType inputTimeType)
{
double day = dateToDaysFrom1970(t.year(), t.month(), t.monthDay());
@@ -194,7 +175,7 @@
double ms = timeToMS(t.hour(), t.minute(), t.second(), milliSeconds);
double localTimeResult = (day * WTF::msPerDay) + ms;
- double localToUTCTimeOffset = inputTimeType == LocalTime
+ double localToUTCTimeOffset = inputTimeType == WTF::LocalTime
? localTimeOffset(vm, localTimeResult, inputTimeType).offset : 0;
return localTimeResult - localToUTCTimeOffset;
@@ -208,18 +189,7 @@
localTime = localTimeOffset(vm, ms);
ms += localTime.offset;
}
-
- const int year = msToYear(ms);
- tm.setSecond(msToSeconds(ms));
- tm.setMinute(msToMinutes(ms));
- tm.setHour(msToHours(ms));
- tm.setWeekDay(msToWeekDay(ms));
- tm.setYearDay(dayInYear(ms, year));
- tm.setMonthDay(dayInMonthFromDayInYear(tm.yearDay(), isLeapYear(year)));
- tm.setMonth(monthFromDayInYear(tm.yearDay(), isLeapYear(year)));
- tm.setYear(year);
- tm.setIsDST(localTime.isDST);
- tm.setUTCOffsetInMinute(localTime.offset / WTF::msPerMinute);
+ tm = GregorianDateTime(ms, localTime);
}
double parseDateFromNullTerminatedCharacters(VM& vm, const char* dateString)
@@ -254,7 +224,7 @@
}
auto dateUtf8 = expectedString.value();
- double value = parseES5DateFromNullTerminatedCharacters(dateUtf8.data());
+ double value = WTF::parseES5DateFromNullTerminatedCharacters(dateUtf8.data());
if (std::isnan(value))
value = parseDateFromNullTerminatedCharacters(vm, dateUtf8.data());
vm.cachedDateString = date;
Modified: trunk/Source/WTF/ChangeLog (251851 => 251852)
--- trunk/Source/WTF/ChangeLog 2019-10-31 16:01:25 UTC (rev 251851)
+++ trunk/Source/WTF/ChangeLog 2019-10-31 16:14:03 UTC (rev 251852)
@@ -1,3 +1,59 @@
+2019-10-31 Yusuke Suzuki <[email protected]>
+
+ [JSC] DateMath should have TimeClipped version
+ https://bugs.webkit.org/show_bug.cgi?id=203550
+
+ Reviewed by Saam Barati.
+
+ We found that our Date constructor is slow because GregorianDateTime calculation takes so long.
+ We are doing many `fmod`, floating division, `floor` etc. These operations, in particular `fmod`, takes
+ very long time. As a result, 30% of JetStream2/date-format-xparb is taken by `fmod` function.
+
+ But since we are performance timeClip operation, double value in DateInstance is always Int52. We should
+ have integer version of GregorianDateTime calculation which avoids many unnecessary fmod etc.
+
+ While integer division is truncate-to-zero, many Date calculation requires `floor(value / xxx)`. For now,
+ we use integer fast path only when the value is Int52 and positive.
+
+ We see 10~ % improvement in JetStream2/date-format-xparb-SP (from 201 to 239).
+
+ * wtf/DateMath.cpp:
+ (WTF::isLeapYear): Deleted.
+ (WTF::daysInYear): Deleted.
+ (WTF::daysFrom1970ToYear): Deleted.
+ (WTF::msToDays): Deleted.
+ (WTF::msToYear): Deleted.
+ (WTF::dayInYear): Deleted.
+ (WTF::msToMinutes): Deleted.
+ (WTF::msToHours): Deleted.
+ (WTF::monthFromDayInYear): Deleted.
+ (WTF::checkMonth): Deleted.
+ (WTF::dayInMonthFromDayInYear): Deleted.
+ (WTF::dateToDaysFrom1970): Deleted.
+ (WTF::timeClip): Deleted.
+ * wtf/DateMath.h:
+ (WTF::TimeClippedPositiveMilliseconds::TimeClippedPositiveMilliseconds):
+ (WTF::TimeClippedPositiveMilliseconds::value const):
+ (WTF::TimeClippedPositiveMilliseconds::asDouble const):
+ (WTF::timeClip):
+ (WTF::daysFrom1970ToYear):
+ (WTF::daysFrom1970ToYearTimeClippedPositive):
+ (WTF::isLeapYear):
+ (WTF::daysInYear):
+ (WTF::msToDays):
+ (WTF::dayInYear):
+ (WTF::dateToDaysFrom1970):
+ (WTF::msToYear):
+ (WTF::msToMinutes):
+ (WTF::msToHours):
+ (WTF::msToSeconds):
+ (WTF::msToWeekDay):
+ (WTF::monthFromDayInYear):
+ (WTF::dayInMonthFromDayInYear):
+ * wtf/GregorianDateTime.cpp:
+ (WTF::GregorianDateTime::GregorianDateTime):
+ * wtf/GregorianDateTime.h:
+
2019-10-30 Alex Christensen <[email protected]>
Prevent Mac CMake build from bit rotting
Modified: trunk/Source/WTF/wtf/DateMath.cpp (251851 => 251852)
--- trunk/Source/WTF/wtf/DateMath.cpp 2019-10-31 16:01:25 UTC (rev 251851)
+++ trunk/Source/WTF/wtf/DateMath.cpp 2019-10-31 16:14:03 UTC (rev 251852)
@@ -109,15 +109,13 @@
/* Constants */
-static constexpr double maxUnixTime = 2145859200.0; // 12/31/2037
-// ECMAScript asks not to support for a date of which total
-// millisecond value is larger than the following value.
-// See 15.9.1.14 of ECMA-262 5th edition.
-static constexpr double maxECMAScriptTime = 8.64E15;
+const char* const weekdayName[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
+const char* const monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+const char* const monthFullName[12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
// Day of year for the first day of each month, where index 0 is January, and day 0 is January 1.
// First for non-leap years, then for leap years.
-static const int firstDayOfMonth[2][12] = {
+const int firstDayOfMonth[2][12] = {
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
};
@@ -133,46 +131,6 @@
}
#endif
-bool isLeapYear(int year)
-{
- if (year % 4 != 0)
- return false;
- if (year % 400 == 0)
- return true;
- if (year % 100 == 0)
- return false;
- return true;
-}
-
-static inline int daysInYear(int year)
-{
- return 365 + isLeapYear(year);
-}
-
-static inline double daysFrom1970ToYear(int year)
-{
- // The Gregorian Calendar rules for leap years:
- // Every fourth year is a leap year. 2004, 2008, and 2012 are leap years.
- // However, every hundredth year is not a leap year. 1900 and 2100 are not leap years.
- // Every four hundred years, there's a leap year after all. 2000 and 2400 are leap years.
-
- static constexpr int leapDaysBefore1971By4Rule = 1970 / 4;
- static constexpr int excludedLeapDaysBefore1971By100Rule = 1970 / 100;
- static constexpr int leapDaysBefore1971By400Rule = 1970 / 400;
-
- const double yearMinusOne = year - 1;
- const double yearsToAddBy4Rule = floor(yearMinusOne / 4.0) - leapDaysBefore1971By4Rule;
- const double yearsToExcludeBy100Rule = floor(yearMinusOne / 100.0) - excludedLeapDaysBefore1971By100Rule;
- const double yearsToAddBy400Rule = floor(yearMinusOne / 400.0) - leapDaysBefore1971By400Rule;
-
- return 365.0 * (year - 1970.0) + yearsToAddBy4Rule - yearsToExcludeBy100Rule + yearsToAddBy400Rule;
-}
-
-double msToDays(double ms)
-{
- return floor(ms / msPerDay);
-}
-
static void appendTwoDigitNumber(StringBuilder& builder, int number)
{
ASSERT(number >= 0);
@@ -181,22 +139,6 @@
builder.append(static_cast<LChar>('0' + number % 10));
}
-int msToYear(double ms)
-{
- int approxYear = static_cast<int>(floor(ms / (msPerDay * 365.2425)) + 1970);
- double msFromApproxYearTo1970 = msPerDay * daysFrom1970ToYear(approxYear);
- if (msFromApproxYearTo1970 > ms)
- return approxYear - 1;
- if (msFromApproxYearTo1970 + msPerDay * daysInYear(approxYear) <= ms)
- return approxYear + 1;
- return approxYear;
-}
-
-int dayInYear(double ms, int year)
-{
- return static_cast<int>(msToDays(ms) - daysFrom1970ToYear(year));
-}
-
static inline double msToMilliseconds(double ms)
{
double result = fmod(ms, msPerDay);
@@ -205,113 +147,6 @@
return result;
}
-int msToMinutes(double ms)
-{
- double result = fmod(floor(ms / msPerMinute), minutesPerHour);
- if (result < 0)
- result += minutesPerHour;
- return static_cast<int>(result);
-}
-
-int msToHours(double ms)
-{
- double result = fmod(floor(ms/msPerHour), hoursPerDay);
- if (result < 0)
- result += hoursPerDay;
- return static_cast<int>(result);
-}
-
-int monthFromDayInYear(int dayInYear, bool leapYear)
-{
- const int d = dayInYear;
- int step;
-
- if (d < (step = 31))
- return 0;
- step += (leapYear ? 29 : 28);
- if (d < step)
- return 1;
- if (d < (step += 31))
- return 2;
- if (d < (step += 30))
- return 3;
- if (d < (step += 31))
- return 4;
- if (d < (step += 30))
- return 5;
- if (d < (step += 31))
- return 6;
- if (d < (step += 31))
- return 7;
- if (d < (step += 30))
- return 8;
- if (d < (step += 31))
- return 9;
- if (d < (step += 30))
- return 10;
- return 11;
-}
-
-static inline bool checkMonth(int dayInYear, int& startDayOfThisMonth, int& startDayOfNextMonth, int daysInThisMonth)
-{
- startDayOfThisMonth = startDayOfNextMonth;
- startDayOfNextMonth += daysInThisMonth;
- return (dayInYear <= startDayOfNextMonth);
-}
-
-int dayInMonthFromDayInYear(int dayInYear, bool leapYear)
-{
- const int d = dayInYear;
- int step;
- int next = 30;
-
- if (d <= next)
- return d + 1;
- const int daysInFeb = (leapYear ? 29 : 28);
- if (checkMonth(d, step, next, daysInFeb))
- return d - step;
- if (checkMonth(d, step, next, 31))
- return d - step;
- if (checkMonth(d, step, next, 30))
- return d - step;
- if (checkMonth(d, step, next, 31))
- return d - step;
- if (checkMonth(d, step, next, 30))
- return d - step;
- if (checkMonth(d, step, next, 31))
- return d - step;
- if (checkMonth(d, step, next, 31))
- return d - step;
- if (checkMonth(d, step, next, 30))
- return d - step;
- if (checkMonth(d, step, next, 31))
- return d - step;
- if (checkMonth(d, step, next, 30))
- return d - step;
- step = next;
- return d - step;
-}
-
-int dayInYear(int year, int month, int day)
-{
- return firstDayOfMonth[isLeapYear(year)][month] + day - 1;
-}
-
-double dateToDaysFrom1970(int year, int month, int day)
-{
- year += month / 12;
-
- month %= 12;
- if (month < 0) {
- month += 12;
- --year;
- }
-
- double yearday = floor(daysFrom1970ToYear(year));
- ASSERT((year >= 1970 && yearday >= 0) || (year < 1970 && yearday < 0));
- return yearday + dayInYear(year, month, day);
-}
-
// There is a hard limit at 2038 that we currently do not have a workaround
// for (rdar://problem/5052975).
static inline int maximumYearForDST()
@@ -1159,13 +994,6 @@
return ms - (offset * msPerMinute);
}
-double timeClip(double t)
-{
- if (std::abs(t) > maxECMAScriptTime)
- return std::numeric_limits<double>::quiet_NaN();
- return std::trunc(t) + 0.0;
-}
-
// See http://tools.ietf.org/html/rfc2822#section-3.3 for more information.
String makeRFC2822DateString(unsigned dayOfWeek, unsigned day, unsigned month, unsigned year, unsigned hours, unsigned minutes, unsigned seconds, int utcOffset)
{
Modified: trunk/Source/WTF/wtf/DateMath.h (251851 => 251852)
--- trunk/Source/WTF/wtf/DateMath.h 2019-10-31 16:01:25 UTC (rev 251851)
+++ trunk/Source/WTF/wtf/DateMath.h 2019-10-31 16:14:03 UTC (rev 251852)
@@ -92,7 +92,6 @@
WTF_EXPORT_PRIVATE double parseES5DateFromNullTerminatedCharacters(const char* dateString);
WTF_EXPORT_PRIVATE double parseDateFromNullTerminatedCharacters(const char* dateString);
WTF_EXPORT_PRIVATE double parseDateFromNullTerminatedCharacters(const char* dateString, bool& haveTZ, int& offset);
-WTF_EXPORT_PRIVATE double timeClip(double);
// dayOfWeek: [0, 6] 0 being Monday, day: [1, 31], month: [0, 11], year: ex: 2011, hours: [0, 23], minutes: [0, 59], seconds: [0, 59], utcOffset: [-720,720].
String makeRFC2822DateString(unsigned dayOfWeek, unsigned day, unsigned month, unsigned year, unsigned hours, unsigned minutes, unsigned seconds, int utcOffset);
@@ -102,9 +101,10 @@
return floor(WallTime::now().secondsSinceEpoch().milliseconds());
}
-const char* const weekdayName[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
-const char* const monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-const char* const monthFullName[12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
+extern WTF_EXPORT_PRIVATE const char* const weekdayName[7];
+extern WTF_EXPORT_PRIVATE const char* const monthName[12];
+extern WTF_EXPORT_PRIVATE const char* const monthFullName[12];
+extern WTF_EXPORT_PRIVATE const int firstDayOfMonth[2][12];
static constexpr double hoursPerDay = 24.0;
static constexpr double minutesPerHour = 60.0;
@@ -117,19 +117,278 @@
static constexpr double msPerHour = msPerSecond * secondsPerHour;
static constexpr double msPerDay = msPerSecond * secondsPerDay;
-WTF_EXPORT_PRIVATE bool isLeapYear(int year);
+static constexpr double maxUnixTime = 2145859200.0; // 12/31/2037
+// ECMAScript asks not to support for a date of which total
+// millisecond value is larger than the following value.
+// See 15.9.1.14 of ECMA-262 5th edition.
+static constexpr double maxECMAScriptTime = 8.64E15;
+class TimeClippedPositiveMilliseconds {
+public:
+ static constexpr int64_t hoursPerDay = 24;
+ static constexpr int64_t minutesPerHour = 60;
+ static constexpr int64_t secondsPerMinute = 60;
+ static constexpr int64_t msPerSecond = 1000;
+ static constexpr int64_t msPerMonth = 2592000000;
+ static constexpr int64_t secondsPerHour = secondsPerMinute * minutesPerHour;
+ static constexpr int64_t secondsPerDay = secondsPerHour * hoursPerDay;
+ static constexpr int64_t msPerMinute = msPerSecond * secondsPerMinute;
+ static constexpr int64_t msPerHour = msPerSecond * secondsPerHour;
+ static constexpr int64_t msPerDay = msPerSecond * secondsPerDay;
+ static constexpr int64_t maxECMAScriptTime = 8.64E15;
+
+ explicit TimeClippedPositiveMilliseconds(int64_t value)
+ : m_value(value)
+ {
+ ASSERT(value >= 0);
+ }
+
+ int64_t value() const { return m_value; }
+ double asDouble() const { return static_cast<double>(m_value); }
+private:
+ int64_t m_value;
+};
+
+inline double timeClip(double t)
+{
+ if (std::abs(t) > maxECMAScriptTime)
+ return std::numeric_limits<double>::quiet_NaN();
+ return std::trunc(t) + 0.0;
+}
+
+inline double daysFrom1970ToYear(int year)
+{
+ // The Gregorian Calendar rules for leap years:
+ // Every fourth year is a leap year. 2004, 2008, and 2012 are leap years.
+ // However, every hundredth year is not a leap year. 1900 and 2100 are not leap years.
+ // Every four hundred years, there's a leap year after all. 2000 and 2400 are leap years.
+
+ static constexpr int leapDaysBefore1971By4Rule = 1970 / 4;
+ static constexpr int excludedLeapDaysBefore1971By100Rule = 1970 / 100;
+ static constexpr int leapDaysBefore1971By400Rule = 1970 / 400;
+
+ const double yearMinusOne = year - 1;
+ const double yearsToAddBy4Rule = floor(yearMinusOne / 4.0) - leapDaysBefore1971By4Rule;
+ const double yearsToExcludeBy100Rule = floor(yearMinusOne / 100.0) - excludedLeapDaysBefore1971By100Rule;
+ const double yearsToAddBy400Rule = floor(yearMinusOne / 400.0) - leapDaysBefore1971By400Rule;
+
+ return 365.0 * (year - 1970.0) + yearsToAddBy4Rule - yearsToExcludeBy100Rule + yearsToAddBy400Rule;
+}
+
+inline int64_t daysFrom1970ToYearTimeClippedPositive(int year)
+{
+ static constexpr int leapDaysBefore1971By4Rule = 1970 / 4;
+ static constexpr int excludedLeapDaysBefore1971By100Rule = 1970 / 100;
+ static constexpr int leapDaysBefore1971By400Rule = 1970 / 400;
+
+ ASSERT(year >= 1970);
+ const int64_t yearMinusOne = year - 1;
+ const int64_t yearsToAddBy4Rule = yearMinusOne / 4.0 - leapDaysBefore1971By4Rule;
+ const int64_t yearsToExcludeBy100Rule = yearMinusOne / 100.0 - excludedLeapDaysBefore1971By100Rule;
+ const int64_t yearsToAddBy400Rule = yearMinusOne / 400.0 - leapDaysBefore1971By400Rule;
+
+ return 365 * (year - 1970) + yearsToAddBy4Rule - yearsToExcludeBy100Rule + yearsToAddBy400Rule;
+}
+
+inline bool isLeapYear(int year)
+{
+ if (year % 4 != 0)
+ return false;
+ if (year % 400 == 0)
+ return true;
+ if (year % 100 == 0)
+ return false;
+ return true;
+}
+
+inline int daysInYear(int year)
+{
+ return 365 + isLeapYear(year);
+}
+
+inline double msToDays(double ms)
+{
+ return floor(ms / msPerDay);
+}
+
+inline int64_t msToDays(TimeClippedPositiveMilliseconds ms)
+{
+ return ms.value() / TimeClippedPositiveMilliseconds::msPerDay;
+}
+
+inline int dayInYear(int year, int month, int day)
+{
+ return firstDayOfMonth[isLeapYear(year)][month] + day - 1;
+}
+
+inline int dayInYear(double ms, int year)
+{
+ return static_cast<int>(msToDays(ms) - daysFrom1970ToYear(year));
+}
+
+inline int dayInYear(TimeClippedPositiveMilliseconds ms, int year)
+{
+ return static_cast<int>(msToDays(ms) - daysFrom1970ToYearTimeClippedPositive(year));
+}
+
// Returns the number of days from 1970-01-01 to the specified date.
-WTF_EXPORT_PRIVATE double dateToDaysFrom1970(int year, int month, int day);
-WTF_EXPORT_PRIVATE int msToYear(double ms);
-WTF_EXPORT_PRIVATE double msToDays(double ms);
-WTF_EXPORT_PRIVATE int msToMinutes(double ms);
-WTF_EXPORT_PRIVATE int msToHours(double ms);
-WTF_EXPORT_PRIVATE int dayInYear(int year, int month, int day);
-WTF_EXPORT_PRIVATE int dayInYear(double ms, int year);
-WTF_EXPORT_PRIVATE int monthFromDayInYear(int dayInYear, bool leapYear);
-WTF_EXPORT_PRIVATE int dayInMonthFromDayInYear(int dayInYear, bool leapYear);
+inline double dateToDaysFrom1970(int year, int month, int day)
+{
+ year += month / 12;
+ month %= 12;
+ if (month < 0) {
+ month += 12;
+ --year;
+ }
+
+ double yearday = floor(daysFrom1970ToYear(year));
+ ASSERT((year >= 1970 && yearday >= 0) || (year < 1970 && yearday < 0));
+ return yearday + dayInYear(year, month, day);
+}
+
+inline int msToYear(double ms)
+{
+ int approxYear = static_cast<int>(floor(ms / (msPerDay * 365.2425)) + 1970);
+ double msFromApproxYearTo1970 = msPerDay * daysFrom1970ToYear(approxYear);
+ if (msFromApproxYearTo1970 > ms)
+ return approxYear - 1;
+ if (msFromApproxYearTo1970 + msPerDay * daysInYear(approxYear) <= ms)
+ return approxYear + 1;
+ return approxYear;
+}
+
+inline int msToMinutes(double ms)
+{
+ double result = fmod(floor(ms / msPerMinute), minutesPerHour);
+ if (result < 0)
+ result += minutesPerHour;
+ return static_cast<int>(result);
+}
+
+inline int msToMinutes(TimeClippedPositiveMilliseconds ms)
+{
+ int64_t result = (ms.value() / TimeClippedPositiveMilliseconds::msPerMinute) % TimeClippedPositiveMilliseconds::minutesPerHour;
+ ASSERT(result >= 0);
+ return static_cast<int>(result);
+}
+
+inline int msToHours(double ms)
+{
+ double result = fmod(floor(ms / msPerHour), hoursPerDay);
+ if (result < 0)
+ result += hoursPerDay;
+ return static_cast<int>(result);
+}
+
+inline int msToHours(TimeClippedPositiveMilliseconds ms)
+{
+ int64_t result = (ms.value() / TimeClippedPositiveMilliseconds::msPerHour) % TimeClippedPositiveMilliseconds::hoursPerDay;
+ ASSERT(result >= 0);
+ return static_cast<int>(result);
+}
+
+inline int msToSeconds(double ms)
+{
+ double result = fmod(floor(ms / msPerSecond), secondsPerMinute);
+ if (result < 0)
+ result += secondsPerMinute;
+ return static_cast<int>(result);
+}
+
+inline int msToSeconds(TimeClippedPositiveMilliseconds ms)
+{
+ int64_t result = ms.value() / TimeClippedPositiveMilliseconds::msPerSecond % TimeClippedPositiveMilliseconds::secondsPerMinute;
+ ASSERT(result >= 0);
+ return static_cast<int>(result);
+}
+
+// 0: Sunday, 1: Monday, etc.
+inline int msToWeekDay(double ms)
+{
+ int wd = (static_cast<int>(msToDays(ms)) + 4) % 7;
+ if (wd < 0)
+ wd += 7;
+ return wd;
+}
+
+inline int msToWeekDay(TimeClippedPositiveMilliseconds ms)
+{
+ int result = (static_cast<int>(msToDays(ms)) + 4) % 7;
+ ASSERT(result >= 0);
+ return result;
+}
+
+inline int monthFromDayInYear(int dayInYear, bool leapYear)
+{
+ const int d = dayInYear;
+ int step;
+
+ if (d < (step = 31))
+ return 0;
+ step += (leapYear ? 29 : 28);
+ if (d < step)
+ return 1;
+ if (d < (step += 31))
+ return 2;
+ if (d < (step += 30))
+ return 3;
+ if (d < (step += 31))
+ return 4;
+ if (d < (step += 30))
+ return 5;
+ if (d < (step += 31))
+ return 6;
+ if (d < (step += 31))
+ return 7;
+ if (d < (step += 30))
+ return 8;
+ if (d < (step += 31))
+ return 9;
+ if (d < (step += 30))
+ return 10;
+ return 11;
+}
+
+inline int dayInMonthFromDayInYear(int dayInYear, bool leapYear)
+{
+ auto checkMonth = [] (int dayInYear, int& startDayOfThisMonth, int& startDayOfNextMonth, int daysInThisMonth) -> bool {
+ startDayOfThisMonth = startDayOfNextMonth;
+ startDayOfNextMonth += daysInThisMonth;
+ return (dayInYear <= startDayOfNextMonth);
+ };
+
+ const int d = dayInYear;
+ int step;
+ int next = 30;
+
+ if (d <= next)
+ return d + 1;
+ const int daysInFeb = (leapYear ? 29 : 28);
+ if (checkMonth(d, step, next, daysInFeb))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 30))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 30))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 30))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 30))
+ return d - step;
+ step = next;
+ return d - step;
+}
+
// Returns combined offset in millisecond (UTC + DST).
WTF_EXPORT_PRIVATE LocalTimeOffset calculateLocalTimeOffset(double utcInMilliseconds, TimeType = UTCTime);
@@ -155,3 +414,5 @@
using WTF::makeRFC2822DateString;
using WTF::LocalTimeOffset;
using WTF::calculateLocalTimeOffset;
+using WTF::timeClip;
+using WTF::jsCurrentTime;
Modified: trunk/Source/WTF/wtf/GregorianDateTime.cpp (251851 => 251852)
--- trunk/Source/WTF/wtf/GregorianDateTime.cpp 2019-10-31 16:01:25 UTC (rev 251851)
+++ trunk/Source/WTF/wtf/GregorianDateTime.cpp 2019-10-31 16:14:03 UTC (rev 251852)
@@ -35,6 +35,53 @@
namespace WTF {
+GregorianDateTime::GregorianDateTime(double ms, LocalTimeOffset localTime)
+{
+ if (ms >= 0
+#if OS(WINDOWS) && CPU(X86)
+ // The VS Compiler for 32-bit builds generates a floating point error when attempting to cast
+ // from an infinity to a 64-bit integer. We leave this routine with the floating point error
+ // left in a register, causing undefined behavior in later floating point operations.
+ //
+ // To avoid this issue, we check for infinity here, and return false in that case.
+ && !std::isinf(ms)
+#endif
+ ) {
+ int64_t integer = static_cast<int64_t>(ms);
+ if (static_cast<double>(integer) == ms && integer <= maxECMAScriptTime) {
+ // Positive integer fast path.
+ WTF::TimeClippedPositiveMilliseconds timeClipped(integer);
+ const int year = msToYear(ms);
+ setSecond(msToSeconds(timeClipped));
+ setMinute(msToMinutes(timeClipped));
+ setHour(msToHours(timeClipped));
+ setWeekDay(msToWeekDay(timeClipped));
+ int yearDay = dayInYear(timeClipped, year);
+ bool leapYear = isLeapYear(year);
+ setYearDay(yearDay);
+ setMonthDay(dayInMonthFromDayInYear(yearDay, leapYear));
+ setMonth(monthFromDayInYear(yearDay, leapYear));
+ setYear(year);
+ setIsDST(localTime.isDST);
+ setUTCOffsetInMinute(localTime.offset / WTF::msPerMinute);
+ return;
+ }
+ }
+ const int year = msToYear(ms);
+ setSecond(msToSeconds(ms));
+ setMinute(msToMinutes(ms));
+ setHour(msToHours(ms));
+ setWeekDay(msToWeekDay(ms));
+ int yearDay = dayInYear(ms, year);
+ bool leapYear = isLeapYear(year);
+ setYearDay(yearDay);
+ setMonthDay(dayInMonthFromDayInYear(yearDay, leapYear));
+ setMonth(monthFromDayInYear(yearDay, leapYear));
+ setYear(year);
+ setIsDST(localTime.isDST);
+ setUTCOffsetInMinute(localTime.offset / WTF::msPerMinute);
+}
+
void GregorianDateTime::setToCurrentLocalTime()
{
#if OS(WINDOWS)
Modified: trunk/Source/WTF/wtf/GregorianDateTime.h (251851 => 251852)
--- trunk/Source/WTF/wtf/GregorianDateTime.h 2019-10-31 16:01:25 UTC (rev 251851)
+++ trunk/Source/WTF/wtf/GregorianDateTime.h 2019-10-31 16:14:03 UTC (rev 251852)
@@ -36,6 +36,7 @@
WTF_MAKE_FAST_ALLOCATED;
public:
GregorianDateTime() = default;
+ WTF_EXPORT_PRIVATE explicit GregorianDateTime(double ms, LocalTimeOffset);
inline int year() const { return m_year; }
inline int month() const { return m_month; }