Fix a race in initialization of timezone cache in platform-win32.
authorulan@chromium.org <ulan@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 14 Mar 2014 15:19:54 +0000 (15:19 +0000)
committerulan@chromium.org <ulan@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 14 Mar 2014 15:19:54 +0000 (15:19 +0000)
This allocates a timezone cache per isolate.

BUG=
R=jochen@chromium.org

Review URL: https://codereview.chromium.org/197023002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19943 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

13 files changed:
src/date.cc
src/date.h
src/platform-cygwin.cc
src/platform-freebsd.cc
src/platform-linux.cc
src/platform-macos.cc
src/platform-openbsd.cc
src/platform-posix.cc
src/platform-qnx.cc
src/platform-solaris.cc
src/platform-win32.cc
src/platform.h
src/runtime.cc

index 4d9cf22..70d6be9 100644 (file)
@@ -62,7 +62,7 @@ void DateCache::ResetDateCache() {
   after_ = &dst_[1];
   local_offset_ms_ = kInvalidLocalOffsetInMs;
   ymd_valid_ = false;
-  OS::TimeZoneChanged();
+  OS::ClearTimezoneCache(tz_cache_);
 }
 
 
index fcd61db..e9c9d9c 100644 (file)
@@ -62,11 +62,14 @@ class DateCache {
   // It is an invariant of DateCache that cache stamp is non-negative.
   static const int kInvalidStamp = -1;
 
-  DateCache() : stamp_(0) {
+  DateCache() : stamp_(0), tz_cache_(OS::CreateTimezoneCache()) {
     ResetDateCache();
   }
 
-  virtual ~DateCache() {}
+  virtual ~DateCache() {
+    OS::DisposeTimezoneCache(tz_cache_);
+    tz_cache_ = NULL;
+  }
 
 
   // Clears cached timezone information and increments the cache stamp.
@@ -113,7 +116,7 @@ class DateCache {
     if (time_ms < 0 || time_ms > kMaxEpochTimeInMs) {
       time_ms = EquivalentTime(time_ms);
     }
-    return OS::LocalTimezone(static_cast<double>(time_ms));
+    return OS::LocalTimezone(static_cast<double>(time_ms), tz_cache_);
   }
 
   // ECMA 262 - 15.9.5.26
@@ -182,11 +185,11 @@ class DateCache {
   // These functions are virtual so that we can override them when testing.
   virtual int GetDaylightSavingsOffsetFromOS(int64_t time_sec) {
     double time_ms = static_cast<double>(time_sec * 1000);
-    return static_cast<int>(OS::DaylightSavingsOffset(time_ms));
+    return static_cast<int>(OS::DaylightSavingsOffset(time_ms, tz_cache_));
   }
 
   virtual int GetLocalOffsetFromOS() {
-    double offset = OS::LocalTimeOffset();
+    double offset = OS::LocalTimeOffset(tz_cache_);
     ASSERT(offset < kInvalidLocalOffsetInMs);
     return static_cast<int>(offset);
   }
@@ -253,6 +256,8 @@ class DateCache {
   int ymd_year_;
   int ymd_month_;
   int ymd_day_;
+
+  TimezoneCache* tz_cache_;
 };
 
 } }   // namespace v8::internal
index ac80439..4ae9bec 100644 (file)
@@ -51,7 +51,7 @@ namespace v8 {
 namespace internal {
 
 
-const char* OS::LocalTimezone(double time) {
+const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
   if (std::isnan(time)) return "";
   time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
   struct tm* t = localtime(&tv);
@@ -60,7 +60,7 @@ const char* OS::LocalTimezone(double time) {
 }
 
 
-double OS::LocalTimeOffset() {
+double OS::LocalTimeOffset(TimezoneCache* cache) {
   // On Cygwin, struct tm does not contain a tm_gmtoff field.
   time_t utc = time(NULL);
   ASSERT(utc != -1);
index 9ab6583..7d15cef 100644 (file)
@@ -61,7 +61,7 @@ namespace v8 {
 namespace internal {
 
 
-const char* OS::LocalTimezone(double time) {
+const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
   if (std::isnan(time)) return "";
   time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
   struct tm* t = localtime(&tv);
@@ -70,7 +70,7 @@ const char* OS::LocalTimezone(double time) {
 }
 
 
-double OS::LocalTimeOffset() {
+double OS::LocalTimeOffset(TimezoneCache* cache) {
   time_t tv = time(NULL);
   struct tm* t = localtime(&tv);
   // tm_gmtoff includes any daylight savings offset, so subtract it.
index b35cd28..527b9f6 100644 (file)
@@ -118,7 +118,7 @@ bool OS::ArmUsingHardFloat() {
 #endif  // def __arm__
 
 
-const char* OS::LocalTimezone(double time) {
+const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
   if (std::isnan(time)) return "";
   time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
   struct tm* t = localtime(&tv);
@@ -127,7 +127,7 @@ const char* OS::LocalTimezone(double time) {
 }
 
 
-double OS::LocalTimeOffset() {
+double OS::LocalTimeOffset(TimezoneCache* cache) {
   time_t tv = time(NULL);
   struct tm* t = localtime(&tv);
   // tm_gmtoff includes any daylight savings offset, so subtract it.
index 683a04d..25ba0da 100644 (file)
@@ -182,7 +182,7 @@ void OS::SignalCodeMovingGC() {
 }
 
 
-const char* OS::LocalTimezone(double time) {
+const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
   if (std::isnan(time)) return "";
   time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
   struct tm* t = localtime(&tv);
@@ -191,7 +191,7 @@ const char* OS::LocalTimezone(double time) {
 }
 
 
-double OS::LocalTimeOffset() {
+double OS::LocalTimeOffset(TimezoneCache* cache) {
   time_t tv = time(NULL);
   struct tm* t = localtime(&tv);
   // tm_gmtoff includes any daylight savings offset, so subtract it.
index c881d47..a5d477d 100644 (file)
@@ -59,7 +59,7 @@ namespace v8 {
 namespace internal {
 
 
-const char* OS::LocalTimezone(double time) {
+const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
   if (std::isnan(time)) return "";
   time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
   struct tm* t = localtime(&tv);
@@ -68,7 +68,7 @@ const char* OS::LocalTimezone(double time) {
 }
 
 
-double OS::LocalTimeOffset() {
+double OS::LocalTimeOffset(TimezoneCache* cache) {
   time_t tv = time(NULL);
   struct tm* t = localtime(&tv);
   // tm_gmtoff includes any daylight savings offset, so subtract it.
index 439140a..c301eae 100644 (file)
@@ -354,7 +354,25 @@ double OS::TimeCurrentMillis() {
 }
 
 
-double OS::DaylightSavingsOffset(double time) {
+class TimezoneCache {};
+
+
+TimezoneCache* OS::CreateTimezoneCache() {
+  return NULL;
+}
+
+
+void OS::DisposeTimezoneCache(TimezoneCache* cache) {
+  ASSERT(cache == NULL);
+}
+
+
+void OS::ClearTimezoneCache(TimezoneCache* cache) {
+  ASSERT(cache == NULL);
+}
+
+
+double OS::DaylightSavingsOffset(double time, TimezoneCache*) {
   if (std::isnan(time)) return nan_value();
   time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
   struct tm* t = localtime(&tv);
@@ -363,9 +381,6 @@ double OS::DaylightSavingsOffset(double time) {
 }
 
 
-void OS::TimeZoneChanged() {}
-
-
 int OS::GetLastError() {
   return errno;
 }
index cd031e7..ef0998f 100644 (file)
@@ -110,7 +110,7 @@ bool OS::ArmUsingHardFloat() {
 #endif  // __arm__
 
 
-const char* OS::LocalTimezone(double time) {
+const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
   if (std::isnan(time)) return "";
   time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
   struct tm* t = localtime(&tv);
@@ -119,7 +119,7 @@ const char* OS::LocalTimezone(double time) {
 }
 
 
-double OS::LocalTimeOffset() {
+double OS::LocalTimeOffset(TimezoneCache* cache) {
   time_t tv = time(NULL);
   struct tm* t = localtime(&tv);
   // tm_gmtoff includes any daylight savings offset, so subtract it.
index 4d910d4..f23ae08 100644 (file)
@@ -80,7 +80,7 @@ namespace v8 {
 namespace internal {
 
 
-const char* OS::LocalTimezone(double time) {
+const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
   if (std::isnan(time)) return "";
   time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
   struct tm* t = localtime(&tv);
@@ -89,7 +89,7 @@ const char* OS::LocalTimezone(double time) {
 }
 
 
-double OS::LocalTimeOffset() {
+double OS::LocalTimeOffset(TimezoneCache* cache) {
   tzset();
   return -static_cast<double>(timezone * msPerSecond);
 }
index afcd82b..fe84bcd 100644 (file)
@@ -218,6 +218,97 @@ void MathSetup() {
 }
 
 
+class TimezoneCache {
+ public:
+  TimezoneCache() : initialized_(false) { }
+
+  void Clear() {
+    initialized_ = false;
+  }
+
+  // Initialize timezone information. The timezone information is obtained from
+  // windows. If we cannot get the timezone information we fall back to CET.
+  void InitializeIfNeeded() {
+    // Just return if timezone information has already been initialized.
+    if (initialized_) return;
+
+    // Initialize POSIX time zone data.
+    _tzset();
+    // Obtain timezone information from operating system.
+    memset(&tzinfo_, 0, sizeof(tzinfo_));
+    if (GetTimeZoneInformation(&tzinfo_) == TIME_ZONE_ID_INVALID) {
+      // If we cannot get timezone information we fall back to CET.
+      tzinfo_.Bias = -60;
+      tzinfo_.StandardDate.wMonth = 10;
+      tzinfo_.StandardDate.wDay = 5;
+      tzinfo_.StandardDate.wHour = 3;
+      tzinfo_.StandardBias = 0;
+      tzinfo_.DaylightDate.wMonth = 3;
+      tzinfo_.DaylightDate.wDay = 5;
+      tzinfo_.DaylightDate.wHour = 2;
+      tzinfo_.DaylightBias = -60;
+    }
+
+    // Make standard and DST timezone names.
+    WideCharToMultiByte(CP_UTF8, 0, tzinfo_.StandardName, -1,
+                        std_tz_name_, kTzNameSize, NULL, NULL);
+    std_tz_name_[kTzNameSize - 1] = '\0';
+    WideCharToMultiByte(CP_UTF8, 0, tzinfo_.DaylightName, -1,
+                        dst_tz_name_, kTzNameSize, NULL, NULL);
+    dst_tz_name_[kTzNameSize - 1] = '\0';
+
+    // If OS returned empty string or resource id (like "@tzres.dll,-211")
+    // simply guess the name from the UTC bias of the timezone.
+    // To properly resolve the resource identifier requires a library load,
+    // which is not possible in a sandbox.
+    if (std_tz_name_[0] == '\0' || std_tz_name_[0] == '@') {
+      OS::SNPrintF(Vector<char>(std_tz_name_, kTzNameSize - 1),
+                   "%s Standard Time",
+                   GuessTimezoneNameFromBias(tzinfo_.Bias));
+    }
+    if (dst_tz_name_[0] == '\0' || dst_tz_name_[0] == '@') {
+      OS::SNPrintF(Vector<char>(dst_tz_name_, kTzNameSize - 1),
+                   "%s Daylight Time",
+                   GuessTimezoneNameFromBias(tzinfo_.Bias));
+    }
+    // Timezone information initialized.
+    initialized_ = true;
+  }
+
+  // Guess the name of the timezone from the bias.
+  // The guess is very biased towards the northern hemisphere.
+  const char* GuessTimezoneNameFromBias(int bias) {
+    static const int kHour = 60;
+    switch (-bias) {
+      case -9*kHour: return "Alaska";
+      case -8*kHour: return "Pacific";
+      case -7*kHour: return "Mountain";
+      case -6*kHour: return "Central";
+      case -5*kHour: return "Eastern";
+      case -4*kHour: return "Atlantic";
+      case  0*kHour: return "GMT";
+      case +1*kHour: return "Central Europe";
+      case +2*kHour: return "Eastern Europe";
+      case +3*kHour: return "Russia";
+      case +5*kHour + 30: return "India";
+      case +8*kHour: return "China";
+      case +9*kHour: return "Japan";
+      case +12*kHour: return "New Zealand";
+      default: return "Local";
+    }
+  }
+
+
+ private:
+  static const int kTzNameSize = 128;
+  bool initialized_;
+  char std_tz_name_[kTzNameSize];
+  char dst_tz_name_[kTzNameSize];
+  TIME_ZONE_INFORMATION tzinfo_;
+  friend class Win32Time;
+};
+
+
 // ----------------------------------------------------------------------------
 // The Time class represents time on win32. A timestamp is represented as
 // a 64-bit integer in 100 nanoseconds since January 1, 1601 (UTC). JavaScript
@@ -242,16 +333,14 @@ class Win32Time {
   // LocalOffset(CET) = 3600000 and LocalOffset(PST) = -28800000. This
   // routine also takes into account whether daylight saving is effect
   // at the time.
-  int64_t LocalOffset();
+  int64_t LocalOffset(TimezoneCache* cache);
 
   // Returns the daylight savings time offset for the time in milliseconds.
-  int64_t DaylightSavingsOffset();
+  int64_t DaylightSavingsOffset(TimezoneCache* cache);
 
   // Returns a string identifying the current timezone for the
   // timestamp taking into account daylight saving.
-  char* LocalTimezone();
-
-  static void TimeZoneChanged() { tz_initialized_ = false; }
+  char* LocalTimezone(TimezoneCache* cache);
 
  private:
   // Constants for time conversion.
@@ -260,25 +349,10 @@ class Win32Time {
   static const int64_t kMsPerMinute = 60000;
 
   // Constants for timezone information.
-  static const int kTzNameSize = 128;
   static const bool kShortTzNames = false;
 
-  // Timezone information. We need to have static buffers for the
-  // timezone names because we return pointers to these in
-  // LocalTimezone().
-  static bool tz_initialized_;
-  static TIME_ZONE_INFORMATION tzinfo_;
-  static char std_tz_name_[kTzNameSize];
-  static char dst_tz_name_[kTzNameSize];
-
-  // Initialize the timezone information (if not already done).
-  static void TzSet();
-
-  // Guess the name of the timezone from the bias.
-  static const char* GuessTimezoneNameFromBias(int bias);
-
   // Return whether or not daylight savings time is in effect at this time.
-  bool InDST();
+  bool InDST(TimezoneCache* cache);
 
   // Accessor for FILETIME representation.
   FILETIME& ft() { return time_.ft_; }
@@ -300,13 +374,6 @@ class Win32Time {
 };
 
 
-// Static variables.
-bool Win32Time::tz_initialized_ = false;
-TIME_ZONE_INFORMATION Win32Time::tzinfo_;
-char Win32Time::std_tz_name_[kTzNameSize];
-char Win32Time::dst_tz_name_[kTzNameSize];
-
-
 // Initialize timestamp to start of epoc.
 Win32Time::Win32Time() {
   t() = 0;
@@ -395,90 +462,13 @@ void Win32Time::SetToCurrentTime() {
 }
 
 
-// Guess the name of the timezone from the bias.
-// The guess is very biased towards the northern hemisphere.
-const char* Win32Time::GuessTimezoneNameFromBias(int bias) {
-  static const int kHour = 60;
-  switch (-bias) {
-    case -9*kHour: return "Alaska";
-    case -8*kHour: return "Pacific";
-    case -7*kHour: return "Mountain";
-    case -6*kHour: return "Central";
-    case -5*kHour: return "Eastern";
-    case -4*kHour: return "Atlantic";
-    case  0*kHour: return "GMT";
-    case +1*kHour: return "Central Europe";
-    case +2*kHour: return "Eastern Europe";
-    case +3*kHour: return "Russia";
-    case +5*kHour + 30: return "India";
-    case +8*kHour: return "China";
-    case +9*kHour: return "Japan";
-    case +12*kHour: return "New Zealand";
-    default: return "Local";
-  }
-}
-
-
-// Initialize timezone information. The timezone information is obtained from
-// windows. If we cannot get the timezone information we fall back to CET.
-// Please notice that this code is not thread-safe.
-void Win32Time::TzSet() {
-  // Just return if timezone information has already been initialized.
-  if (tz_initialized_) return;
-
-  // Initialize POSIX time zone data.
-  _tzset();
-  // Obtain timezone information from operating system.
-  memset(&tzinfo_, 0, sizeof(tzinfo_));
-  if (GetTimeZoneInformation(&tzinfo_) == TIME_ZONE_ID_INVALID) {
-    // If we cannot get timezone information we fall back to CET.
-    tzinfo_.Bias = -60;
-    tzinfo_.StandardDate.wMonth = 10;
-    tzinfo_.StandardDate.wDay = 5;
-    tzinfo_.StandardDate.wHour = 3;
-    tzinfo_.StandardBias = 0;
-    tzinfo_.DaylightDate.wMonth = 3;
-    tzinfo_.DaylightDate.wDay = 5;
-    tzinfo_.DaylightDate.wHour = 2;
-    tzinfo_.DaylightBias = -60;
-  }
-
-  // Make standard and DST timezone names.
-  WideCharToMultiByte(CP_UTF8, 0, tzinfo_.StandardName, -1,
-                      std_tz_name_, kTzNameSize, NULL, NULL);
-  std_tz_name_[kTzNameSize - 1] = '\0';
-  WideCharToMultiByte(CP_UTF8, 0, tzinfo_.DaylightName, -1,
-                      dst_tz_name_, kTzNameSize, NULL, NULL);
-  dst_tz_name_[kTzNameSize - 1] = '\0';
-
-  // If OS returned empty string or resource id (like "@tzres.dll,-211")
-  // simply guess the name from the UTC bias of the timezone.
-  // To properly resolve the resource identifier requires a library load,
-  // which is not possible in a sandbox.
-  if (std_tz_name_[0] == '\0' || std_tz_name_[0] == '@') {
-    OS::SNPrintF(Vector<char>(std_tz_name_, kTzNameSize - 1),
-                 "%s Standard Time",
-                 GuessTimezoneNameFromBias(tzinfo_.Bias));
-  }
-  if (dst_tz_name_[0] == '\0' || dst_tz_name_[0] == '@') {
-    OS::SNPrintF(Vector<char>(dst_tz_name_, kTzNameSize - 1),
-                 "%s Daylight Time",
-                 GuessTimezoneNameFromBias(tzinfo_.Bias));
-  }
-
-  // Timezone information initialized.
-  tz_initialized_ = true;
-}
-
-
 // Return the local timezone offset in milliseconds east of UTC. This
 // takes into account whether daylight saving is in effect at the time.
 // Only times in the 32-bit Unix range may be passed to this function.
 // Also, adding the time-zone offset to the input must not overflow.
 // The function EquivalentTime() in date.js guarantees this.
-int64_t Win32Time::LocalOffset() {
-  // Initialize timezone information, if needed.
-  TzSet();
+int64_t Win32Time::LocalOffset(TimezoneCache* cache) {
+  cache->InitializeIfNeeded();
 
   Win32Time rounded_to_second(*this);
   rounded_to_second.t() = rounded_to_second.t() / 1000 / kTimeScaler *
@@ -501,29 +491,30 @@ int64_t Win32Time::LocalOffset() {
   if (localtime_s(&posix_local_time_struct, &posix_time)) return 0;
 
   if (posix_local_time_struct.tm_isdst > 0) {
-    return (tzinfo_.Bias + tzinfo_.DaylightBias) * -kMsPerMinute;
+    return (cache->tzinfo_.Bias + cache->tzinfo_.DaylightBias) * -kMsPerMinute;
   } else if (posix_local_time_struct.tm_isdst == 0) {
-    return (tzinfo_.Bias + tzinfo_.StandardBias) * -kMsPerMinute;
+    return (cache->tzinfo_.Bias + cache->tzinfo_.StandardBias) * -kMsPerMinute;
   } else {
-    return tzinfo_.Bias * -kMsPerMinute;
+    return cache->tzinfo_.Bias * -kMsPerMinute;
   }
 }
 
 
 // Return whether or not daylight savings time is in effect at this time.
-bool Win32Time::InDST() {
-  // Initialize timezone information, if needed.
-  TzSet();
+bool Win32Time::InDST(TimezoneCache* cache) {
+  cache->InitializeIfNeeded();
 
   // Determine if DST is in effect at the specified time.
   bool in_dst = false;
-  if (tzinfo_.StandardDate.wMonth != 0 || tzinfo_.DaylightDate.wMonth != 0) {
+  if (cache->tzinfo_.StandardDate.wMonth != 0 ||
+      cache->tzinfo_.DaylightDate.wMonth != 0) {
     // Get the local timezone offset for the timestamp in milliseconds.
-    int64_t offset = LocalOffset();
+    int64_t offset = LocalOffset(cache);
 
     // Compute the offset for DST. The bias parameters in the timezone info
     // are specified in minutes. These must be converted to milliseconds.
-    int64_t dstofs = -(tzinfo_.Bias + tzinfo_.DaylightBias) * kMsPerMinute;
+    int64_t dstofs =
+        -(cache->tzinfo_.Bias + cache->tzinfo_.DaylightBias) * kMsPerMinute;
 
     // If the local time offset equals the timezone bias plus the daylight
     // bias then DST is in effect.
@@ -535,17 +526,17 @@ bool Win32Time::InDST() {
 
 
 // Return the daylight savings time offset for this time.
-int64_t Win32Time::DaylightSavingsOffset() {
-  return InDST() ? 60 * kMsPerMinute : 0;
+int64_t Win32Time::DaylightSavingsOffset(TimezoneCache* cache) {
+  return InDST(cache) ? 60 * kMsPerMinute : 0;
 }
 
 
 // Returns a string identifying the current timezone for the
 // timestamp taking into account daylight saving.
-char* Win32Time::LocalTimezone() {
+char* Win32Time::LocalTimezone(TimezoneCache* cache) {
   // Return the standard or DST time zone name based on whether daylight
   // saving is in effect at the given time.
-  return InDST() ? dst_tz_name_ : std_tz_name_;
+  return InDST(cache) ? cache->dst_tz_name_ : cache->std_tz_name_;
 }
 
 
@@ -588,36 +579,47 @@ double OS::TimeCurrentMillis() {
 }
 
 
+TimezoneCache* OS::CreateTimezoneCache() {
+  return new TimezoneCache();
+}
+
+
+void OS::DisposeTimezoneCache(TimezoneCache* cache) {
+  delete cache;
+}
+
+
+void OS::ClearTimezoneCache(TimezoneCache* cache) {
+  cache->Clear();
+}
+
+
 // Returns a string identifying the current timezone taking into
 // account daylight saving.
-const char* OS::LocalTimezone(double time) {
-  return Win32Time(time).LocalTimezone();
+const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
+  return Win32Time(time).LocalTimezone(cache);
 }
 
 
 // Returns the local time offset in milliseconds east of UTC without
 // taking daylight savings time into account.
-double OS::LocalTimeOffset() {
+double OS::LocalTimeOffset(TimezoneCache* cache) {
   // Use current time, rounded to the millisecond.
   Win32Time t(TimeCurrentMillis());
   // Time::LocalOffset inlcudes any daylight savings offset, so subtract it.
-  return static_cast<double>(t.LocalOffset() - t.DaylightSavingsOffset());
+  return static_cast<double>(t.LocalOffset(cache) -
+                             t.DaylightSavingsOffset(cache));
 }
 
 
 // Returns the daylight savings offset in milliseconds for the given
 // time.
-double OS::DaylightSavingsOffset(double time) {
-  int64_t offset = Win32Time(time).DaylightSavingsOffset();
+double OS::DaylightSavingsOffset(double time, TimezoneCache* cache) {
+  int64_t offset = Win32Time(time).DaylightSavingsOffset(cache);
   return static_cast<double>(offset);
 }
 
 
-void OS::TimeZoneChanged() {
-  Win32Time::TimeZoneChanged();
-}
-
-
 int OS::GetLastError() {
   return ::GetLastError();
 }
index d424666..d087d23 100644 (file)
@@ -159,6 +159,9 @@ inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
 #endif  // V8_NO_FAST_TLS
 
 
+class TimezoneCache;
+
+
 // ----------------------------------------------------------------------------
 // OS
 //
@@ -182,18 +185,20 @@ class OS {
   // 00:00:00 UTC, January 1, 1970.
   static double TimeCurrentMillis();
 
+  static TimezoneCache* CreateTimezoneCache();
+  static void DisposeTimezoneCache(TimezoneCache* cache);
+  static void ClearTimezoneCache(TimezoneCache* cache);
+
   // Returns a string identifying the current time zone. The
   // timestamp is used for determining if DST is in effect.
-  static const char* LocalTimezone(double time);
+  static const char* LocalTimezone(double time, TimezoneCache* cache);
 
   // Returns the local time offset in milliseconds east of UTC without
   // taking daylight savings time into account.
-  static double LocalTimeOffset();
+  static double LocalTimeOffset(TimezoneCache* cache);
 
   // Returns the daylight savings offset for the given time.
-  static double DaylightSavingsOffset(double time);
-
-  static void TimeZoneChanged();
+  static double DaylightSavingsOffset(double time, TimezoneCache* cache);
 
   // Returns last OS error.
   static int GetLastError();
index b9dc418..02be8a6 100644 (file)
@@ -9583,8 +9583,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
   ASSERT(args.length() == 1);
 
   CONVERT_DOUBLE_ARG_CHECKED(x, 0);
-  int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
-  const char* zone = OS::LocalTimezone(static_cast<double>(time));
+  const char* zone =
+      isolate->date_cache()->LocalTimezone(static_cast<int64_t>(x));
   return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
 }