Commit d4900677 authored by barraclough@apple.com's avatar barraclough@apple.com

String(new Date(2010,10,1)) is wrong in KRAT, YAKT

https://bugs.webkit.org/show_bug.cgi?id=106750

Reviewed by Darin Adler.

First part of a fix, simplfy date handling code, instead of operating separately
on the UTC-standard and standard-DST offsets, just generate a combined UTC-local
offset (this is what we actually need, and what the OS gives us).

../JavaScriptCore: 

* runtime/JSDateMath.cpp:
(JSC::getLocalTimeOffset):
    - removed getUTCOffset, converted getDSTOffset -> getLocalTimeOffset
(JSC::gregorianDateTimeToMS):
(JSC::msToGregorianDateTime):
(JSC::parseDateFromNullTerminatedCharacters):
    - call getLocalTimeOffset instead of getUTCOffset/getDSTOffset
* runtime/VM.cpp:
(JSC::VM::resetDateCache):
    - removed cachedUTCOffset, converted DSTOffsetCache -> LocalTimeOffsetCache
* runtime/VM.h:
(JSC::LocalTimeOffsetCache::LocalTimeOffsetCache):
(JSC::LocalTimeOffsetCache::reset):
(LocalTimeOffsetCache):
    - removed cachedUTCOffset, converted DSTOffsetCache -> LocalTimeOffsetCache

../WTF: 

* wtf/DateMath.cpp:
(WTF::calculateUTCOffset):
(WTF::calculateDSTOffset):
    - made static, now not called from outside of this file.
(WTF::calculateLocalTimeOffset):
    - This combines the 2038 related adjustment from calculateDSTOffset with the
      maxUnixTime adjustment from calculateDSTOffsetSimple. Then, if HAVE(TM_GMTOFF)
      just call getLocalTime, if not use calculateUTCOffset/calculateDSTOffset.
(WTF::parseDateFromNullTerminatedCharacters):
    - call calculateLocalTimeOffset instead of calculateUTCOffset/calculateDSTOffset
* wtf/DateMath.h:
(WTF::LocalTimeOffset::LocalTimeOffset):
(LocalTimeOffset):
(WTF::LocalTimeOffset::operator==):
    - new struct type, a tuple of UTC-local offset & isDST flag.
    - replaced calculateUTCOffset/calculateDSTOffset with calculateLocalTimeOffset
* wtf/GregorianDateTime.cpp:
(WTF::GregorianDateTime::setToCurrentLocalTime):
    - call calculateLocalTimeOffset instead of calculateUTCOffset/calculateDSTOffset



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@150833 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 239349ed
2013-05-27 Gavin Barraclough <barraclough@apple.com>
String(new Date(2010,10,1)) is wrong in KRAT, YAKT
https://bugs.webkit.org/show_bug.cgi?id=106750
Reviewed by Darin Adler.
First part of a fix, simplfy date handling code, instead of operating separately
on the UTC-standard and standard-DST offsets, just generate a combined UTC-local
offset (this is what we actually need, and what the OS gives us).
* runtime/JSDateMath.cpp:
(JSC::getLocalTimeOffset):
- removed getUTCOffset, converted getDSTOffset -> getLocalTimeOffset
(JSC::gregorianDateTimeToMS):
(JSC::msToGregorianDateTime):
(JSC::parseDateFromNullTerminatedCharacters):
- call getLocalTimeOffset instead of getUTCOffset/getDSTOffset
* runtime/VM.cpp:
(JSC::VM::resetDateCache):
- removed cachedUTCOffset, converted DSTOffsetCache -> LocalTimeOffsetCache
* runtime/VM.h:
(JSC::LocalTimeOffsetCache::LocalTimeOffsetCache):
(JSC::LocalTimeOffsetCache::reset):
(LocalTimeOffsetCache):
- removed cachedUTCOffset, converted DSTOffsetCache -> LocalTimeOffsetCache
2013-05-28 Mark Hahnenberg <mhahnenberg@apple.com>
r150199 is very wrong
......
......@@ -1775,7 +1775,6 @@ __ZN3JSCL21dateProtoFuncToStringEPNS_9ExecStateE
__ZNK3JSC12DateInstance26calculateGregorianDateTimeEPNS_9ExecStateE
__ZN3JSC21msToGregorianDateTimeEPNS_9ExecStateEdbRNS_17GregorianDateTimeE
__ZN3JSCL12getDSTOffsetEPNS_9ExecStateEdd
__ZN3WTF18calculateDSTOffsetEdd
__ZN3WTF18dateToDaysFrom1970Eiii
__ZN3JSC10formatDateERKNS_17GregorianDateTimeERA100_c
__ZN3JSC10formatTimeERKNS_17GregorianDateTimeERA100_c
......
......@@ -119,10 +119,7 @@ EXPORTS
?broadcast@ThreadCondition@WTF@@QAEXXZ
?bufferLengthForStringDecimal@DecimalNumber@WTF@@QBEIXZ
?bufferLengthForStringExponential@DecimalNumber@WTF@@QBEIXZ
?byteCompile@Yarr@JSC@@YA?AV?$PassOwnPtr@UBytecodePattern@Yarr@JSC@@@WTF@@AAUYarrPattern@12@PAVBumpPointerAllocator@4@@Z
?calculateDSTOffset@WTF@@YANNN@Z
?calculateStringHashAndLengthFromUTF8MaskingTop8Bits@Unicode@WTF@@YAIPBD0AAI1@Z
?calculateUTCOffset@WTF@@YAHXZ
?byteCompile@Yarr@JSC@@YA?AV?$PassOwnPtr@UBytecodePattern@Yarr@JSC@@@WTF@@AAUYarrPattern@12@PAVBumpPointerAllocator@4@@Z ?calculateStringHashAndLengthFromUTF8MaskingTop8Bits@Unicode@WTF@@YAIPBD0AAI1@Z
?calculatedFunctionName@DebuggerCallFrame@JSC@@QBE?AVString@WTF@@XZ
?call@JSC@@YA?AVJSValue@1@PAVExecState@1@V21@W4CallType@1@ABTCallData@1@1ABVArgList@1@@Z
?callHostFunctionAsConstructor@JSC@@YI_JPAVExecState@1@@Z
......
......@@ -119,9 +119,7 @@ EXPORTS
?bufferLengthForStringDecimal@DecimalNumber@WTF@@QBEIXZ
?bufferLengthForStringExponential@DecimalNumber@WTF@@QBEIXZ
?byteCompile@Yarr@JSC@@YA?AV?$PassOwnPtr@UBytecodePattern@Yarr@JSC@@@WTF@@AAUYarrPattern@12@PAVBumpPointerAllocator@4@@Z
?calculateDSTOffset@WTF@@YANNN@Z
?calculateStringHashAndLengthFromUTF8MaskingTop8Bits@Unicode@WTF@@YAIPBD0AAI1@Z
?calculateUTCOffset@WTF@@YAHXZ
?calculatedFunctionName@DebuggerCallFrame@JSC@@QBE?AVString@WTF@@XZ
?call@JSC@@YA?AVJSValue@1@PAVExecState@1@V21@W4CallType@1@ABTCallData@1@1ABVArgList@1@@Z
?callHostFunctionAsConstructor@JSC@@YI_JPAVExecState@1@@Z
......
......@@ -127,14 +127,14 @@ static inline int msToWeekDay(double ms)
return wd;
}
// Get the DST offset for the time passed in.
// Get the combined UTC + DST offset for the time passed in.
//
// NOTE: The implementation relies on the fact that no time zones have
// more than one daylight savings offset change per month.
// If this function is called with NaN it returns NaN.
static double getDSTOffset(ExecState* exec, double ms, double utcOffset)
static LocalTimeOffset localTimeOffset(ExecState* exec, double ms)
{
DSTOffsetCache& cache = exec->vm().dstOffsetCache;
LocalTimeOffsetCache& cache = exec->vm().localTimeOffsetCache;
double start = cache.start;
double end = cache.end;
......@@ -146,7 +146,7 @@ static double getDSTOffset(ExecState* exec, double ms, double utcOffset)
double newEnd = end + cache.increment;
if (ms <= newEnd) {
double endOffset = calculateDSTOffset(newEnd, utcOffset);
LocalTimeOffset endOffset = calculateLocalTimeOffset(newEnd);
if (cache.offset == endOffset) {
// If the offset at the end of the new interval still matches
// the offset in the cache, we grow the cached time interval
......@@ -154,34 +154,33 @@ static double getDSTOffset(ExecState* exec, double ms, double utcOffset)
cache.end = newEnd;
cache.increment = msPerMonth;
return endOffset;
}
LocalTimeOffset offset = calculateLocalTimeOffset(ms);
if (offset == endOffset) {
// The offset at the given time is equal to the offset at the
// new end of the interval, so that means that we've just skipped
// the point in time where the DST offset change occurred. Updated
// the interval to reflect this and reset the increment.
cache.start = ms;
cache.end = newEnd;
cache.increment = msPerMonth;
} else {
double offset = calculateDSTOffset(ms, utcOffset);
if (offset == endOffset) {
// The offset at the given time is equal to the offset at the
// new end of the interval, so that means that we've just skipped
// the point in time where the DST offset change occurred. Updated
// the interval to reflect this and reset the increment.
cache.start = ms;
cache.end = newEnd;
cache.increment = 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
// the offset change point and change the end of the interval.
cache.increment /= 3;
cache.end = ms;
}
// Update the offset in the cache and return it.
cache.offset = offset;
return offset;
// The interval contains a DST offset change and the given time is
// before it. Adjust the increment to avoid a linear search for
// the offset change point and change the end of the interval.
cache.increment /= 3;
cache.end = ms;
}
// Update the offset in the cache and return it.
cache.offset = offset;
return offset;
}
}
// Compute the DST offset for the time and shrink the cache interval
// to only contain the time. This allows fast repeated DST offset
// computations for the same time.
double offset = calculateDSTOffset(ms, utcOffset);
LocalTimeOffset offset = calculateLocalTimeOffset(ms);
cache.offset = offset;
cache.start = ms;
cache.end = ms;
......@@ -189,30 +188,14 @@ static double getDSTOffset(ExecState* exec, double ms, double utcOffset)
return offset;
}
/*
* Get the difference in milliseconds between this time zone and UTC (GMT)
* NOT including DST.
*/
double getUTCOffset(ExecState* exec)
{
double utcOffset = exec->vm().cachedUTCOffset;
if (!std::isnan(utcOffset))
return utcOffset;
exec->vm().cachedUTCOffset = calculateUTCOffset();
return exec->vm().cachedUTCOffset;
}
double gregorianDateTimeToMS(ExecState* exec, const GregorianDateTime& t, double milliSeconds, bool inputIsUTC)
{
double day = dateToDaysFrom1970(t.year(), t.month(), t.monthDay());
double ms = timeToMS(t.hour(), t.minute(), t.second(), milliSeconds);
double result = (day * WTF::msPerDay) + ms;
if (!inputIsUTC) { // convert to UTC
double utcOffset = getUTCOffset(exec);
result -= utcOffset;
result -= getDSTOffset(exec, result, utcOffset);
}
if (!inputIsUTC)
result -= localTimeOffset(exec, result).offset;
return result;
}
......@@ -220,12 +203,10 @@ double gregorianDateTimeToMS(ExecState* exec, const GregorianDateTime& t, double
// input is UTC
void msToGregorianDateTime(ExecState* exec, double ms, bool outputIsUTC, GregorianDateTime& tm)
{
double dstOff = 0.0;
double utcOff = 0.0;
LocalTimeOffset localTime(false, 0);
if (!outputIsUTC) {
utcOff = getUTCOffset(exec);
dstOff = getDSTOffset(exec, ms, utcOff);
ms += dstOff + utcOff;
localTime = localTimeOffset(exec, ms);
ms += localTime.offset;
}
const int year = msToYear(ms);
......@@ -237,8 +218,8 @@ void msToGregorianDateTime(ExecState* exec, double ms, bool outputIsUTC, Gregori
tm.setMonthDay(dayInMonthFromDayInYear(tm.yearDay(), isLeapYear(year)));
tm.setMonth(monthFromDayInYear(tm.yearDay(), isLeapYear(year)));
tm.setYear(year);
tm.setIsDST(dstOff != 0.0);
tm.setUtcOffset(static_cast<long>((dstOff + utcOff) / WTF::msPerSecond));
tm.setIsDST(localTime.isDST);
tm.setUtcOffset(localTime.offset / WTF::msPerSecond);
}
double parseDateFromNullTerminatedCharacters(ExecState* exec, const char* dateString)
......@@ -251,11 +232,9 @@ double parseDateFromNullTerminatedCharacters(ExecState* exec, const char* dateSt
return QNaN;
// fall back to local timezone
if (!haveTZ) {
double utcOffset = getUTCOffset(exec);
double dstOffset = getDSTOffset(exec, ms, utcOffset);
offset = (utcOffset + dstOffset) / WTF::msPerMinute;
}
if (!haveTZ)
offset = localTimeOffset(exec, ms).offset / WTF::msPerMinute;
return ms - (offset * WTF::msPerMinute);
}
......
......@@ -171,7 +171,6 @@ VM::VM(VMType vmType, HeapType heapType)
, sizeOfLastScratchBuffer(0)
#endif
, dynamicGlobalObject(0)
, cachedUTCOffset(QNaN)
, m_enabledProfiler(0)
, m_regExpCache(new RegExpCache(this))
#if ENABLE(REGEXP_TRACING)
......@@ -425,8 +424,7 @@ VM::ClientData::~ClientData()
void VM::resetDateCache()
{
cachedUTCOffset = QNaN;
dstOffsetCache.reset();
localTimeOffsetCache.reset();
cachedDateString = String();
cachedDateStringValue = QNaN;
dateInstanceCache.reset();
......
......@@ -51,6 +51,7 @@
#include "Watchdog.h"
#include "WeakRandom.h"
#include <wtf/BumpPointerAllocator.h>
#include <wtf/DateMath.h>
#include <wtf/Forward.h>
#include <wtf/HashMap.h>
#include <wtf/RefCountedArray.h>
......@@ -101,21 +102,23 @@ namespace JSC {
struct HashTable;
struct Instruction;
struct DSTOffsetCache {
DSTOffsetCache()
struct LocalTimeOffsetCache {
LocalTimeOffsetCache()
: start(0.0)
, end(-1.0)
, increment(0.0)
{
reset();
}
void reset()
{
offset = 0.0;
offset = LocalTimeOffset();
start = 0.0;
end = -1.0;
increment = 0.0;
}
double offset;
LocalTimeOffset offset;
double start;
double end;
double increment;
......@@ -370,8 +373,7 @@ namespace JSC {
HashSet<JSObject*> stringRecursionCheckVisitedObjects;
double cachedUTCOffset;
DSTOffsetCache dstOffsetCache;
LocalTimeOffsetCache localTimeOffsetCache;
String cachedDateString;
double cachedDateStringValue;
......
2013-05-27 Gavin Barraclough <barraclough@apple.com>
String(new Date(2010,10,1)) is wrong in KRAT, YAKT
https://bugs.webkit.org/show_bug.cgi?id=106750
Reviewed by Darin Adler.
First part of a fix, simplfy date handling code, instead of operating separately
on the UTC-standard and standard-DST offsets, just generate a combined UTC-local
offset (this is what we actually need, and what the OS gives us).
* wtf/DateMath.cpp:
(WTF::calculateUTCOffset):
(WTF::calculateDSTOffset):
- made static, now not called from outside of this file.
(WTF::calculateLocalTimeOffset):
- This combines the 2038 related adjustment from calculateDSTOffset with the
maxUnixTime adjustment from calculateDSTOffsetSimple. Then, if HAVE(TM_GMTOFF)
just call getLocalTime, if not use calculateUTCOffset/calculateDSTOffset.
(WTF::parseDateFromNullTerminatedCharacters):
- call calculateLocalTimeOffset instead of calculateUTCOffset/calculateDSTOffset
* wtf/DateMath.h:
(WTF::LocalTimeOffset::LocalTimeOffset):
(LocalTimeOffset):
(WTF::LocalTimeOffset::operator==):
- new struct type, a tuple of UTC-local offset & isDST flag.
- replaced calculateUTCOffset/calculateDSTOffset with calculateLocalTimeOffset
* wtf/GregorianDateTime.cpp:
(WTF::GregorianDateTime::setToCurrentLocalTime):
- call calculateLocalTimeOffset instead of calculateUTCOffset/calculateDSTOffset
2013-05-27 Patrick Gansterer <paroga@webkit.org>
Use correct stack size on Solaris and OpenBSD
......
......@@ -374,7 +374,9 @@ int equivalentYearForDST(int year)
return year;
}
int32_t calculateUTCOffset()
#if !HAVE(TM_GMTOFF)
static int32_t calculateUTCOffset()
{
#if OS(WINDOWS)
TIME_ZONE_INFORMATION timeZoneInformation;
......@@ -418,28 +420,20 @@ int32_t calculateUTCOffset()
/*
* Get the DST offset for the time passed in.
*/
static double calculateDSTOffsetSimple(double localTimeSeconds, double utcOffset)
static double calculateDSTOffset(time_t localTime, double utcOffset)
{
#if OS(WINCE)
UNUSED_PARAM(localTimeSeconds);
UNUSED_PARAM(utcOffset);
return 0;
#else
if (localTimeSeconds > maxUnixTime)
localTimeSeconds = maxUnixTime;
else if (localTimeSeconds < 0) // Go ahead a day to make localtime work (does not work with 0)
localTimeSeconds += secondsPerDay;
//input is UTC so we have to shift back to local time to determine DST thus the + getUTCOffset()
double offsetTime = (localTimeSeconds * msPerSecond) + utcOffset;
double offsetTime = (localTime * msPerSecond) + utcOffset;
// Offset from UTC but doesn't include DST obviously
int offsetHour = msToHours(offsetTime);
int offsetMinute = msToMinutes(offsetTime);
// FIXME: time_t has a potential problem in 2038
time_t localTime = static_cast<time_t>(localTimeSeconds);
tm localTM;
getLocalTime(&localTime, &localTM);
......@@ -452,10 +446,12 @@ static double calculateDSTOffsetSimple(double localTimeSeconds, double utcOffset
#endif
}
// Get the DST offset, given a time in UTC
double calculateDSTOffset(double ms, double utcOffset)
#endif
// Returns combined offset in millisecond (UTC + DST).
LocalTimeOffset calculateLocalTimeOffset(double ms)
{
// On Mac OS X, the call to localtime (see calculateDSTOffsetSimple) will return historically accurate
// On Mac OS X, the call to localtime (see calculateDSTOffset) will return historically accurate
// DST information (e.g. New Zealand did not have DST from 1946 to 1974) however the JavaScript
// standard explicitly dictates that historical information should not be considered when
// determining DST. For this reason we shift away from years that localtime can handle but would
......@@ -471,7 +467,23 @@ double calculateDSTOffset(double ms, double utcOffset)
ms = (day * msPerDay) + msToMilliseconds(ms);
}
return calculateDSTOffsetSimple(ms / msPerSecond, utcOffset);
double localTimeSeconds = ms / msPerSecond;
if (localTimeSeconds > maxUnixTime)
localTimeSeconds = maxUnixTime;
else if (localTimeSeconds < 0) // Go ahead a day to make localtime work (does not work with 0).
localTimeSeconds += secondsPerDay;
// FIXME: time_t has a potential problem in 2038.
time_t localTime = static_cast<time_t>(localTimeSeconds);
#if HAVE(TM_GMTOFF)
tm localTM;
getLocalTime(&localTime, &localTM);
return LocalTimeOffset(localTM.tm_isdst, localTM.tm_gmtoff * msPerSecond);
#else
double utcOffset = calculateUTCOffset();
double dstOffset = calculateDSTOffset(localTime, utcOffset);
return LocalTimeOffset(dstOffset, utcOffset + dstOffset);
#endif
}
void initializeDates()
......@@ -1062,11 +1074,9 @@ double parseDateFromNullTerminatedCharacters(const char* dateString)
return std::numeric_limits<double>::quiet_NaN();
// fall back to local timezone
if (!haveTZ) {
double utcOffset = calculateUTCOffset();
double dstOffset = calculateDSTOffset(ms, utcOffset);
offset = (utcOffset + dstOffset) / msPerMinute;
}
if (!haveTZ)
offset = calculateLocalTimeOffset(ms).offset / msPerMinute;
return ms - (offset * msPerMinute);
}
......
......@@ -55,6 +55,33 @@
namespace WTF {
struct LocalTimeOffset {
LocalTimeOffset()
: isDST(false)
, offset(0)
{
}
LocalTimeOffset(bool isDST, int offset)
: isDST(isDST)
, offset(offset)
{
}
bool operator==(const LocalTimeOffset& other)
{
return isDST == other.isDST && offset == other.offset;
}
bool operator!=(const LocalTimeOffset& other)
{
return isDST != other.isDST || offset != other.offset;
}
bool isDST;
int offset;
};
void initializeDates();
int equivalentYearForDST(int year);
......@@ -99,9 +126,8 @@ 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);
// Returns offset milliseconds for UTC and DST.
WTF_EXPORT_PRIVATE int32_t calculateUTCOffset();
WTF_EXPORT_PRIVATE double calculateDSTOffset(double ms, double utcOffset);
// Returns combined offset in millisecond (UTC + DST).
WTF_EXPORT_PRIVATE LocalTimeOffset calculateLocalTimeOffset(double utcInMilliseconds);
} // namespace WTF
......@@ -122,7 +148,7 @@ using WTF::msToHours;
using WTF::secondsPerMinute;
using WTF::parseDateFromNullTerminatedCharacters;
using WTF::makeRFC2822DateString;
using WTF::calculateUTCOffset;
using WTF::calculateDSTOffset;
using WTF::LocalTimeOffset;
using WTF::calculateLocalTimeOffset;
#endif // DateMath_h
......@@ -78,9 +78,7 @@ void GregorianDateTime::setToCurrentLocalTime()
#if HAVE(TM_GMTOFF)
m_utcOffset = localTM.tm_gmtoff;
#else
int utcOffset = calculateUTCOffset();
utcOffset += calculateDSTOffset(localTime * msPerSecond, utcOffset);
m_utcOffset = utcOffset / msPerSecond;
m_utcOffset = calculateLocalTimeOffset(localTime * msPerSecond).offset / msPerSecond;
#endif
#endif
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment