Changeset 251852 in webkit


Ignore:
Timestamp:
Oct 31, 2019 9:14:03 AM (5 years ago)
Author:
ysuzuki@apple.com
Message:

[JSC] DateMath should have TimeClipped version
https://bugs.webkit.org/show_bug.cgi?id=203550

Reviewed by Saam Barati.

Source/JavaScriptCore:

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.

Source/WTF:

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:
Location:
trunk/Source
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r251834 r251852  
     12019-10-31  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] DateMath should have TimeClipped version
     4        https://bugs.webkit.org/show_bug.cgi?id=203550
     5
     6        Reviewed by Saam Barati.
     7
     8        Removing `using namespace WTF;` in Date related files in JSC.
     9
     10        * runtime/DateConstructor.cpp:
     11        * runtime/DateConversion.cpp:
     12        (JSC::formatDateTime):
     13        * runtime/DateInstance.cpp:
     14        * runtime/DatePrototype.cpp:
     15        * runtime/JSDateMath.cpp:
     16        (JSC::localTimeOffset):
     17        (JSC::timeToMS):
     18        (JSC::gregorianDateTimeToMS):
     19        (JSC::msToGregorianDateTime):
     20        (JSC::parseDate):
     21        (JSC::msToSeconds): Deleted.
     22        (JSC::msToWeekDay): Deleted.
     23
    1242019-10-30  Peng Liu  <peng.liu6@apple.com>
    225
  • trunk/Source/JavaScriptCore/runtime/DateConstructor.cpp

    r251425 r251852  
    5555
    5656namespace JSC {
    57 
    58 using namespace WTF;
    5957
    6058const ClassInfo DateConstructor::s_info = { "Function", &InternalFunction::s_info, &dateConstructorTable, nullptr, CREATE_METHOD_TABLE(DateConstructor) };
  • trunk/Source/JavaScriptCore/runtime/DateConversion.cpp

    r251826 r251852  
    3737namespace JSC {
    3838
    39 using namespace WTF;
    40 
    4139template<int width>
    4240static inline void appendNumber(StringBuilder& builder, int value)
     
    6967
    7068    if (appendDate) {
    71         builder.append(weekdayName[(t.weekDay() + 6) % 7]);
     69        builder.append(WTF::weekdayName[(t.weekDay() + 6) % 7]);
    7270
    7371        if (asUTCVariant) {
     
    7573            appendNumber<2>(builder, t.monthDay());
    7674            builder.append(' ');
    77             builder.append(monthName[t.month()]);
     75            builder.append(WTF::monthName[t.month()]);
    7876        } else {
    7977            builder.append(' ');
    80             builder.append(monthName[t.month()]);
     78            builder.append(WTF::monthName[t.month()]);
    8179            builder.append(' ');
    8280            appendNumber<2>(builder, t.monthDay());
  • trunk/Source/JavaScriptCore/runtime/DateInstance.cpp

    r251826 r251852  
    3030
    3131namespace JSC {
    32 
    33 using namespace WTF;
    3432
    3533const ClassInfo DateInstance::s_info = {"Date", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DateInstance)};
  • trunk/Source/JavaScriptCore/runtime/DatePrototype.cpp

    r251826 r251852  
    6969
    7070namespace JSC {
    71 
    72 using namespace WTF;
    7371
    7472EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(JSGlobalObject*, CallFrame*);
  • trunk/Source/JavaScriptCore/runtime/JSDateMath.cpp

    r251826 r251852  
    101101namespace JSC {
    102102
    103 using namespace WTF;
    104 
    105 static inline double timeToMS(double hour, double min, double sec, double ms)
    106 {
    107     return (((hour * minutesPerHour + min) * secondsPerMinute + sec) * msPerSecond + ms);
    108 }
    109 
    110 static inline int msToSeconds(double ms)
    111 {
    112     double result = fmod(floor(ms / msPerSecond), secondsPerMinute);
    113     if (result < 0)
    114         result += secondsPerMinute;
    115     return static_cast<int>(result);
    116 }
    117 
    118 // 0: Sunday, 1: Monday, etc.
    119 static inline int msToWeekDay(double ms)
    120 {
    121     int wd = (static_cast<int>(msToDays(ms)) + 4) % 7;
    122     if (wd < 0)
    123         wd += 7;
    124     return wd;
    125 }
    126 
    127103// Get the combined UTC + DST offset for the time passed in.
    128104//
     
    153129                // and return the offset.
    154130                cache.end = newEnd;
    155                 cache.increment = msPerMonth;
     131                cache.increment = WTF::msPerMonth;
    156132                return endOffset;
    157133            }
     
    164140                cache.start = ms;
    165141                cache.end = newEnd;
    166                 cache.increment = msPerMonth;
     142                cache.increment = WTF::msPerMonth;
    167143            } else {
    168144                // The interval contains a DST offset change and the given time is
     
    185161    cache.start = ms;
    186162    cache.end = ms;
    187     cache.increment = msPerMonth;
     163    cache.increment = WTF::msPerMonth;
    188164    return offset;
     165}
     166
     167static inline double timeToMS(double hour, double min, double sec, double ms)
     168{
     169    return (((hour * WTF::minutesPerHour + min) * WTF::secondsPerMinute + sec) * WTF::msPerSecond + ms);
    189170}
    190171
     
    195176    double localTimeResult = (day * WTF::msPerDay) + ms;
    196177
    197     double localToUTCTimeOffset = inputTimeType == LocalTime
     178    double localToUTCTimeOffset = inputTimeType == WTF::LocalTime
    198179        ? localTimeOffset(vm, localTimeResult, inputTimeType).offset : 0;
    199180
     
    209190        ms += localTime.offset;
    210191    }
    211 
    212     const int year = msToYear(ms);
    213     tm.setSecond(msToSeconds(ms));
    214     tm.setMinute(msToMinutes(ms));
    215     tm.setHour(msToHours(ms));
    216     tm.setWeekDay(msToWeekDay(ms));
    217     tm.setYearDay(dayInYear(ms, year));
    218     tm.setMonthDay(dayInMonthFromDayInYear(tm.yearDay(), isLeapYear(year)));
    219     tm.setMonth(monthFromDayInYear(tm.yearDay(), isLeapYear(year)));
    220     tm.setYear(year);
    221     tm.setIsDST(localTime.isDST);
    222     tm.setUTCOffsetInMinute(localTime.offset / WTF::msPerMinute);
     192    tm = GregorianDateTime(ms, localTime);
    223193}
    224194
     
    255225
    256226    auto dateUtf8 = expectedString.value();
    257     double value = parseES5DateFromNullTerminatedCharacters(dateUtf8.data());
     227    double value = WTF::parseES5DateFromNullTerminatedCharacters(dateUtf8.data());
    258228    if (std::isnan(value))
    259229        value = parseDateFromNullTerminatedCharacters(vm, dateUtf8.data());
  • trunk/Source/WTF/ChangeLog

    r251831 r251852  
     12019-10-31  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] DateMath should have TimeClipped version
     4        https://bugs.webkit.org/show_bug.cgi?id=203550
     5
     6        Reviewed by Saam Barati.
     7
     8        We found that our Date constructor is slow because GregorianDateTime calculation takes so long.
     9        We are doing many `fmod`, floating division, `floor` etc. These operations, in particular `fmod`, takes
     10        very long time. As a result, 30% of JetStream2/date-format-xparb is taken by `fmod` function.
     11
     12        But since we are performance timeClip operation, double value in DateInstance is always Int52. We should
     13        have integer version of GregorianDateTime calculation which avoids many unnecessary fmod etc.
     14
     15        While integer division is truncate-to-zero, many Date calculation requires `floor(value / xxx)`. For now,
     16        we use integer fast path only when the value is Int52 and positive.
     17
     18        We see 10~ % improvement in JetStream2/date-format-xparb-SP (from 201 to 239).
     19
     20        * wtf/DateMath.cpp:
     21        (WTF::isLeapYear): Deleted.
     22        (WTF::daysInYear): Deleted.
     23        (WTF::daysFrom1970ToYear): Deleted.
     24        (WTF::msToDays): Deleted.
     25        (WTF::msToYear): Deleted.
     26        (WTF::dayInYear): Deleted.
     27        (WTF::msToMinutes): Deleted.
     28        (WTF::msToHours): Deleted.
     29        (WTF::monthFromDayInYear): Deleted.
     30        (WTF::checkMonth): Deleted.
     31        (WTF::dayInMonthFromDayInYear): Deleted.
     32        (WTF::dateToDaysFrom1970): Deleted.
     33        (WTF::timeClip): Deleted.
     34        * wtf/DateMath.h:
     35        (WTF::TimeClippedPositiveMilliseconds::TimeClippedPositiveMilliseconds):
     36        (WTF::TimeClippedPositiveMilliseconds::value const):
     37        (WTF::TimeClippedPositiveMilliseconds::asDouble const):
     38        (WTF::timeClip):
     39        (WTF::daysFrom1970ToYear):
     40        (WTF::daysFrom1970ToYearTimeClippedPositive):
     41        (WTF::isLeapYear):
     42        (WTF::daysInYear):
     43        (WTF::msToDays):
     44        (WTF::dayInYear):
     45        (WTF::dateToDaysFrom1970):
     46        (WTF::msToYear):
     47        (WTF::msToMinutes):
     48        (WTF::msToHours):
     49        (WTF::msToSeconds):
     50        (WTF::msToWeekDay):
     51        (WTF::monthFromDayInYear):
     52        (WTF::dayInMonthFromDayInYear):
     53        * wtf/GregorianDateTime.cpp:
     54        (WTF::GregorianDateTime::GregorianDateTime):
     55        * wtf/GregorianDateTime.h:
     56
    1572019-10-30  Alex Christensen  <achristensen@webkit.org>
    258
  • trunk/Source/WTF/wtf/DateMath.cpp

    r250005 r251852  
    110110/* Constants */
    111111
    112 static constexpr double maxUnixTime = 2145859200.0; // 12/31/2037
    113 // ECMAScript asks not to support for a date of which total
    114 // millisecond value is larger than the following value.
    115 // See 15.9.1.14 of ECMA-262 5th edition.
    116 static constexpr double maxECMAScriptTime = 8.64E15;
     112const char* const weekdayName[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
     113const char* const monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
     114const char* const monthFullName[12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
    117115
    118116// Day of year for the first day of each month, where index 0 is January, and day 0 is January 1.
    119117// First for non-leap years, then for leap years.
    120 static const int firstDayOfMonth[2][12] = {
     118const int firstDayOfMonth[2][12] = {
    121119    {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
    122120    {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
     
    134132#endif
    135133
    136 bool isLeapYear(int year)
    137 {
    138     if (year % 4 != 0)
    139         return false;
    140     if (year % 400 == 0)
    141         return true;
    142     if (year % 100 == 0)
    143         return false;
    144     return true;
    145 }
    146 
    147 static inline int daysInYear(int year)
    148 {
    149     return 365 + isLeapYear(year);
    150 }
    151 
    152 static inline double daysFrom1970ToYear(int year)
    153 {
    154     // The Gregorian Calendar rules for leap years:
    155     // Every fourth year is a leap year.  2004, 2008, and 2012 are leap years.
    156     // However, every hundredth year is not a leap year.  1900 and 2100 are not leap years.
    157     // Every four hundred years, there's a leap year after all.  2000 and 2400 are leap years.
    158 
    159     static constexpr int leapDaysBefore1971By4Rule = 1970 / 4;
    160     static constexpr int excludedLeapDaysBefore1971By100Rule = 1970 / 100;
    161     static constexpr int leapDaysBefore1971By400Rule = 1970 / 400;
    162 
    163     const double yearMinusOne = year - 1;
    164     const double yearsToAddBy4Rule = floor(yearMinusOne / 4.0) - leapDaysBefore1971By4Rule;
    165     const double yearsToExcludeBy100Rule = floor(yearMinusOne / 100.0) - excludedLeapDaysBefore1971By100Rule;
    166     const double yearsToAddBy400Rule = floor(yearMinusOne / 400.0) - leapDaysBefore1971By400Rule;
    167 
    168     return 365.0 * (year - 1970.0) + yearsToAddBy4Rule - yearsToExcludeBy100Rule + yearsToAddBy400Rule;
    169 }
    170 
    171 double msToDays(double ms)
    172 {
    173     return floor(ms / msPerDay);
    174 }
    175 
    176134static void appendTwoDigitNumber(StringBuilder& builder, int number)
    177135{
     
    182140}
    183141
    184 int msToYear(double ms)
    185 {
    186     int approxYear = static_cast<int>(floor(ms / (msPerDay * 365.2425)) + 1970);
    187     double msFromApproxYearTo1970 = msPerDay * daysFrom1970ToYear(approxYear);
    188     if (msFromApproxYearTo1970 > ms)
    189         return approxYear - 1;
    190     if (msFromApproxYearTo1970 + msPerDay * daysInYear(approxYear) <= ms)
    191         return approxYear + 1;
    192     return approxYear;
    193 }
    194 
    195 int dayInYear(double ms, int year)
    196 {
    197     return static_cast<int>(msToDays(ms) - daysFrom1970ToYear(year));
    198 }
    199 
    200142static inline double msToMilliseconds(double ms)
    201143{
     
    204146        result += msPerDay;
    205147    return result;
    206 }
    207 
    208 int msToMinutes(double ms)
    209 {
    210     double result = fmod(floor(ms / msPerMinute), minutesPerHour);
    211     if (result < 0)
    212         result += minutesPerHour;
    213     return static_cast<int>(result);
    214 }
    215 
    216 int msToHours(double ms)
    217 {
    218     double result = fmod(floor(ms/msPerHour), hoursPerDay);
    219     if (result < 0)
    220         result += hoursPerDay;
    221     return static_cast<int>(result);
    222 }
    223 
    224 int monthFromDayInYear(int dayInYear, bool leapYear)
    225 {
    226     const int d = dayInYear;
    227     int step;
    228 
    229     if (d < (step = 31))
    230         return 0;
    231     step += (leapYear ? 29 : 28);
    232     if (d < step)
    233         return 1;
    234     if (d < (step += 31))
    235         return 2;
    236     if (d < (step += 30))
    237         return 3;
    238     if (d < (step += 31))
    239         return 4;
    240     if (d < (step += 30))
    241         return 5;
    242     if (d < (step += 31))
    243         return 6;
    244     if (d < (step += 31))
    245         return 7;
    246     if (d < (step += 30))
    247         return 8;
    248     if (d < (step += 31))
    249         return 9;
    250     if (d < (step += 30))
    251         return 10;
    252     return 11;
    253 }
    254 
    255 static inline bool checkMonth(int dayInYear, int& startDayOfThisMonth, int& startDayOfNextMonth, int daysInThisMonth)
    256 {
    257     startDayOfThisMonth = startDayOfNextMonth;
    258     startDayOfNextMonth += daysInThisMonth;
    259     return (dayInYear <= startDayOfNextMonth);
    260 }
    261 
    262 int dayInMonthFromDayInYear(int dayInYear, bool leapYear)
    263 {
    264     const int d = dayInYear;
    265     int step;
    266     int next = 30;
    267 
    268     if (d <= next)
    269         return d + 1;
    270     const int daysInFeb = (leapYear ? 29 : 28);
    271     if (checkMonth(d, step, next, daysInFeb))
    272         return d - step;
    273     if (checkMonth(d, step, next, 31))
    274         return d - step;
    275     if (checkMonth(d, step, next, 30))
    276         return d - step;
    277     if (checkMonth(d, step, next, 31))
    278         return d - step;
    279     if (checkMonth(d, step, next, 30))
    280         return d - step;
    281     if (checkMonth(d, step, next, 31))
    282         return d - step;
    283     if (checkMonth(d, step, next, 31))
    284         return d - step;
    285     if (checkMonth(d, step, next, 30))
    286         return d - step;
    287     if (checkMonth(d, step, next, 31))
    288         return d - step;
    289     if (checkMonth(d, step, next, 30))
    290         return d - step;
    291     step = next;
    292     return d - step;
    293 }
    294 
    295 int dayInYear(int year, int month, int day)
    296 {
    297     return firstDayOfMonth[isLeapYear(year)][month] + day - 1;
    298 }
    299 
    300 double dateToDaysFrom1970(int year, int month, int day)
    301 {
    302     year += month / 12;
    303 
    304     month %= 12;
    305     if (month < 0) {
    306         month += 12;
    307         --year;
    308     }
    309 
    310     double yearday = floor(daysFrom1970ToYear(year));
    311     ASSERT((year >= 1970 && yearday >= 0) || (year < 1970 && yearday < 0));
    312     return yearday + dayInYear(year, month, day);
    313148}
    314149
     
    1160995}
    1161996
    1162 double timeClip(double t)
    1163 {
    1164     if (std::abs(t) > maxECMAScriptTime)
    1165         return std::numeric_limits<double>::quiet_NaN();
    1166     return std::trunc(t) + 0.0;
    1167 }
    1168 
    1169997// See http://tools.ietf.org/html/rfc2822#section-3.3 for more information.
    1170998String makeRFC2822DateString(unsigned dayOfWeek, unsigned day, unsigned month, unsigned year, unsigned hours, unsigned minutes, unsigned seconds, int utcOffset)
  • trunk/Source/WTF/wtf/DateMath.h

    r251826 r251852  
    9393WTF_EXPORT_PRIVATE double parseDateFromNullTerminatedCharacters(const char* dateString);
    9494WTF_EXPORT_PRIVATE double parseDateFromNullTerminatedCharacters(const char* dateString, bool& haveTZ, int& offset);
    95 WTF_EXPORT_PRIVATE double timeClip(double);
    9695// 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].
    9796String makeRFC2822DateString(unsigned dayOfWeek, unsigned day, unsigned month, unsigned year, unsigned hours, unsigned minutes, unsigned seconds, int utcOffset);
     
    103102}
    104103
    105 const char* const weekdayName[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
    106 const char* const monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
    107 const char* const monthFullName[12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
     104extern WTF_EXPORT_PRIVATE const char* const weekdayName[7];
     105extern WTF_EXPORT_PRIVATE const char* const monthName[12];
     106extern WTF_EXPORT_PRIVATE const char* const monthFullName[12];
     107extern WTF_EXPORT_PRIVATE const int firstDayOfMonth[2][12];
    108108
    109109static constexpr double hoursPerDay = 24.0;
     
    118118static constexpr double msPerDay = msPerSecond * secondsPerDay;
    119119
    120 WTF_EXPORT_PRIVATE bool isLeapYear(int year);
     120static constexpr double maxUnixTime = 2145859200.0; // 12/31/2037
     121// ECMAScript asks not to support for a date of which total
     122// millisecond value is larger than the following value.
     123// See 15.9.1.14 of ECMA-262 5th edition.
     124static constexpr double maxECMAScriptTime = 8.64E15;
     125
     126class TimeClippedPositiveMilliseconds {
     127public:
     128    static constexpr int64_t hoursPerDay = 24;
     129    static constexpr int64_t minutesPerHour = 60;
     130    static constexpr int64_t secondsPerMinute = 60;
     131    static constexpr int64_t msPerSecond = 1000;
     132    static constexpr int64_t msPerMonth = 2592000000;
     133    static constexpr int64_t secondsPerHour = secondsPerMinute * minutesPerHour;
     134    static constexpr int64_t secondsPerDay = secondsPerHour * hoursPerDay;
     135    static constexpr int64_t msPerMinute = msPerSecond * secondsPerMinute;
     136    static constexpr int64_t msPerHour = msPerSecond * secondsPerHour;
     137    static constexpr int64_t msPerDay = msPerSecond * secondsPerDay;
     138    static constexpr int64_t maxECMAScriptTime = 8.64E15;
     139
     140    explicit TimeClippedPositiveMilliseconds(int64_t value)
     141        : m_value(value)
     142    {
     143        ASSERT(value >= 0);
     144    }
     145
     146    int64_t value() const { return m_value; }
     147    double asDouble() const { return static_cast<double>(m_value); }
     148private:
     149    int64_t m_value;
     150};
     151
     152inline double timeClip(double t)
     153{
     154    if (std::abs(t) > maxECMAScriptTime)
     155        return std::numeric_limits<double>::quiet_NaN();
     156    return std::trunc(t) + 0.0;
     157}
     158
     159inline double daysFrom1970ToYear(int year)
     160{
     161    // The Gregorian Calendar rules for leap years:
     162    // Every fourth year is a leap year. 2004, 2008, and 2012 are leap years.
     163    // However, every hundredth year is not a leap year. 1900 and 2100 are not leap years.
     164    // Every four hundred years, there's a leap year after all. 2000 and 2400 are leap years.
     165
     166    static constexpr int leapDaysBefore1971By4Rule = 1970 / 4;
     167    static constexpr int excludedLeapDaysBefore1971By100Rule = 1970 / 100;
     168    static constexpr int leapDaysBefore1971By400Rule = 1970 / 400;
     169
     170    const double yearMinusOne = year - 1;
     171    const double yearsToAddBy4Rule = floor(yearMinusOne / 4.0) - leapDaysBefore1971By4Rule;
     172    const double yearsToExcludeBy100Rule = floor(yearMinusOne / 100.0) - excludedLeapDaysBefore1971By100Rule;
     173    const double yearsToAddBy400Rule = floor(yearMinusOne / 400.0) - leapDaysBefore1971By400Rule;
     174
     175    return 365.0 * (year - 1970.0) + yearsToAddBy4Rule - yearsToExcludeBy100Rule + yearsToAddBy400Rule;
     176}
     177
     178inline int64_t daysFrom1970ToYearTimeClippedPositive(int year)
     179{
     180    static constexpr int leapDaysBefore1971By4Rule = 1970 / 4;
     181    static constexpr int excludedLeapDaysBefore1971By100Rule = 1970 / 100;
     182    static constexpr int leapDaysBefore1971By400Rule = 1970 / 400;
     183
     184    ASSERT(year >= 1970);
     185    const int64_t yearMinusOne = year - 1;
     186    const int64_t yearsToAddBy4Rule = yearMinusOne / 4.0 - leapDaysBefore1971By4Rule;
     187    const int64_t yearsToExcludeBy100Rule = yearMinusOne / 100.0 - excludedLeapDaysBefore1971By100Rule;
     188    const int64_t yearsToAddBy400Rule = yearMinusOne / 400.0 - leapDaysBefore1971By400Rule;
     189
     190    return 365 * (year - 1970) + yearsToAddBy4Rule - yearsToExcludeBy100Rule + yearsToAddBy400Rule;
     191}
     192
     193inline bool isLeapYear(int year)
     194{
     195    if (year % 4 != 0)
     196        return false;
     197    if (year % 400 == 0)
     198        return true;
     199    if (year % 100 == 0)
     200        return false;
     201    return true;
     202}
     203
     204inline int daysInYear(int year)
     205{
     206    return 365 + isLeapYear(year);
     207}
     208
     209inline double msToDays(double ms)
     210{
     211    return floor(ms / msPerDay);
     212}
     213
     214inline int64_t msToDays(TimeClippedPositiveMilliseconds ms)
     215{
     216    return ms.value() / TimeClippedPositiveMilliseconds::msPerDay;
     217}
     218
     219inline int dayInYear(int year, int month, int day)
     220{
     221    return firstDayOfMonth[isLeapYear(year)][month] + day - 1;
     222}
     223
     224inline int dayInYear(double ms, int year)
     225{
     226    return static_cast<int>(msToDays(ms) - daysFrom1970ToYear(year));
     227}
     228
     229inline int dayInYear(TimeClippedPositiveMilliseconds ms, int year)
     230{
     231    return static_cast<int>(msToDays(ms) - daysFrom1970ToYearTimeClippedPositive(year));
     232}
    121233
    122234// Returns the number of days from 1970-01-01 to the specified date.
    123 WTF_EXPORT_PRIVATE double dateToDaysFrom1970(int year, int month, int day);
    124 WTF_EXPORT_PRIVATE int msToYear(double ms);
    125 WTF_EXPORT_PRIVATE double msToDays(double ms);
    126 WTF_EXPORT_PRIVATE int msToMinutes(double ms);
    127 WTF_EXPORT_PRIVATE int msToHours(double ms);
    128 WTF_EXPORT_PRIVATE int dayInYear(int year, int month, int day);
    129 WTF_EXPORT_PRIVATE int dayInYear(double ms, int year);
    130 WTF_EXPORT_PRIVATE int monthFromDayInYear(int dayInYear, bool leapYear);
    131 WTF_EXPORT_PRIVATE int dayInMonthFromDayInYear(int dayInYear, bool leapYear);
     235inline double dateToDaysFrom1970(int year, int month, int day)
     236{
     237    year += month / 12;
     238
     239    month %= 12;
     240    if (month < 0) {
     241        month += 12;
     242        --year;
     243    }
     244
     245    double yearday = floor(daysFrom1970ToYear(year));
     246    ASSERT((year >= 1970 && yearday >= 0) || (year < 1970 && yearday < 0));
     247    return yearday + dayInYear(year, month, day);
     248}
     249
     250inline int msToYear(double ms)
     251{
     252    int approxYear = static_cast<int>(floor(ms / (msPerDay * 365.2425)) + 1970);
     253    double msFromApproxYearTo1970 = msPerDay * daysFrom1970ToYear(approxYear);
     254    if (msFromApproxYearTo1970 > ms)
     255        return approxYear - 1;
     256    if (msFromApproxYearTo1970 + msPerDay * daysInYear(approxYear) <= ms)
     257        return approxYear + 1;
     258    return approxYear;
     259}
     260
     261inline int msToMinutes(double ms)
     262{
     263    double result = fmod(floor(ms / msPerMinute), minutesPerHour);
     264    if (result < 0)
     265        result += minutesPerHour;
     266    return static_cast<int>(result);
     267}
     268
     269inline int msToMinutes(TimeClippedPositiveMilliseconds ms)
     270{
     271    int64_t result = (ms.value() / TimeClippedPositiveMilliseconds::msPerMinute) % TimeClippedPositiveMilliseconds::minutesPerHour;
     272    ASSERT(result >= 0);
     273    return static_cast<int>(result);
     274}
     275
     276inline int msToHours(double ms)
     277{
     278    double result = fmod(floor(ms / msPerHour), hoursPerDay);
     279    if (result < 0)
     280        result += hoursPerDay;
     281    return static_cast<int>(result);
     282}
     283
     284inline int msToHours(TimeClippedPositiveMilliseconds ms)
     285{
     286    int64_t result = (ms.value() / TimeClippedPositiveMilliseconds::msPerHour) % TimeClippedPositiveMilliseconds::hoursPerDay;
     287    ASSERT(result >= 0);
     288    return static_cast<int>(result);
     289}
     290
     291inline int msToSeconds(double ms)
     292{
     293    double result = fmod(floor(ms / msPerSecond), secondsPerMinute);
     294    if (result < 0)
     295        result += secondsPerMinute;
     296    return static_cast<int>(result);
     297}
     298
     299inline int msToSeconds(TimeClippedPositiveMilliseconds ms)
     300{
     301    int64_t result = ms.value() / TimeClippedPositiveMilliseconds::msPerSecond % TimeClippedPositiveMilliseconds::secondsPerMinute;
     302    ASSERT(result >= 0);
     303    return static_cast<int>(result);
     304}
     305
     306// 0: Sunday, 1: Monday, etc.
     307inline int msToWeekDay(double ms)
     308{
     309    int wd = (static_cast<int>(msToDays(ms)) + 4) % 7;
     310    if (wd < 0)
     311        wd += 7;
     312    return wd;
     313}
     314
     315inline int msToWeekDay(TimeClippedPositiveMilliseconds ms)
     316{
     317    int result = (static_cast<int>(msToDays(ms)) + 4) % 7;
     318    ASSERT(result >= 0);
     319    return result;
     320}
     321
     322inline int monthFromDayInYear(int dayInYear, bool leapYear)
     323{
     324    const int d = dayInYear;
     325    int step;
     326
     327    if (d < (step = 31))
     328        return 0;
     329    step += (leapYear ? 29 : 28);
     330    if (d < step)
     331        return 1;
     332    if (d < (step += 31))
     333        return 2;
     334    if (d < (step += 30))
     335        return 3;
     336    if (d < (step += 31))
     337        return 4;
     338    if (d < (step += 30))
     339        return 5;
     340    if (d < (step += 31))
     341        return 6;
     342    if (d < (step += 31))
     343        return 7;
     344    if (d < (step += 30))
     345        return 8;
     346    if (d < (step += 31))
     347        return 9;
     348    if (d < (step += 30))
     349        return 10;
     350    return 11;
     351}
     352
     353inline int dayInMonthFromDayInYear(int dayInYear, bool leapYear)
     354{
     355    auto checkMonth = [] (int dayInYear, int& startDayOfThisMonth, int& startDayOfNextMonth, int daysInThisMonth) -> bool {
     356        startDayOfThisMonth = startDayOfNextMonth;
     357        startDayOfNextMonth += daysInThisMonth;
     358        return (dayInYear <= startDayOfNextMonth);
     359    };
     360
     361    const int d = dayInYear;
     362    int step;
     363    int next = 30;
     364
     365    if (d <= next)
     366        return d + 1;
     367    const int daysInFeb = (leapYear ? 29 : 28);
     368    if (checkMonth(d, step, next, daysInFeb))
     369        return d - step;
     370    if (checkMonth(d, step, next, 31))
     371        return d - step;
     372    if (checkMonth(d, step, next, 30))
     373        return d - step;
     374    if (checkMonth(d, step, next, 31))
     375        return d - step;
     376    if (checkMonth(d, step, next, 30))
     377        return d - step;
     378    if (checkMonth(d, step, next, 31))
     379        return d - step;
     380    if (checkMonth(d, step, next, 31))
     381        return d - step;
     382    if (checkMonth(d, step, next, 30))
     383        return d - step;
     384    if (checkMonth(d, step, next, 31))
     385        return d - step;
     386    if (checkMonth(d, step, next, 30))
     387        return d - step;
     388    step = next;
     389    return d - step;
     390}
    132391
    133392// Returns combined offset in millisecond (UTC + DST).
     
    156415using WTF::LocalTimeOffset;
    157416using WTF::calculateLocalTimeOffset;
     417using WTF::timeClip;
     418using WTF::jsCurrentTime;
  • trunk/Source/WTF/wtf/GregorianDateTime.cpp

    r251826 r251852  
    3535
    3636namespace WTF {
     37
     38GregorianDateTime::GregorianDateTime(double ms, LocalTimeOffset localTime)
     39{
     40    if (ms >= 0
     41#if OS(WINDOWS) && CPU(X86)
     42            // The VS Compiler for 32-bit builds generates a floating point error when attempting to cast
     43            // from an infinity to a 64-bit integer. We leave this routine with the floating point error
     44            // left in a register, causing undefined behavior in later floating point operations.
     45            //
     46            // To avoid this issue, we check for infinity here, and return false in that case.
     47            && !std::isinf(ms)
     48#endif
     49        ) {
     50        int64_t integer = static_cast<int64_t>(ms);
     51        if (static_cast<double>(integer) == ms && integer <= maxECMAScriptTime) {
     52            // Positive integer fast path.
     53            WTF::TimeClippedPositiveMilliseconds timeClipped(integer);
     54            const int year = msToYear(ms);
     55            setSecond(msToSeconds(timeClipped));
     56            setMinute(msToMinutes(timeClipped));
     57            setHour(msToHours(timeClipped));
     58            setWeekDay(msToWeekDay(timeClipped));
     59            int yearDay = dayInYear(timeClipped, year);
     60            bool leapYear = isLeapYear(year);
     61            setYearDay(yearDay);
     62            setMonthDay(dayInMonthFromDayInYear(yearDay, leapYear));
     63            setMonth(monthFromDayInYear(yearDay, leapYear));
     64            setYear(year);
     65            setIsDST(localTime.isDST);
     66            setUTCOffsetInMinute(localTime.offset / WTF::msPerMinute);
     67            return;
     68        }
     69    }
     70    const int year = msToYear(ms);
     71    setSecond(msToSeconds(ms));
     72    setMinute(msToMinutes(ms));
     73    setHour(msToHours(ms));
     74    setWeekDay(msToWeekDay(ms));
     75    int yearDay = dayInYear(ms, year);
     76    bool leapYear = isLeapYear(year);
     77    setYearDay(yearDay);
     78    setMonthDay(dayInMonthFromDayInYear(yearDay, leapYear));
     79    setMonth(monthFromDayInYear(yearDay, leapYear));
     80    setYear(year);
     81    setIsDST(localTime.isDST);
     82    setUTCOffsetInMinute(localTime.offset / WTF::msPerMinute);
     83}
    3784
    3885void GregorianDateTime::setToCurrentLocalTime()
  • trunk/Source/WTF/wtf/GregorianDateTime.h

    r251826 r251852  
    3737public:
    3838    GregorianDateTime() = default;
     39    WTF_EXPORT_PRIVATE explicit GregorianDateTime(double ms, LocalTimeOffset);
    3940
    4041    inline int year() const { return m_year; }
Note: See TracChangeset for help on using the changeset viewer.