Ignore:
Timestamp:
Nov 5, 2009, 10:26:47 PM (16 years ago)
Author:
[email protected]
Message:

JavaScriptCore: https://bugs.webkit.org/show_bug.cgi?id=31197
Implemented a timezone cache not based on Mac OS X's notify_check API.

Patch by Geoffrey Garen <[email protected]> on 2009-11-05
Reviewed by Oliver Hunt.

If the VM calculates the local timezone offset from UTC, it caches the
result until the end of the current VM invocation. (We don't want to cache
forever, because the user's timezone may change over time.)

This removes notify_* overhead on Mac, and, more significantly, removes
OS time and date call overhead on non-Mac platforms.

~8% speedup on Date microbenchmark on Mac. SunSpider reports maybe a tiny
speedup on Mac. (Speedup on non-Mac platforms should be even more noticeable.)

  • interpreter/CachedCall.h:

(JSC::CachedCall::CachedCall):

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::execute):

  • runtime/JSGlobalObject.h:

(JSC::DynamicGlobalObjectScope::DynamicGlobalObjectScope): Made the
DynamicGlobalObjectScope constructor responsible for checking whether a
dynamicGlobalObject has already been set. This eliminated some duplicate
client code, and allowed me to avoid adding even more duplicate client
code. Made DynamicGlobalObjectScope responsible for resetting the
local timezone cache upon first entry to the VM.

  • runtime/DateConstructor.cpp:

(JSC::constructDate):
(JSC::callDate):
(JSC::dateParse):
(JSC::dateUTC):

  • runtime/DateConversion.cpp:

(JSC::parseDate):

  • runtime/DateConversion.h:
  • runtime/DateInstance.cpp:

(JSC::DateInstance::gregorianDateTime):

  • runtime/DateInstance.h:
  • runtime/DateInstanceCache.h:
  • runtime/DatePrototype.cpp:

(JSC::setNewValueFromTimeArgs):
(JSC::setNewValueFromDateArgs):
(JSC::dateProtoFuncSetYear):

  • runtime/InitializeThreading.cpp:

(JSC::initializeThreadingOnce):

  • runtime/JSGlobalData.cpp:

(JSC::JSGlobalData::JSGlobalData):

  • runtime/JSGlobalData.h:
  • wtf/DateMath.cpp:

(WTF::getCurrentUTCTime):
(WTF::getCurrentUTCTimeWithMicroseconds):
(WTF::getLocalTime):
(JSC::getUTCOffset): Use the new cache. Also, see below.
(JSC::gregorianDateTimeToMS):
(JSC::msToGregorianDateTime):
(JSC::initializeDates):
(JSC::parseDateFromNullTerminatedCharacters): Simplified the way this function
accounts for the local timezone offset, to accomodate our new caching API,
and a (possibly misguided) caller in WebCore. Also, see below.

  • wtf/DateMath.h:

(JSC::GregorianDateTime::GregorianDateTime): Moved most of the code in
DateMath.* into the JSC namespace. The code needed to move so it could
naturally interact with ExecState and JSGlobalData to support caching.
Logically, it seemed right to move it, too, since this code is not really
as low-level as the WTF namespace might imply -- it implements a set of
date parsing and conversion quirks that are finely tuned to the JavaScript
language. Also removed the Mac OS X notify_* infrastructure.

WebCore: https://bugs.webkit.org/show_bug.cgi?id=31197
Implemented a timezone cache not based on Mac OS X's notify_check API.

Patch by Geoffrey Garen <[email protected]> on 2009-11-05
Updated for JavaScriptCore internal API change.

  • platform/network/HTTPParsers.cpp:

(WebCore::parseDate): Pass 0 for ExecState, since we don't have one.
(This function probably shouldn't be using a JavaScript date parser
to begin with, but oh well.)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/wtf/DateMath.cpp

    r50183 r50590  
    5151#include "StringExtras.h"
    5252
     53#include "CallFrame.h"
     54
    5355#include <algorithm>
    5456#include <limits.h>
     
    6264#endif
    6365
    64 #if PLATFORM(DARWIN)
    65 #include <notify.h>
    66 #endif
    67 
    6866#if PLATFORM(WINCE)
    6967extern "C" size_t strftime(char * const s, const size_t maxsize, const char * const format, const struct tm * const t);
     
    8280
    8381namespace WTF {
     82
     83double getCurrentUTCTime()
     84{
     85    return floor(getCurrentUTCTimeWithMicroseconds());
     86}
     87
     88// Returns current time in milliseconds since 1 Jan 1970.
     89double getCurrentUTCTimeWithMicroseconds()
     90{
     91    return currentTime() * 1000.0;
     92}
     93
     94void getLocalTime(const time_t* localTime, struct tm* localTM)
     95{
     96#if COMPILER(MSVC7) || COMPILER(MINGW) || PLATFORM(WINCE)
     97    *localTM = *localtime(localTime);
     98#elif COMPILER(MSVC)
     99    localtime_s(localTM, localTime);
     100#else
     101    localtime_r(localTime, localTM);
     102#endif
     103}
     104
     105} // namespace WTF
     106
     107using namespace WTF;
     108
     109namespace JSC {
    84110
    85111/* Constants */
     
    294320}
    295321
    296 double getCurrentUTCTime()
    297 {
    298     return floor(getCurrentUTCTimeWithMicroseconds());
    299 }
    300 
    301 // Returns current time in milliseconds since 1 Jan 1970.
    302 double getCurrentUTCTimeWithMicroseconds()
    303 {
    304     return currentTime() * 1000.0;
    305 }
    306 
    307 void getLocalTime(const time_t* localTime, struct tm* localTM)
    308 {
    309 #if COMPILER(MSVC7) || COMPILER(MINGW) || PLATFORM(WINCE)
    310     *localTM = *localtime(localTime);
    311 #elif COMPILER(MSVC)
    312     localtime_s(localTM, localTime);
    313 #else
    314     localtime_r(localTime, localTM);
    315 #endif
    316 }
    317 
    318322// There is a hard limit at 2038 that we currently do not have a workaround
    319323// for (rdar://problem/5052975).
     
    400404}
    401405
    402 #if PLATFORM(DARWIN)
    403 static int32_t s_cachedUTCOffset; // In milliseconds. An assumption here is that access to an int32_t variable is atomic on platforms that take this code path.
    404 static bool s_haveCachedUTCOffset;
    405 static int s_notificationToken;
    406 #endif
    407 
    408406/*
    409407 * Get the difference in milliseconds between this time zone and UTC (GMT)
    410408 * NOT including DST.
    411409 */
    412 double getUTCOffset()
    413 {
    414 #if PLATFORM(DARWIN)
    415     if (s_haveCachedUTCOffset) {
    416         int notified;
    417         uint32_t status = notify_check(s_notificationToken, &notified);
    418         if (status == NOTIFY_STATUS_OK && !notified)
    419             return s_cachedUTCOffset;
    420     }
    421 #endif
    422 
    423     int32_t utcOffset = calculateUTCOffset();
    424 
    425 #if PLATFORM(DARWIN)
    426     // Theoretically, it is possible that several threads will be executing this code at once, in which case we will have a race condition,
    427     // and a newer value may be overwritten. In practice, time zones don't change that often.
    428     s_cachedUTCOffset = utcOffset;
    429 #endif
    430 
    431     return utcOffset;
     410double getUTCOffset(ExecState* exec)
     411{
     412    double utcOffset = exec->globalData().cachedUTCOffset;
     413    if (!isnan(utcOffset))
     414        return utcOffset;
     415    exec->globalData().cachedUTCOffset = calculateUTCOffset();
     416    return exec->globalData().cachedUTCOffset;
    432417}
    433418
     
    487472}
    488473
    489 double gregorianDateTimeToMS(const GregorianDateTime& t, double milliSeconds, bool inputIsUTC)
     474double gregorianDateTimeToMS(ExecState* exec, const GregorianDateTime& t, double milliSeconds, bool inputIsUTC)
    490475{
    491476    int day = dateToDayInYear(t.year + 1900, t.month, t.monthDay);
     
    494479
    495480    if (!inputIsUTC) { // convert to UTC
    496         double utcOffset = getUTCOffset();
     481        double utcOffset = getUTCOffset(exec);
    497482        result -= utcOffset;
    498483        result -= getDSTOffset(result, utcOffset);
     
    503488
    504489// input is UTC
    505 void msToGregorianDateTime(double ms, bool outputIsUTC, GregorianDateTime& tm)
     490void msToGregorianDateTime(ExecState* exec, double ms, bool outputIsUTC, GregorianDateTime& tm)
    506491{
    507492    double dstOff = 0.0;
    508493    double utcOff = 0.0;
    509494    if (!outputIsUTC) {
    510         utcOff = getUTCOffset();
     495        utcOff = getUTCOffset(exec);
    511496        dstOff = getDSTOffset(ms, utcOff);
    512497        ms += dstOff + utcOff;
     
    535520
    536521    equivalentYearForDST(2000); // Need to call once to initialize a static used in this function.
    537 #if PLATFORM(DARWIN)
    538     // Register for a notification whenever the time zone changes.
    539     uint32_t status = notify_register_check("com.apple.system.timezone", &s_notificationToken);
    540     if (status == NOTIFY_STATUS_OK) {
    541         s_cachedUTCOffset = calculateUTCOffset();
    542         s_haveCachedUTCOffset = true;
    543     }
    544 #endif
    545522}
    546523
     
    623600}
    624601
    625 double parseDateFromNullTerminatedCharacters(const char* dateString)
     602// Odd case where 'exec' is allowed to be 0, to accomodate a caller in WebCore.
     603double parseDateFromNullTerminatedCharacters(const char* dateString, ExecState* exec)
    626604{
    627605    // This parses a date in the form:
     
    890868            year += 1900;
    891869    }
    892 
     870   
     871    double ms = ymdhmsToSeconds(year, month + 1, day, hour, minute, second) * msPerSecond;
    893872    // fall back to local timezone
    894873    if (!haveTZ) {
    895         GregorianDateTime t;
    896         t.monthDay = day;
    897         t.month = month;
    898         t.year = year - 1900;
    899         t.isDST = -1;
    900         t.second = second;
    901         t.minute = minute;
    902         t.hour = hour;
    903 
    904         // Use our gregorianDateTimeToMS() rather than mktime() as the latter can't handle the full year range.
    905         return gregorianDateTimeToMS(t, 0, false);
    906     }
    907 
    908     return (ymdhmsToSeconds(year, month + 1, day, hour, minute, second) - (offset * 60.0)) * msPerSecond;
     874        if (exec) {
     875            double utcOffset = getUTCOffset(exec);
     876            double dstOffset = getDSTOffset(ms, utcOffset);
     877            offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
     878        } else {
     879            double utcOffset = calculateUTCOffset();
     880            double dstOffset = getDSTOffset(ms, utcOffset);
     881            offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
     882        }
     883    }
     884
     885    return ms - (offset * msPerMinute);
    909886}
    910887
     
    919896
    920897
    921 } // namespace WTF
     898} // namespace JSC
Note: See TracChangeset for help on using the changeset viewer.