Title: [275109] trunk/Source
Revision
275109
Author
[email protected]
Date
2021-03-26 13:05:48 -0700 (Fri, 26 Mar 2021)

Log Message

[JSC] Use new Apple ICU APIs to avoid C++ ICU API usage
https://bugs.webkit.org/show_bug.cgi?id=223783
<rdar://problem/75060240>

Reviewed by Mark Lam.

Source/_javascript_Core:

This patch adopts ICU 69's draft APIs to avoid using ICU C++ APIs in newer macOS build.
AppleICU adopts these draft APIs so that we can use it even in ICU 68 if ICU is AppleICU.
The API is ucal_getTimeZoneOffsetFromLocal, which is back-ported from ICU 69[1].
The purpose of this API is that calculating timezone offset and dst offset from *local* time.

[1]: https://github.com/unicode-org/icu/commit/53aa0505c5f95a8cebbd7b4421d474fd2a790b80

* runtime/IntlDateTimeFormat.cpp:
* runtime/JSDateMath.cpp:
(JSC::OpaqueICUTimeZoneDeleter::operator()):
(JSC::DateCache::calculateLocalTimeOffset):
(JSC::DateCache::defaultTimeZone):
(JSC::DateCache::timeZoneCacheSlow):
* runtime/JSDateMath.h:

Source/WTF:

* wtf/DateMath.h:
(WTF::LocalTimeOffset::LocalTimeOffset):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (275108 => 275109)


--- trunk/Source/_javascript_Core/ChangeLog	2021-03-26 19:26:35 UTC (rev 275108)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-03-26 20:05:48 UTC (rev 275109)
@@ -1,3 +1,26 @@
+2021-03-26  Yusuke Suzuki  <[email protected]>
+
+        [JSC] Use new Apple ICU APIs to avoid C++ ICU API usage
+        https://bugs.webkit.org/show_bug.cgi?id=223783
+        <rdar://problem/75060240>
+
+        Reviewed by Mark Lam.
+
+        This patch adopts ICU 69's draft APIs to avoid using ICU C++ APIs in newer macOS build.
+        AppleICU adopts these draft APIs so that we can use it even in ICU 68 if ICU is AppleICU.
+        The API is ucal_getTimeZoneOffsetFromLocal, which is back-ported from ICU 69[1].
+        The purpose of this API is that calculating timezone offset and dst offset from *local* time.
+
+        [1]: https://github.com/unicode-org/icu/commit/53aa0505c5f95a8cebbd7b4421d474fd2a790b80
+
+        * runtime/IntlDateTimeFormat.cpp:
+        * runtime/JSDateMath.cpp:
+        (JSC::OpaqueICUTimeZoneDeleter::operator()):
+        (JSC::DateCache::calculateLocalTimeOffset):
+        (JSC::DateCache::defaultTimeZone):
+        (JSC::DateCache::timeZoneCacheSlow):
+        * runtime/JSDateMath.h:
+
 2021-03-26  Jessie Berlin  <[email protected]>
 
         Update the BEFORE/SINCE, SYSTEM_VERSION_PREFIX, and MACOSX_DEPLOYMENT_TARGET flags

Modified: trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.cpp (275108 => 275109)


--- trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.cpp	2021-03-26 19:26:35 UTC (rev 275108)
+++ trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.cpp	2021-03-26 20:05:48 UTC (rev 275109)
@@ -31,6 +31,7 @@
 #include "IntlObjectInlines.h"
 #include "JSBoundFunction.h"
 #include "JSCInlines.h"
+#include "JSDateMath.h"
 #include "ObjectConstructor.h"
 #include <unicode/ucal.h>
 #include <unicode/uenum.h>
@@ -59,8 +60,6 @@
         udtitvfmt_close(formatter);
 }
 
-static constexpr double minECMAScriptTime = -8.64E15;
-
 const ClassInfo IntlDateTimeFormat::s_info = { "Object", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(IntlDateTimeFormat) };
 
 namespace IntlDateTimeFormatInternal {

Modified: trunk/Source/_javascript_Core/runtime/JSDateMath.cpp (275108 => 275109)


--- trunk/Source/_javascript_Core/runtime/JSDateMath.cpp	2021-03-26 19:26:35 UTC (rev 275108)
+++ trunk/Source/_javascript_Core/runtime/JSDateMath.cpp	2021-03-26 20:05:48 UTC (rev 275109)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 1999-2000 Harri Porten ([email protected])
- * Copyright (C) 2006-2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2021 Apple Inc. All rights reserved.
  * Copyright (C) 2009 Google Inc. All rights reserved.
  * Copyright (C) 2007-2009 Torch Mobile, Inc.
  * Copyright (C) 2010 &yet, LLC. ([email protected])
@@ -75,7 +75,15 @@
 #include "ExceptionHelpers.h"
 #include "VM.h"
 #include <limits>
+#include <wtf/unicode/icu/ICUHelpers.h>
 
+#if U_ICU_VERSION_MAJOR_NUM >= 68 && USE(APPLE_INTERNAL_SDK)
+#define HAVE_ICU_C_TIMEZONE_API 1
+#ifdef U_HIDE_DRAFT_API
+#undef U_HIDE_DRAFT_API
+#endif
+#include <unicode/ucal.h>
+#else
 // icu::TimeZone and icu::BasicTimeZone features are only available in ICU C++ APIs.
 // We use these C++ APIs as an exception.
 #undef U_SHOW_CPLUSPLUS_API
@@ -85,13 +93,28 @@
 #include <unicode/unistr.h>
 #undef U_SHOW_CPLUSPLUS_API
 #define U_SHOW_CPLUSPLUS_API 0
+#endif
 
 namespace JSC {
 
+
+#if HAVE(ICU_C_TIMEZONE_API)
+class OpaqueICUTimeZone {
+    WTF_MAKE_FAST_ALLOCATED(OpaqueICUTimeZone);
+public:
+    std::unique_ptr<UCalendar, ICUDeleter<ucal_close>> m_calendar;
+};
+#endif
+
 void OpaqueICUTimeZoneDeleter::operator()(OpaqueICUTimeZone* timeZone)
 {
-    if (timeZone)
+    if (timeZone) {
+#if HAVE(ICU_C_TIMEZONE_API)
+        delete timeZone;
+#else
         delete bitwise_cast<icu::TimeZone*>(timeZone);
+#endif
+    }
 }
 
 // Get the combined UTC + DST offset for the time passed in.
@@ -98,25 +121,51 @@
 //
 // 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.
+// If this function is called with NaN it returns random value.
 LocalTimeOffset DateCache::calculateLocalTimeOffset(double millisecondsFromEpoch, WTF::TimeType inputTimeType)
 {
-    auto& timeZoneCache = *bitwise_cast<icu::TimeZone*>(this->timeZoneCache());
     int32_t rawOffset = 0;
     int32_t dstOffset = 0;
     UErrorCode status = U_ZERO_ERROR;
+
+    // This function can fail input date is invalid: NaN etc.
+    // We can return any values in this case since later we fail when computing non timezone offset part anyway.
+    constexpr LocalTimeOffset failed { false, 0 };
+
+#if HAVE(ICU_C_TIMEZONE_API)
+    auto& timeZoneCache = *this->timeZoneCache();
+    ucal_setMillis(timeZoneCache.m_calendar.get(), millisecondsFromEpoch, &status);
+    if (U_FAILURE(status))
+        return failed;
+
     if (inputTimeType != WTF::LocalTime) {
+        rawOffset = ucal_get(timeZoneCache.m_calendar.get(), UCAL_ZONE_OFFSET, &status);
+        if (U_FAILURE(status))
+            return failed;
+        dstOffset = ucal_get(timeZoneCache.m_calendar.get(), UCAL_DST_OFFSET, &status);
+        if (U_FAILURE(status))
+            return failed;
+    } else {
+        ucal_getTimeZoneOffsetFromLocal(timeZoneCache.m_calendar.get(), UCAL_TZ_LOCAL_FORMER, UCAL_TZ_LOCAL_FORMER, &rawOffset, &dstOffset, &status);
+        if (U_FAILURE(status))
+            return failed;
+    }
+#else
+    auto& timeZoneCache = *bitwise_cast<icu::TimeZone*>(this->timeZoneCache());
+    if (inputTimeType != WTF::LocalTime) {
         constexpr bool isLocalTime = false;
         timeZoneCache.getOffset(millisecondsFromEpoch, isLocalTime, rawOffset, dstOffset, status);
+        if (U_FAILURE(status))
+            return failed;
     } else {
         // icu::TimeZone is a timezone instance which inherits icu::BasicTimeZone.
         // https://unicode-org.atlassian.net/browse/ICU-13705 will move getOffsetFromLocal to icu::TimeZone.
         static_cast<const icu::BasicTimeZone&>(timeZoneCache).getOffsetFromLocal(millisecondsFromEpoch, icu::BasicTimeZone::kFormer, icu::BasicTimeZone::kFormer, rawOffset, dstOffset, status);
+        if (U_FAILURE(status))
+            return failed;
     }
-    // The above can fail if input date is invalid: NaN etc.
-    // We can return any values in this case since later we fail when computing non timezone offset part anyway.
-    if (U_FAILURE(status))
-        return { false, 0 };
+#endif
+
     return { !!dstOffset, rawOffset + dstOffset };
 }
 
@@ -284,6 +333,24 @@
 // https://tc39.es/ecma402/#sec-defaulttimezone
 String DateCache::defaultTimeZone()
 {
+#if HAVE(ICU_C_TIMEZONE_API)
+    auto& timeZone = *timeZoneCache();
+    Vector<UChar, 32> buffer;
+    auto status = callBufferProducingFunction(ucal_getTimeZoneID, timeZone.m_calendar.get(), buffer);
+    if (U_FAILURE(status))
+        return "UTC"_s;
+
+    Vector<UChar, 32> canonicalBuffer;
+    status = callBufferProducingFunction(ucal_getCanonicalTimeZoneID, buffer.data(), buffer.size(), canonicalBuffer, nullptr);
+    if (U_FAILURE(status))
+        return "UTC"_s;
+
+    String canonical = String(canonicalBuffer);
+    if (isUTCEquivalent(canonical))
+        return "UTC"_s;
+
+    return canonical;
+#else
     icu::UnicodeString timeZoneID;
     icu::UnicodeString canonicalTimeZoneID;
     auto& timeZone = *bitwise_cast<icu::TimeZone*>(timeZoneCache());
@@ -300,6 +367,7 @@
         return "UTC"_s;
 
     return canonical;
+#endif
 }
 
 // To confine icu::TimeZone destructor invocation in this file.
@@ -313,9 +381,20 @@
 
 void DateCache::timeZoneCacheSlow()
 {
+    ASSERT(!m_timeZoneCache);
+#if HAVE(ICU_C_TIMEZONE_API)
+    auto* cache = new OpaqueICUTimeZone;
+    Vector<UChar, 32> timeZoneID;
+    auto status = callBufferProducingFunction(ucal_getHostTimeZone, timeZoneID);
+    ASSERT_UNUSED(status, U_SUCCESS(status));
+    cache->m_calendar = std::unique_ptr<UCalendar, ICUDeleter<ucal_close>>(ucal_open(timeZoneID.data(), timeZoneID.size(), "", UCAL_DEFAULT, &status));
+    ASSERT_UNUSED(status, U_SUCCESS(status));
+    ucal_setGregorianChange(cache->m_calendar.get(), minECMAScriptTime, &status); // Ignore "unsupported" error.
+    m_timeZoneCache = std::unique_ptr<OpaqueICUTimeZone, OpaqueICUTimeZoneDeleter>(cache);
+#else
     // Do not use icu::TimeZone::createDefault. ICU internally has a cache for timezone and createDefault returns this cached value.
-    ASSERT(!m_timeZoneCache);
     m_timeZoneCache = std::unique_ptr<OpaqueICUTimeZone, OpaqueICUTimeZoneDeleter>(bitwise_cast<OpaqueICUTimeZone*>(icu::TimeZone::detectHostTimeZone()));
+#endif
 }
 
 void DateCache::reset()

Modified: trunk/Source/_javascript_Core/runtime/JSDateMath.h (275108 => 275109)


--- trunk/Source/_javascript_Core/runtime/JSDateMath.h	2021-03-26 19:26:35 UTC (rev 275108)
+++ trunk/Source/_javascript_Core/runtime/JSDateMath.h	2021-03-26 20:05:48 UTC (rev 275109)
@@ -52,6 +52,8 @@
 class OpaqueICUTimeZone;
 class VM;
 
+static constexpr double minECMAScriptTime = -8.64E15;
+
 // We do not expose icu::TimeZone in this header file. And we cannot use icu::TimeZone forward declaration
 // because icu namespace can be an alias to icu$verNum namespace.
 struct OpaqueICUTimeZoneDeleter {

Modified: trunk/Source/WTF/ChangeLog (275108 => 275109)


--- trunk/Source/WTF/ChangeLog	2021-03-26 19:26:35 UTC (rev 275108)
+++ trunk/Source/WTF/ChangeLog	2021-03-26 20:05:48 UTC (rev 275109)
@@ -1,3 +1,14 @@
+2021-03-26  Yusuke Suzuki  <[email protected]>
+
+        [JSC] Use new Apple ICU APIs to avoid C++ ICU API usage
+        https://bugs.webkit.org/show_bug.cgi?id=223783
+        <rdar://problem/75060240>
+
+        Reviewed by Mark Lam.
+
+        * wtf/DateMath.h:
+        (WTF::LocalTimeOffset::LocalTimeOffset):
+
 2021-03-26  Per Arne  <[email protected]>
 
         Enforce notifyd message filtering

Modified: trunk/Source/WTF/wtf/DateMath.h (275108 => 275109)


--- trunk/Source/WTF/wtf/DateMath.h	2021-03-26 19:26:35 UTC (rev 275108)
+++ trunk/Source/WTF/wtf/DateMath.h	2021-03-26 20:05:48 UTC (rev 275109)
@@ -60,7 +60,7 @@
     WTF_MAKE_STRUCT_FAST_ALLOCATED;
 
     LocalTimeOffset() = default;
-    LocalTimeOffset(bool isDST, int offset)
+    constexpr LocalTimeOffset(bool isDST, int offset)
         : isDST(isDST)
         , offset(offset)
     {
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to