Date performance fixes, bug 578259. r=waldo
This commit is contained in:
@@ -98,16 +98,12 @@ extern int gettimeofday(struct timeval *tv);
|
||||
#define PRMJ_YEAR_SECONDS (PRMJ_DAY_SECONDS * PRMJ_YEAR_DAYS)
|
||||
#define PRMJ_MAX_UNIX_TIMET 2145859200L /*time_t value equiv. to 12/31/2037 */
|
||||
|
||||
/* function prototypes */
|
||||
static void PRMJ_basetime(JSInt64 tsecs, PRMJTime *prtm);
|
||||
/*
|
||||
* get the difference in seconds between this time zone and UTC (GMT)
|
||||
*/
|
||||
JSInt32
|
||||
PRMJ_LocalGMTDifference()
|
||||
{
|
||||
struct tm ltime;
|
||||
|
||||
#if defined(XP_WIN) && !defined(WINCE)
|
||||
/* Windows does not follow POSIX. Updates to the
|
||||
* TZ environment variable are not reflected
|
||||
@@ -116,11 +112,31 @@ PRMJ_LocalGMTDifference()
|
||||
*/
|
||||
_tzset();
|
||||
#endif
|
||||
/* get the difference between this time zone and GMT */
|
||||
memset((char *)<ime,0,sizeof(ltime));
|
||||
ltime.tm_mday = 2;
|
||||
ltime.tm_year = 70;
|
||||
return (JSInt32)mktime(<ime) - (24L * 3600L);
|
||||
|
||||
/*
|
||||
* Get the difference between this time zone and GMT, by checking the local
|
||||
* time at the epoch.
|
||||
*/
|
||||
time_t local = 0;
|
||||
struct tm tm;
|
||||
#ifndef HAVE_LOCALTIME_R
|
||||
struct tm *ptm = localtime(&local);
|
||||
if (!ptm)
|
||||
return 0;
|
||||
tm = *ptm;
|
||||
#else
|
||||
localtime_r(&local, &tm);
|
||||
#endif
|
||||
|
||||
JSInt32 time = (tm.tm_hour * 3600)
|
||||
+ (tm.tm_min * 60)
|
||||
+ tm.tm_sec;
|
||||
time = (24 * 3600) - time;
|
||||
|
||||
if (time >= (12 * 3600))
|
||||
time -= (24 * 3600);
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
/* Constants for GMT offset from 1970 */
|
||||
@@ -689,170 +705,6 @@ static int mtab[] = {
|
||||
31,31,30,31,30,31
|
||||
};
|
||||
|
||||
/*
|
||||
* basic time calculation functionality for localtime and gmtime
|
||||
* setups up prtm argument with correct values based upon input number
|
||||
* of seconds.
|
||||
*/
|
||||
static void
|
||||
PRMJ_basetime(JSInt64 tsecs, PRMJTime *prtm)
|
||||
{
|
||||
/* convert tsecs back to year,month,day,hour,secs */
|
||||
JSInt32 year = 0;
|
||||
JSInt32 month = 0;
|
||||
JSInt32 yday = 0;
|
||||
JSInt32 mday = 0;
|
||||
JSInt32 wday = 6; /* start on a Sunday */
|
||||
JSInt32 days = 0;
|
||||
JSInt32 seconds = 0;
|
||||
JSInt32 minutes = 0;
|
||||
JSInt32 hours = 0;
|
||||
JSInt32 isleap = 0;
|
||||
|
||||
/* Temporaries used for various computations */
|
||||
JSInt64 result;
|
||||
JSInt64 result1;
|
||||
JSInt64 result2;
|
||||
|
||||
JSInt64 base;
|
||||
|
||||
/* Some variables for intermediate result storage to make computing isleap
|
||||
easier/faster */
|
||||
JSInt32 fourCenturyBlocks;
|
||||
JSInt32 centuriesLeft;
|
||||
JSInt32 fourYearBlocksLeft;
|
||||
JSInt32 yearsLeft;
|
||||
|
||||
/* Since leap years work by 400/100/4 year intervals, precompute the length
|
||||
of those in seconds if they start at the beginning of year 1. */
|
||||
JSInt64 fourYears;
|
||||
JSInt64 century;
|
||||
JSInt64 fourCenturies;
|
||||
|
||||
JSLL_UI2L(result, PRMJ_DAY_SECONDS);
|
||||
|
||||
JSLL_I2L(fourYears, PRMJ_FOUR_YEARS_DAYS);
|
||||
JSLL_MUL(fourYears, fourYears, result);
|
||||
|
||||
JSLL_I2L(century, PRMJ_CENTURY_DAYS);
|
||||
JSLL_MUL(century, century, result);
|
||||
|
||||
JSLL_I2L(fourCenturies, PRMJ_FOUR_CENTURIES_DAYS);
|
||||
JSLL_MUL(fourCenturies, fourCenturies, result);
|
||||
|
||||
/* get the base time via UTC */
|
||||
base = PRMJ_ToExtendedTime(0);
|
||||
JSLL_UI2L(result, PRMJ_USEC_PER_SEC);
|
||||
JSLL_DIV(base,base,result);
|
||||
JSLL_ADD(tsecs,tsecs,base);
|
||||
|
||||
/* Compute our |year|, |isleap|, and part of |days|. When this part is
|
||||
done, |year| should hold the year our date falls in (number of whole
|
||||
years elapsed before our date), isleap should hold 1 if the year the
|
||||
date falls in is a leap year and 0 otherwise. */
|
||||
|
||||
/* First do year 0; it's special and nonleap. */
|
||||
JSLL_UI2L(result, PRMJ_YEAR_SECONDS);
|
||||
if (!JSLL_CMP(tsecs,<,result)) {
|
||||
days = PRMJ_YEAR_DAYS;
|
||||
year = 1;
|
||||
JSLL_SUB(tsecs, tsecs, result);
|
||||
}
|
||||
|
||||
/* Now use those constants we computed above */
|
||||
JSLL_UDIVMOD(&result1, &result2, tsecs, fourCenturies);
|
||||
JSLL_L2I(fourCenturyBlocks, result1);
|
||||
year += fourCenturyBlocks * 400;
|
||||
days += fourCenturyBlocks * PRMJ_FOUR_CENTURIES_DAYS;
|
||||
tsecs = result2;
|
||||
|
||||
JSLL_UDIVMOD(&result1, &result2, tsecs, century);
|
||||
JSLL_L2I(centuriesLeft, result1);
|
||||
year += centuriesLeft * 100;
|
||||
days += centuriesLeft * PRMJ_CENTURY_DAYS;
|
||||
tsecs = result2;
|
||||
|
||||
JSLL_UDIVMOD(&result1, &result2, tsecs, fourYears);
|
||||
JSLL_L2I(fourYearBlocksLeft, result1);
|
||||
year += fourYearBlocksLeft * 4;
|
||||
days += fourYearBlocksLeft * PRMJ_FOUR_YEARS_DAYS;
|
||||
tsecs = result2;
|
||||
|
||||
/* Recall that |result| holds PRMJ_YEAR_SECONDS */
|
||||
JSLL_UDIVMOD(&result1, &result2, tsecs, result);
|
||||
JSLL_L2I(yearsLeft, result1);
|
||||
year += yearsLeft;
|
||||
days += yearsLeft * PRMJ_YEAR_DAYS;
|
||||
tsecs = result2;
|
||||
|
||||
/* now compute isleap. Note that we don't have to use %, since we've
|
||||
already computed those remainders. Also note that they're all offset by
|
||||
1 because of the 1 for year 0. */
|
||||
isleap =
|
||||
(yearsLeft == 3) && (fourYearBlocksLeft != 24 || centuriesLeft == 3);
|
||||
JS_ASSERT(isleap ==
|
||||
((year % 4 == 0) && (year % 100 != 0 || year % 400 == 0)));
|
||||
|
||||
JSLL_UI2L(result1,PRMJ_DAY_SECONDS);
|
||||
|
||||
JSLL_DIV(result,tsecs,result1);
|
||||
JSLL_L2I(mday,result);
|
||||
|
||||
/* let's find the month */
|
||||
while(((month == 1 && isleap) ?
|
||||
(mday >= mtab[month] + 1) :
|
||||
(mday >= mtab[month]))){
|
||||
yday += mtab[month];
|
||||
days += mtab[month];
|
||||
|
||||
mday -= mtab[month];
|
||||
|
||||
/* it's a Feb, check if this is a leap year */
|
||||
if(month == 1 && isleap != 0){
|
||||
yday++;
|
||||
days++;
|
||||
mday--;
|
||||
}
|
||||
month++;
|
||||
}
|
||||
|
||||
/* now adjust tsecs */
|
||||
JSLL_MUL(result,result,result1);
|
||||
JSLL_SUB(tsecs,tsecs,result);
|
||||
|
||||
mday++; /* day of month always start with 1 */
|
||||
days += mday;
|
||||
wday = (days + wday) % 7;
|
||||
|
||||
yday += mday;
|
||||
|
||||
/* get the hours */
|
||||
JSLL_UI2L(result1,PRMJ_HOUR_SECONDS);
|
||||
JSLL_DIV(result,tsecs,result1);
|
||||
JSLL_L2I(hours,result);
|
||||
JSLL_MUL(result,result,result1);
|
||||
JSLL_SUB(tsecs,tsecs,result);
|
||||
|
||||
/* get minutes */
|
||||
JSLL_UI2L(result1,60);
|
||||
JSLL_DIV(result,tsecs,result1);
|
||||
JSLL_L2I(minutes,result);
|
||||
JSLL_MUL(result,result,result1);
|
||||
JSLL_SUB(tsecs,tsecs,result);
|
||||
|
||||
JSLL_L2I(seconds,tsecs);
|
||||
|
||||
prtm->tm_usec = 0L;
|
||||
prtm->tm_sec = (JSInt8)seconds;
|
||||
prtm->tm_min = (JSInt8)minutes;
|
||||
prtm->tm_hour = (JSInt8)hours;
|
||||
prtm->tm_mday = (JSInt8)mday;
|
||||
prtm->tm_mon = (JSInt8)month;
|
||||
prtm->tm_wday = (JSInt8)wday;
|
||||
prtm->tm_year = (JSInt16)year;
|
||||
prtm->tm_yday = (JSInt16)yday;
|
||||
}
|
||||
|
||||
JSInt64
|
||||
DSTOffsetCache::computeDSTOffsetMilliseconds(int64 localTimeSeconds)
|
||||
{
|
||||
@@ -869,9 +721,7 @@ DSTOffsetCache::computeDSTOffsetMilliseconds(int64 localTimeSeconds)
|
||||
#endif
|
||||
|
||||
time_t local = static_cast<time_t>(localTimeSeconds);
|
||||
PRMJTime prtm;
|
||||
struct tm tm;
|
||||
PRMJ_basetime(localTimeSeconds, &prtm);
|
||||
#ifndef HAVE_LOCALTIME_R
|
||||
struct tm *ptm = localtime(&local);
|
||||
if (!ptm)
|
||||
@@ -881,8 +731,13 @@ DSTOffsetCache::computeDSTOffsetMilliseconds(int64 localTimeSeconds)
|
||||
localtime_r(&local, &tm); /* get dst information */
|
||||
#endif
|
||||
|
||||
JSInt32 diff = ((tm.tm_hour - prtm.tm_hour) * SECONDS_PER_HOUR) +
|
||||
((tm.tm_min - prtm.tm_min) * SECONDS_PER_MINUTE);
|
||||
JSInt32 base = PRMJ_LocalGMTDifference();
|
||||
|
||||
int32 dayoff = int32((localTimeSeconds - base) % (SECONDS_PER_HOUR * 24));
|
||||
int32 tmoff = tm.tm_sec + (tm.tm_min * SECONDS_PER_MINUTE) +
|
||||
(tm.tm_hour * SECONDS_PER_HOUR);
|
||||
|
||||
JSInt32 diff = tmoff - dayoff;
|
||||
|
||||
if (diff < 0)
|
||||
diff += SECONDS_PER_DAY;
|
||||
@@ -911,12 +766,23 @@ DSTOffsetCache::getDSTOffsetMilliseconds(JSInt64 localTimeMilliseconds, JSContex
|
||||
* values, must result in a cache miss.
|
||||
*/
|
||||
|
||||
if (rangeStartSeconds <= localTimeSeconds) {
|
||||
if (localTimeSeconds <= rangeEndSeconds) {
|
||||
noteCacheHit();
|
||||
return offsetMilliseconds;
|
||||
}
|
||||
if (rangeStartSeconds <= localTimeSeconds &&
|
||||
localTimeSeconds <= rangeEndSeconds) {
|
||||
noteCacheHit();
|
||||
return offsetMilliseconds;
|
||||
}
|
||||
|
||||
if (oldRangeStartSeconds <= localTimeSeconds &&
|
||||
localTimeSeconds <= oldRangeEndSeconds) {
|
||||
noteCacheHit();
|
||||
return oldOffsetMilliseconds;
|
||||
}
|
||||
|
||||
oldOffsetMilliseconds = offsetMilliseconds;
|
||||
oldRangeStartSeconds = rangeStartSeconds;
|
||||
oldRangeEndSeconds = rangeEndSeconds;
|
||||
|
||||
if (rangeStartSeconds <= localTimeSeconds) {
|
||||
JSInt64 newEndSeconds = JS_MIN(rangeEndSeconds + RANGE_EXPANSION_AMOUNT, MAX_UNIX_TIMET);
|
||||
if (newEndSeconds >= localTimeSeconds) {
|
||||
JSInt64 endOffsetMilliseconds = computeDSTOffsetMilliseconds(newEndSeconds);
|
||||
|
||||
Reference in New Issue
Block a user