Bug 1346211 - Part 3: Only refresh ICU default time zone after time zone change was observed. r=Waldo
authorAndré Bargull <andre.bargull@gmail.com>
Thu, 16 Aug 2018 08:27:54 -0700
changeset 487324 7cad19d2d2d9368d130b78f2d8cf18ecf39b3c9b
parent 487323 62d58886e8d759f52c871a82dbe4d9c2a266c0c7
child 487325 fe6637fcb77005211e23c8adb38ac32dbbbb4414
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs1346211
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1346211 - Part 3: Only refresh ICU default time zone after time zone change was observed. r=Waldo
js/src/vm/DateTime.cpp
js/src/vm/DateTime.h
--- a/js/src/vm/DateTime.cpp
+++ b/js/src/vm/DateTime.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "vm/DateTime.h"
 
+#include "mozilla/Unused.h"
+
 #if defined(XP_WIN)
 #include "mozilla/UniquePtr.h"
 
 #include <cstdlib>
 #include <cstring>
 #endif /* defined(XP_WIN) */
 #include <time.h>
 
@@ -137,42 +139,44 @@ UTCToLocalStandardOffsetSeconds()
     if (utc_secs > local_secs)
         return (SecondsPerDay + local_secs) - utc_secs;
 
     // Otherwise we have more local seconds, so move the UTC seconds into the
     // local seconds' frame of reference and then subtract.
     return local_secs - (utc_secs + SecondsPerDay);
 }
 
-void
+bool
 js::DateTimeInfo::internalUpdateTimeZoneAdjustment(ResetTimeZoneMode mode)
 {
     /*
      * The difference between local standard time and UTC will never change for
      * a given time zone.
      */
     utcToLocalStandardOffsetSeconds = UTCToLocalStandardOffsetSeconds();
 
     double newTZA = utcToLocalStandardOffsetSeconds * msPerSecond;
     if (mode == ResetTimeZoneMode::DontResetIfOffsetUnchanged && newTZA == localTZA_)
-        return;
+        return false;
 
     localTZA_ = newTZA;
 
     /*
      * The initial range values are carefully chosen to result in a cache miss
      * on first use given the range of possible values.  Be careful to keep
      * these values and the caching algorithm in sync!
      */
     offsetMilliseconds = 0;
     rangeStartSeconds = rangeEndSeconds = INT64_MIN;
     oldOffsetMilliseconds = 0;
     oldRangeStartSeconds = oldRangeEndSeconds = INT64_MIN;
 
     sanityCheck();
+
+    return true;
 }
 
 js::DateTimeInfo::DateTimeInfo()
 {
     internalUpdateTimeZoneAdjustment(ResetTimeZoneMode::ResetEvenIfOffsetUnchaged);
 }
 
 int64_t
@@ -290,31 +294,50 @@ js::DateTimeInfo::sanityCheck()
 }
 
 /* static */ js::ExclusiveData<js::DateTimeInfo>*
 js::DateTimeInfo::instance;
 
 /* static */ js::ExclusiveData<js::IcuTimeZoneStatus>*
 js::IcuTimeZoneState;
 
+#if defined(XP_WIN)
+static bool
+IsOlsonCompatibleWindowsTimeZoneId(const char* tz);
+#endif
+
 bool
 js::InitDateTimeState()
 {
 
     MOZ_ASSERT(!DateTimeInfo::instance,
                "we should be initializing only once");
 
     DateTimeInfo::instance = js_new<ExclusiveData<DateTimeInfo>>(mutexid::DateTimeInfoMutex);
     if (!DateTimeInfo::instance)
         return false;
 
     MOZ_ASSERT(!IcuTimeZoneState,
                "we should be initializing only once");
 
-    IcuTimeZoneState = js_new<ExclusiveData<IcuTimeZoneStatus>>(mutexid::IcuTimeZoneStateMutex);
+    IcuTimeZoneStatus initialStatus = IcuTimeZoneStatus::Valid;
+
+#if defined(XP_WIN)
+    // Directly set the ICU time zone status into the invalid state when we
+    // need to compute the actual default time zone from the TZ environment
+    // variable. We don't yet want to initialize ICU's time zone classes,
+    // because that may cause I/O operations slowing down the JS engine
+    // initialization, which we're currently in the middle of.
+    const char* tz = std::getenv("TZ");
+    if (tz && IsOlsonCompatibleWindowsTimeZoneId(tz))
+        initialStatus = IcuTimeZoneStatus::NeedsUpdate;
+#endif
+
+    IcuTimeZoneState = js_new<ExclusiveData<IcuTimeZoneStatus>>(mutexid::IcuTimeZoneStateMutex,
+                                                                initialStatus);
     if (!IcuTimeZoneState) {
         js_delete(DateTimeInfo::instance);
         DateTimeInfo::instance = nullptr;
         return false;
     }
 
     return true;
 }
@@ -327,21 +350,25 @@ js::FinishDateTimeState()
 
     js_delete(DateTimeInfo::instance);
     DateTimeInfo::instance = nullptr;
 }
 
 void
 js::ResetTimeZoneInternal(ResetTimeZoneMode mode)
 {
-    js::DateTimeInfo::updateTimeZoneAdjustment(mode);
+    bool needsUpdate = js::DateTimeInfo::updateTimeZoneAdjustment(mode);
 
 #if ENABLE_INTL_API && defined(ICU_TZ_HAS_RECREATE_DEFAULT)
-    auto guard = js::IcuTimeZoneState->lock();
-    guard.get() = js::IcuTimeZoneStatus::NeedsUpdate;
+    if (needsUpdate) {
+        auto guard = js::IcuTimeZoneState->lock();
+        guard.get() = js::IcuTimeZoneStatus::NeedsUpdate;
+    }
+#else
+    mozilla::Unused << needsUpdate;
 #endif
 }
 
 JS_PUBLIC_API(void)
 JS::ResetTimeZone()
 {
     js::ResetTimeZoneInternal(js::ResetTimeZoneMode::ResetEvenIfOffsetUnchaged);
 }
--- a/js/src/vm/DateTime.h
+++ b/js/src/vm/DateTime.h
@@ -139,19 +139,20 @@ class DateTimeInfo
 
   private:
     // We don't want anyone accidentally calling *only*
     // DateTimeInfo::updateTimeZoneAdjustment() to respond to a system time
     // zone change (missing the necessary poking of ICU as well), so ensure
     // only js::ResetTimeZoneInternal() can call this via access restrictions.
     friend void js::ResetTimeZoneInternal(ResetTimeZoneMode);
 
-    static void updateTimeZoneAdjustment(ResetTimeZoneMode mode) {
+    // Returns true iff the internal DST offset cache was purged.
+    static bool updateTimeZoneAdjustment(ResetTimeZoneMode mode) {
         auto guard = instance->lock();
-        guard->internalUpdateTimeZoneAdjustment(mode);
+        return guard->internalUpdateTimeZoneAdjustment(mode);
     }
 
     /*
      * The current local time zone adjustment, cached because retrieving this
      * dynamically is Slow, and a certain venerable benchmark which shall not
      * be named depends on it being fast.
      *
      * SpiderMonkey occasionally and arbitrarily updates this value from the
@@ -181,17 +182,17 @@ class DateTimeInfo
      */
     int32_t utcToLocalStandardOffsetSeconds;
 
     static const int64_t MaxUnixTimeT = 2145859200; /* time_t 12/31/2037 */
 
     static const int64_t RangeExpansionAmount = 30 * SecondsPerDay;
 
     int64_t internalGetDSTOffsetMilliseconds(int64_t utcMilliseconds);
-    void internalUpdateTimeZoneAdjustment(ResetTimeZoneMode mode);
+    bool internalUpdateTimeZoneAdjustment(ResetTimeZoneMode mode);
 
     void sanityCheck();
 };
 
 enum class IcuTimeZoneStatus { Valid, NeedsUpdate };
 
 extern ExclusiveData<IcuTimeZoneStatus>*
 IcuTimeZoneState;