Bug 563938 - Refactor DST offset computation to pave the way for caching the DST offset when possible. No functionality change. r=sayrer

--HG--
extra : rebase_source : ad70045b70cc23dd7578e594490a10b4fc6fc7ef
This commit is contained in:
Jeff Walden 2010-05-26 17:00:28 -07:00
parent 22db0647cc
commit e98ca56524
4 changed files with 109 additions and 103 deletions

View File

@ -64,6 +64,7 @@
#include "jsarray.h"
#include "jstask.h"
#include "jsvector.h"
#include "prmjtime.h"
#ifdef _MSC_VER
#pragma warning(push)
@ -1893,6 +1894,8 @@ struct JSContext
JSClassProtoCache classProtoCache;
DSTOffsetCache dstOffsetCache;
private:
/*
* To go from a live generator frame (on the stack) to its generator object

View File

@ -392,9 +392,9 @@ EquivalentYearForDST(jsint year)
static jsdouble LocalTZA;
static jsdouble
DaylightSavingTA(jsdouble t)
DaylightSavingTA(jsdouble t, JSContext *cx)
{
volatile int64 PR_t;
int64 PR_t;
int64 ms2us;
int64 offset;
jsdouble result;
@ -421,7 +421,7 @@ DaylightSavingTA(jsdouble t)
JSLL_I2L(ms2us, PRMJ_USEC_PER_MSEC);
JSLL_MUL(PR_t, PR_t, ms2us);
offset = PRMJ_DSTOffset(PR_t);
offset = cx->dstOffsetCache.getDSTOffset(PR_t, cx);
JSLL_DIV(offset, offset, ms2us);
JSLL_L2D(result, offset);
@ -429,19 +429,23 @@ DaylightSavingTA(jsdouble t)
}
static jsdouble
AdjustTime(jsdouble date)
AdjustTime(jsdouble date, JSContext *cx)
{
jsdouble t = DaylightSavingTA(date) + LocalTZA;
jsdouble t = DaylightSavingTA(date, cx) + LocalTZA;
t = (LocalTZA >= 0) ? fmod(t, msPerDay) : -fmod(msPerDay - t, msPerDay);
return t;
}
#define LocalTime(t) ((t) + AdjustTime(t))
static jsdouble
LocalTime(jsdouble t, JSContext *cx)
{
return t + AdjustTime(t, cx);
}
static jsdouble
UTC(jsdouble t)
UTC(jsdouble t, JSContext *cx)
{
return t - AdjustTime(t - LocalTZA);
return t - AdjustTime(t - LocalTZA, cx);
}
static intN
@ -748,7 +752,7 @@ ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
*/
static JSBool
date_parseISOString(JSString *str, jsdouble *result)
date_parseISOString(JSString *str, jsdouble *result, JSContext *cx)
{
jsdouble msec;
@ -856,7 +860,7 @@ date_parseISOString(JSString *str, jsdouble *result)
frac * 1000.0);;
if (isLocalTime) {
msec = UTC(msec);
msec = UTC(msec, cx);
} else {
msec -= ((tzMul) * ((tzHour * msPerHour)
+ (tzMin * msPerMinute)));
@ -881,7 +885,7 @@ date_parseISOString(JSString *str, jsdouble *result)
}
static JSBool
date_parseString(JSString *str, jsdouble *result)
date_parseString(JSString *str, jsdouble *result, JSContext *cx)
{
jsdouble msec;
@ -902,7 +906,7 @@ date_parseString(JSString *str, jsdouble *result)
int temp;
JSBool seenmonthname = JS_FALSE;
if (date_parseISOString(str, result))
if (date_parseISOString(str, result, cx))
return JS_TRUE;
str->getCharsAndLength(s, limit);
@ -1137,7 +1141,7 @@ date_parseString(JSString *str, jsdouble *result)
msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
if (tzoffset == -1) { /* no time zone specified, have to use local */
msec = UTC(msec);
msec = UTC(msec, cx);
} else {
msec += tzoffset * msPerMinute;
}
@ -1165,7 +1169,7 @@ date_parse(JSContext *cx, uintN argc, jsval *vp)
if (!str)
return JS_FALSE;
vp[2] = STRING_TO_JSVAL(str);
if (!date_parseString(str, &result)) {
if (!date_parseString(str, &result, cx)) {
*vp = cx->runtime->NaNValue;
return true;
}
@ -1251,7 +1255,7 @@ GetAndCacheLocalTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp)
/* if result is NaN, it couldn't be finite. */
if (JSDOUBLE_IS_FINITE(result))
result = LocalTime(result);
result = LocalTime(result, cx);
if (!js_NewDoubleInRootedValue(cx, result, slotp))
return false;
@ -1580,7 +1584,7 @@ date_makeTime(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp)
}
if (local)
lorutime = LocalTime(result);
lorutime = LocalTime(result, cx);
else
lorutime = result;
@ -1612,7 +1616,7 @@ date_makeTime(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp)
/* fprintf(stderr, "%f\n", result); */
if (local)
result = UTC(result);
result = UTC(result, cx);
/* fprintf(stderr, "%f\n", result); */
@ -1709,7 +1713,7 @@ date_makeDate(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp)
return js_NewNumberInRootedValue(cx, result, vp);
lorutime = +0.;
} else {
lorutime = local ? LocalTime(result) : result;
lorutime = local ? LocalTime(result, cx) : result;
}
argp = args;
@ -1733,7 +1737,7 @@ date_makeDate(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp)
result = MakeDate(day, TimeWithinDay(lorutime));
if (local)
result = UTC(result);
result = UTC(result, cx);
return SetUTCTime(cx, obj, TIMECLIP(result), vp);
}
@ -1800,10 +1804,10 @@ date_setYear(JSContext *cx, uintN argc, jsval *vp)
if (year >= 0 && year <= 99)
year += 1900;
jsdouble t = JSDOUBLE_IS_FINITE(result) ? LocalTime(result) : +0.0;
jsdouble t = JSDOUBLE_IS_FINITE(result) ? LocalTime(result, cx) : +0.0;
jsdouble day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
result = MakeDate(day, TimeWithinDay(t));
result = UTC(result);
result = UTC(result, cx);
return SetUTCTime(cx, obj, TIMECLIP(result), vp);
}
@ -1886,7 +1890,7 @@ date_toISOString(JSContext *cx, uintN argc, jsval *vp)
/* for Date.toLocaleString; interface to PRMJTime date struct.
*/
static void
new_explode(jsdouble timeval, PRMJTime *split)
new_explode(jsdouble timeval, PRMJTime *split, JSContext *cx)
{
jsint year = YearFromTime(timeval);
@ -1902,7 +1906,7 @@ new_explode(jsdouble timeval, PRMJTime *split)
/* not sure how this affects things, but it doesn't seem
to matter. */
split->tm_isdst = (DaylightSavingTA(timeval) != 0);
split->tm_isdst = (DaylightSavingTA(timeval, cx) != 0);
}
typedef enum formatspec {
@ -1923,11 +1927,11 @@ date_format(JSContext *cx, jsdouble date, formatspec format, jsval *rval)
if (!JSDOUBLE_IS_FINITE(date)) {
JS_snprintf(buf, sizeof buf, js_NaN_date_str);
} else {
jsdouble local = LocalTime(date);
jsdouble local = LocalTime(date, cx);
/* offset from GMT in minutes. The offset includes daylight savings,
if it applies. */
jsint minutes = (jsint) floor(AdjustTime(date) / msPerMinute);
jsint minutes = (jsint) floor(AdjustTime(date, cx) / msPerMinute);
/* map 510 minutes to 0830 hours */
intN offset = (minutes / 60) * 100 + minutes % 60;
@ -1943,7 +1947,7 @@ date_format(JSContext *cx, jsdouble date, formatspec format, jsval *rval)
/* get a timezone string from the OS to include as a
comment. */
new_explode(date, &split);
new_explode(date, &split, cx);
if (PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &split) != 0) {
/* Decide whether to use the resulting timezone string.
@ -2040,8 +2044,8 @@ date_toLocaleHelper(JSContext *cx, const char *format, jsval *vp)
JS_snprintf(buf, sizeof buf, js_NaN_date_str);
} else {
intN result_len;
jsdouble local = LocalTime(utctime);
new_explode(local, &split);
jsdouble local = LocalTime(utctime, cx);
new_explode(local, &split, cx);
/* let PRMJTime format it. */
result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split);
@ -2311,7 +2315,7 @@ js_Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
return JS_FALSE;
argv[0] = STRING_TO_JSVAL(str);
if (!date_parseString(str, &d))
if (!date_parseString(str, &d, cx))
d = js_NaN;
else
d = TIMECLIP(d);
@ -2322,7 +2326,7 @@ js_Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
return JS_FALSE;
if (JSDOUBLE_IS_FINITE(msec_time)) {
msec_time = UTC(msec_time);
msec_time = UTC(msec_time, cx);
msec_time = TIMECLIP(msec_time);
}
d = msec_time;
@ -2369,7 +2373,7 @@ js_NewDateObject(JSContext* cx, int year, int mon, int mday,
JS_ASSERT(mon < 12);
msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
obj = js_NewDateObjectMsec(cx, UTC(msec_time));
obj = js_NewDateObjectMsec(cx, UTC(msec_time, cx));
return obj;
}
@ -2478,7 +2482,7 @@ js_DateSetYear(JSContext *cx, JSObject *obj, int year)
msFromTime(local));
/* SetUTCTime also invalidates local time cache. */
SetUTCTime(cx, obj, UTC(local));
SetUTCTime(cx, obj, UTC(local, cx));
}
JS_FRIEND_API(void)
@ -2502,7 +2506,7 @@ js_DateSetMonth(JSContext *cx, JSObject *obj, int month)
MinFromTime(local),
SecFromTime(local),
msFromTime(local));
SetUTCTime(cx, obj, UTC(local));
SetUTCTime(cx, obj, UTC(local, cx));
}
JS_FRIEND_API(void)
@ -2523,7 +2527,7 @@ js_DateSetDate(JSContext *cx, JSObject *obj, int date)
MinFromTime(local),
SecFromTime(local),
msFromTime(local));
SetUTCTime(cx, obj, UTC(local));
SetUTCTime(cx, obj, UTC(local, cx));
}
JS_FRIEND_API(void)
@ -2543,7 +2547,7 @@ js_DateSetHours(JSContext *cx, JSObject *obj, int hours)
MinFromTime(local),
SecFromTime(local),
msFromTime(local));
SetUTCTime(cx, obj, UTC(local));
SetUTCTime(cx, obj, UTC(local, cx));
}
JS_FRIEND_API(void)
@ -2563,7 +2567,7 @@ js_DateSetMinutes(JSContext *cx, JSObject *obj, int minutes)
minutes,
SecFromTime(local),
msFromTime(local));
SetUTCTime(cx, obj, UTC(local));
SetUTCTime(cx, obj, UTC(local, cx));
}
JS_FRIEND_API(void)
@ -2583,7 +2587,7 @@ js_DateSetSeconds(JSContext *cx, JSObject *obj, int seconds)
MinFromTime(local),
seconds,
msFromTime(local));
SetUTCTime(cx, obj, UTC(local));
SetUTCTime(cx, obj, UTC(local, cx));
}
JS_FRIEND_API(jsdouble)

View File

@ -555,68 +555,6 @@ PRMJ_Now(void)
}
#endif
/* Get the DST timezone offset for the time passed in */
JSInt64
PRMJ_DSTOffset(JSInt64 local_time)
{
JSInt64 us2s;
time_t local;
JSInt32 diff;
JSInt64 maxtimet;
struct tm tm;
PRMJTime prtm;
#ifndef HAVE_LOCALTIME_R
struct tm *ptm;
#endif
JSLL_UI2L(us2s, PRMJ_USEC_PER_SEC);
JSLL_DIV(local_time, local_time, us2s);
/* get the maximum of time_t value */
JSLL_UI2L(maxtimet,PRMJ_MAX_UNIX_TIMET);
if(JSLL_CMP(local_time,>,maxtimet)){
JSLL_UI2L(local_time,PRMJ_MAX_UNIX_TIMET);
} else if(!JSLL_GE_ZERO(local_time)){
/*go ahead a day to make localtime work (does not work with 0) */
JSLL_UI2L(local_time,PRMJ_DAY_SECONDS);
}
#if defined(XP_WIN) && !defined(WINCE)
/* Windows does not follow POSIX. Updates to the
* TZ environment variable are not reflected
* immediately on that platform as they are
* on UNIX systems without this call.
*/
_tzset();
#endif
JSLL_L2UI(local,local_time);
PRMJ_basetime(local_time,&prtm);
#ifndef HAVE_LOCALTIME_R
ptm = localtime(&local);
if(!ptm){
return 0;
}
tm = *ptm;
#else
localtime_r(&local,&tm); /* get dst information */
#endif
diff = ((tm.tm_hour - prtm.tm_hour) * PRMJ_HOUR_SECONDS) +
((tm.tm_min - prtm.tm_min) * 60);
if (diff < 0)
diff += PRMJ_DAY_SECONDS;
JSLL_UI2L(local_time,diff);
JSLL_MUL(local_time,local_time,us2s);
return(local_time);
}
#ifdef NS_HAVE_INVALID_PARAMETER_HANDLER
static void
PRMJ_InvalidParameterHandler(const wchar_t *expression,
@ -913,3 +851,52 @@ PRMJ_basetime(JSInt64 tsecs, PRMJTime *prtm)
prtm->tm_year = (JSInt16)year;
prtm->tm_yday = (JSInt16)yday;
}
JSInt64
DSTOffsetCache::computeDSTOffset(int64 localTime)
{
localTime /= MICROSECONDS_PER_SECOND;
if (localTime > MAX_UNIX_TIMET) {
localTime = MAX_UNIX_TIMET;
} else if (localTime < 0) {
/* Go ahead a day to make localtime work (does not work with 0). */
localTime = SECONDS_PER_DAY;
}
#if defined(XP_WIN) && !defined(WINCE)
/* Windows does not follow POSIX. Updates to the
* TZ environment variable are not reflected
* immediately on that platform as they are
* on UNIX systems without this call.
*/
_tzset();
#endif
time_t local = static_cast<time_t>(localTime);
PRMJTime prtm;
struct tm tm;
PRMJ_basetime(localTime, &prtm);
#ifndef HAVE_LOCALTIME_R
struct tm *ptm = localtime(&local);
if (!ptm)
return 0;
tm = *ptm;
#else
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);
if (diff < 0)
diff += SECONDS_PER_DAY;
return diff * MICROSECONDS_PER_SECOND;
}
JSInt64
DSTOffsetCache::getDSTOffset(JSInt64 localTime, JSContext *cx)
{
return computeDSTOffset(localTime);
}

View File

@ -49,6 +49,22 @@
#include "jscompat.h"
#endif
struct JSContext;
class DSTOffsetCache {
public:
JSInt64 getDSTOffset(int64 localTime, JSContext *cx);
private:
JSInt64 computeDSTOffset(int64 localTime);
static const JSInt64 MAX_UNIX_TIMET = 2145859200; /* time_t 12/31/2037 */
static const JSInt64 MICROSECONDS_PER_SECOND = 1000000;
static const JSInt64 SECONDS_PER_MINUTE = 60;
static const JSInt64 SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE;
static const JSInt64 SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR;
};
JS_BEGIN_EXTERN_C
typedef struct PRMJTime PRMJTime;
@ -93,10 +109,6 @@ PRMJ_LocalGMTDifference(void);
extern size_t
PRMJ_FormatTime(char *buf, int buflen, const char *fmt, PRMJTime *tm);
/* Get the DST offset for the local time passed in */
extern JSInt64
PRMJ_DSTOffset(JSInt64 local_time);
JS_END_EXTERN_C
#endif /* prmjtime_h___ */