mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Bug 1706949 part 13 - Fix icu and intl for wasi. r=anba,glandium
Differential Revision: https://phabricator.services.mozilla.com/D113218
This commit is contained in:
parent
1df3b4b4d2
commit
9e6185bf59
9
config/external/icu/data/icu_data.S
vendored
9
config/external/icu/data/icu_data.S
vendored
@ -13,12 +13,17 @@
|
||||
#endif
|
||||
|
||||
.global ICU_DATA_SYMBOL
|
||||
#ifdef __APPLE__
|
||||
#if defined(__APPLE__)
|
||||
.data
|
||||
.const
|
||||
#elif defined(__wasi__)
|
||||
.section .rodata,"",@
|
||||
#else
|
||||
.section .rodata
|
||||
#endif
|
||||
.balign 16
|
||||
ICU_DATA_SYMBOL:
|
||||
.incbin ICU_DATA_FILE
|
||||
.incbin ICU_DATA_FILE
|
||||
#ifdef __wasi__
|
||||
.size ICU_DATA_SYMBOL, . - ICU_DATA_SYMBOL
|
||||
#endif
|
||||
|
721
intl/icu-patches/bug-1706949-wasi-workaround.diff
Normal file
721
intl/icu-patches/bug-1706949-wasi-workaround.diff
Normal file
@ -0,0 +1,721 @@
|
||||
# Handle WASI lack of support for <thread> and <atomic>.
|
||||
#
|
||||
# WASI issue: https://github.com/WebAssembly/wasi-sdk/issues/180
|
||||
|
||||
diff --git a/intl/icu-patches/bug-1706949-wasi-workaround.diff b/intl/icu-patches/bug-1706949-wasi-workaround.diff
|
||||
new file mode 100644
|
||||
index 000000000000..e69de29bb2d1
|
||||
diff --git a/intl/icu/source/common/putilimp.h b/intl/icu/source/common/putilimp.h
|
||||
index d9c90cf4e756..410770aa7c0d 100644
|
||||
--- a/intl/icu/source/common/putilimp.h
|
||||
+++ b/intl/icu/source/common/putilimp.h
|
||||
@@ -103,6 +103,8 @@ typedef size_t uintptr_t;
|
||||
#endif
|
||||
#elif U_PLATFORM == U_PF_OS400
|
||||
/* not defined */
|
||||
+#elif defined(__wasi__)
|
||||
+ /* not defined */
|
||||
#else
|
||||
# define U_TZSET tzset
|
||||
#endif
|
||||
@@ -128,6 +130,8 @@ typedef size_t uintptr_t;
|
||||
/* not defined */
|
||||
#elif U_PLATFORM == U_PF_IPHONE
|
||||
/* not defined */
|
||||
+#elif defined(__wasi__)
|
||||
+ /* not defined */
|
||||
#else
|
||||
# define U_TIMEZONE timezone
|
||||
#endif
|
||||
@@ -141,6 +145,8 @@ typedef size_t uintptr_t;
|
||||
#endif
|
||||
#elif U_PLATFORM == U_PF_OS400
|
||||
/* not defined */
|
||||
+#elif defined(__wasi__)
|
||||
+ /* not defined */
|
||||
#else
|
||||
# define U_TZNAME tzname
|
||||
#endif
|
||||
diff --git a/intl/icu/source/common/umapfile.h b/intl/icu/source/common/umapfile.h
|
||||
index 92bd567a2a98..4ed1112bc6df 100644
|
||||
--- a/intl/icu/source/common/umapfile.h
|
||||
+++ b/intl/icu/source/common/umapfile.h
|
||||
@@ -41,6 +41,8 @@ U_CFUNC void uprv_unmapFile(UDataMemory *pData);
|
||||
|
||||
#if UCONFIG_NO_FILE_IO
|
||||
# define MAP_IMPLEMENTATION MAP_NONE
|
||||
+#elif defined(__wasi__)
|
||||
+# define MAP_IMPLEMENTATION MAP_STDIO
|
||||
#elif U_PLATFORM_USES_ONLY_WIN32_API
|
||||
# define MAP_IMPLEMENTATION MAP_WIN32
|
||||
#elif U_HAVE_MMAP || U_PLATFORM == U_PF_OS390
|
||||
diff --git a/intl/icu/source/common/umutex.cpp b/intl/icu/source/common/umutex.cpp
|
||||
index ccbee9960a39..6c3452ca1bea 100644
|
||||
--- a/intl/icu/source/common/umutex.cpp
|
||||
+++ b/intl/icu/source/common/umutex.cpp
|
||||
@@ -43,6 +43,7 @@ U_NAMESPACE_BEGIN
|
||||
*
|
||||
*************************************************************************************************/
|
||||
|
||||
+#ifndef __wasi__
|
||||
namespace {
|
||||
std::mutex *initMutex;
|
||||
std::condition_variable *initCondition;
|
||||
@@ -55,9 +56,11 @@ std::once_flag initFlag;
|
||||
std::once_flag *pInitFlag = &initFlag;
|
||||
|
||||
} // Anonymous namespace
|
||||
+#endif
|
||||
|
||||
U_CDECL_BEGIN
|
||||
static UBool U_CALLCONV umtx_cleanup() {
|
||||
+#ifndef __wasi__
|
||||
initMutex->~mutex();
|
||||
initCondition->~condition_variable();
|
||||
UMutex::cleanup();
|
||||
@@ -66,17 +69,21 @@ static UBool U_CALLCONV umtx_cleanup() {
|
||||
// Do not use this trick anywhere else in ICU; use umtx_initOnce, not std::call_once().
|
||||
pInitFlag->~once_flag();
|
||||
pInitFlag = new(&initFlag) std::once_flag();
|
||||
+#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static void U_CALLCONV umtx_init() {
|
||||
+#ifndef __wasi__
|
||||
initMutex = STATIC_NEW(std::mutex);
|
||||
initCondition = STATIC_NEW(std::condition_variable);
|
||||
ucln_common_registerCleanup(UCLN_COMMON_MUTEX, umtx_cleanup);
|
||||
+#endif
|
||||
}
|
||||
U_CDECL_END
|
||||
|
||||
|
||||
+#ifndef __wasi__
|
||||
std::mutex *UMutex::getMutex() {
|
||||
std::mutex *retPtr = fMutex.load(std::memory_order_acquire);
|
||||
if (retPtr == nullptr) {
|
||||
@@ -93,14 +100,17 @@ std::mutex *UMutex::getMutex() {
|
||||
U_ASSERT(retPtr != nullptr);
|
||||
return retPtr;
|
||||
}
|
||||
+#endif
|
||||
|
||||
UMutex *UMutex::gListHead = nullptr;
|
||||
|
||||
void UMutex::cleanup() {
|
||||
UMutex *next = nullptr;
|
||||
for (UMutex *m = gListHead; m != nullptr; m = next) {
|
||||
+#ifndef __wasi__
|
||||
(*m->fMutex).~mutex();
|
||||
m->fMutex = nullptr;
|
||||
+#endif
|
||||
next = m->fListLink;
|
||||
m->fListLink = nullptr;
|
||||
}
|
||||
@@ -110,20 +120,24 @@ void UMutex::cleanup() {
|
||||
|
||||
U_CAPI void U_EXPORT2
|
||||
umtx_lock(UMutex *mutex) {
|
||||
+#ifndef __wasi__
|
||||
if (mutex == nullptr) {
|
||||
mutex = &globalMutex;
|
||||
}
|
||||
mutex->lock();
|
||||
+#endif
|
||||
}
|
||||
|
||||
|
||||
U_CAPI void U_EXPORT2
|
||||
umtx_unlock(UMutex* mutex)
|
||||
{
|
||||
+#ifndef __wasi__
|
||||
if (mutex == nullptr) {
|
||||
mutex = &globalMutex;
|
||||
}
|
||||
mutex->unlock();
|
||||
+#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -143,18 +157,22 @@ umtx_unlock(UMutex* mutex)
|
||||
//
|
||||
U_COMMON_API UBool U_EXPORT2
|
||||
umtx_initImplPreInit(UInitOnce &uio) {
|
||||
+#ifndef __wasi__
|
||||
std::call_once(*pInitFlag, umtx_init);
|
||||
std::unique_lock<std::mutex> lock(*initMutex);
|
||||
+#endif
|
||||
if (umtx_loadAcquire(uio.fState) == 0) {
|
||||
umtx_storeRelease(uio.fState, 1);
|
||||
return true; // Caller will next call the init function.
|
||||
} else {
|
||||
+#ifndef __wasi__
|
||||
while (umtx_loadAcquire(uio.fState) == 1) {
|
||||
// Another thread is currently running the initialization.
|
||||
// Wait until it completes.
|
||||
initCondition->wait(lock);
|
||||
}
|
||||
U_ASSERT(uio.fState == 2);
|
||||
+#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -168,11 +186,13 @@ umtx_initImplPreInit(UInitOnce &uio) {
|
||||
|
||||
U_COMMON_API void U_EXPORT2
|
||||
umtx_initImplPostInit(UInitOnce &uio) {
|
||||
+#ifndef __wasi__
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(*initMutex);
|
||||
umtx_storeRelease(uio.fState, 2);
|
||||
}
|
||||
initCondition->notify_all();
|
||||
+#endif
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
diff --git a/intl/icu/source/common/umutex.h b/intl/icu/source/common/umutex.h
|
||||
index 2503aa4a2914..49c348444703 100644
|
||||
--- a/intl/icu/source/common/umutex.h
|
||||
+++ b/intl/icu/source/common/umutex.h
|
||||
@@ -20,9 +20,12 @@
|
||||
#ifndef UMUTEX_H
|
||||
#define UMUTEX_H
|
||||
|
||||
+#ifndef __wasi__
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
+#endif
|
||||
+
|
||||
#include <type_traits>
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
@@ -37,6 +40,8 @@
|
||||
#error U_USER_ATOMICS and U_USER_MUTEX_H are not supported
|
||||
#endif
|
||||
|
||||
+#ifndef __wasi__
|
||||
+
|
||||
// Export an explicit template instantiation of std::atomic<int32_t>.
|
||||
// When building DLLs for Windows this is required as it is used as a data member of the exported SharedObject class.
|
||||
// See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
|
||||
@@ -61,6 +66,7 @@ template struct std::atomic<std::mutex *>;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+#endif
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
@@ -70,6 +76,8 @@ U_NAMESPACE_BEGIN
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
+#ifndef __wasi__
|
||||
+
|
||||
typedef std::atomic<int32_t> u_atomic_int32_t;
|
||||
#define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
|
||||
|
||||
@@ -89,6 +97,28 @@ inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
|
||||
return var->fetch_sub(1) - 1;
|
||||
}
|
||||
|
||||
+#else
|
||||
+
|
||||
+typedef int32_t u_atomic_int32_t;
|
||||
+#define ATOMIC_INT32_T_INITIALIZER(val) val
|
||||
+
|
||||
+inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
|
||||
+ return var;
|
||||
+}
|
||||
+
|
||||
+inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
|
||||
+ var = val;
|
||||
+}
|
||||
+
|
||||
+inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
|
||||
+ return ++(*var);
|
||||
+}
|
||||
+
|
||||
+inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
|
||||
+ return --(*var);
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
|
||||
/*************************************************************************************************
|
||||
*
|
||||
@@ -231,17 +261,25 @@ public:
|
||||
|
||||
// requirements for C++ BasicLockable, allows UMutex to work with std::lock_guard
|
||||
void lock() {
|
||||
+#ifndef __wasi__
|
||||
std::mutex *m = fMutex.load(std::memory_order_acquire);
|
||||
if (m == nullptr) { m = getMutex(); }
|
||||
m->lock();
|
||||
+#endif
|
||||
+ }
|
||||
+ void unlock() {
|
||||
+#ifndef __wasi__
|
||||
+ fMutex.load(std::memory_order_relaxed)->unlock();
|
||||
+#endif
|
||||
}
|
||||
- void unlock() { fMutex.load(std::memory_order_relaxed)->unlock(); }
|
||||
|
||||
static void cleanup();
|
||||
|
||||
private:
|
||||
+#ifndef __wasi__
|
||||
alignas(std::mutex) char fStorage[sizeof(std::mutex)] {};
|
||||
std::atomic<std::mutex *> fMutex { nullptr };
|
||||
+#endif
|
||||
|
||||
/** All initialized UMutexes are kept in a linked list, so that they can be found,
|
||||
* and the underlying std::mutex destructed, by u_cleanup().
|
||||
@@ -253,7 +291,9 @@ private:
|
||||
* Initial fast check is inline, in lock(). The returned value may never
|
||||
* be nullptr.
|
||||
*/
|
||||
+#ifndef __wasi__
|
||||
std::mutex *getMutex();
|
||||
+#endif
|
||||
};
|
||||
|
||||
|
||||
diff --git a/intl/icu/source/common/unifiedcache.cpp b/intl/icu/source/common/unifiedcache.cpp
|
||||
index f2dd91655958..c483ce143cd3 100644
|
||||
--- a/intl/icu/source/common/unifiedcache.cpp
|
||||
+++ b/intl/icu/source/common/unifiedcache.cpp
|
||||
@@ -13,15 +13,19 @@
|
||||
#include "unifiedcache.h"
|
||||
|
||||
#include <algorithm> // For std::max()
|
||||
+#ifndef __wasi__
|
||||
#include <mutex>
|
||||
+#endif
|
||||
|
||||
#include "uassert.h"
|
||||
#include "uhash.h"
|
||||
#include "ucln_cmn.h"
|
||||
|
||||
static icu::UnifiedCache *gCache = NULL;
|
||||
+#ifndef __wasi__
|
||||
static std::mutex *gCacheMutex = nullptr;
|
||||
static std::condition_variable *gInProgressValueAddedCond;
|
||||
+#endif
|
||||
static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER;
|
||||
|
||||
static const int32_t MAX_EVICT_ITERATIONS = 10;
|
||||
@@ -34,10 +38,12 @@ static UBool U_CALLCONV unifiedcache_cleanup() {
|
||||
gCacheInitOnce.reset();
|
||||
delete gCache;
|
||||
gCache = nullptr;
|
||||
+#ifndef __wasi__
|
||||
gCacheMutex->~mutex();
|
||||
gCacheMutex = nullptr;
|
||||
gInProgressValueAddedCond->~condition_variable();
|
||||
gInProgressValueAddedCond = nullptr;
|
||||
+#endif
|
||||
return TRUE;
|
||||
}
|
||||
U_CDECL_END
|
||||
@@ -72,8 +78,10 @@ static void U_CALLCONV cacheInit(UErrorCode &status) {
|
||||
ucln_common_registerCleanup(
|
||||
UCLN_COMMON_UNIFIED_CACHE, unifiedcache_cleanup);
|
||||
|
||||
+#ifndef __wasi__
|
||||
gCacheMutex = STATIC_NEW(std::mutex);
|
||||
gInProgressValueAddedCond = STATIC_NEW(std::condition_variable);
|
||||
+#endif
|
||||
gCache = new UnifiedCache(status);
|
||||
if (gCache == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
@@ -135,28 +143,38 @@ void UnifiedCache::setEvictionPolicy(
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}
|
||||
+#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
+#endif
|
||||
fMaxUnused = count;
|
||||
fMaxPercentageOfInUse = percentageOfInUseItems;
|
||||
}
|
||||
|
||||
int32_t UnifiedCache::unusedCount() const {
|
||||
+#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
+#endif
|
||||
return uhash_count(fHashtable) - fNumValuesInUse;
|
||||
}
|
||||
|
||||
int64_t UnifiedCache::autoEvictedCount() const {
|
||||
+#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
+#endif
|
||||
return fAutoEvictedCount;
|
||||
}
|
||||
|
||||
int32_t UnifiedCache::keyCount() const {
|
||||
+#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
+#endif
|
||||
return uhash_count(fHashtable);
|
||||
}
|
||||
|
||||
void UnifiedCache::flush() const {
|
||||
+#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
+#endif
|
||||
|
||||
// Use a loop in case cache items that are flushed held hard references to
|
||||
// other cache items making those additional cache items eligible for
|
||||
@@ -165,7 +183,9 @@ void UnifiedCache::flush() const {
|
||||
}
|
||||
|
||||
void UnifiedCache::handleUnreferencedObject() const {
|
||||
+#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
+#endif
|
||||
--fNumValuesInUse;
|
||||
_runEvictionSlice();
|
||||
}
|
||||
@@ -184,7 +204,9 @@ void UnifiedCache::dump() {
|
||||
}
|
||||
|
||||
void UnifiedCache::dumpContents() const {
|
||||
+#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
+#endif
|
||||
_dumpContents();
|
||||
}
|
||||
|
||||
@@ -224,7 +246,9 @@ UnifiedCache::~UnifiedCache() {
|
||||
// Now all that should be left in the cache are entries that refer to
|
||||
// each other and entries with hard references from outside the cache.
|
||||
// Nothing we can do about these so proceed to wipe out the cache.
|
||||
+#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
+#endif
|
||||
_flush(TRUE);
|
||||
}
|
||||
uhash_close(fHashtable);
|
||||
@@ -325,7 +349,9 @@ void UnifiedCache::_putIfAbsentAndGet(
|
||||
const CacheKeyBase &key,
|
||||
const SharedObject *&value,
|
||||
UErrorCode &status) const {
|
||||
+#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
+#endif
|
||||
const UHashElement *element = uhash_find(fHashtable, &key);
|
||||
if (element != NULL && !_inProgress(element)) {
|
||||
_fetch(element, value, status);
|
||||
@@ -350,14 +376,18 @@ UBool UnifiedCache::_poll(
|
||||
UErrorCode &status) const {
|
||||
U_ASSERT(value == NULL);
|
||||
U_ASSERT(status == U_ZERO_ERROR);
|
||||
+#ifndef __wasi__
|
||||
std::unique_lock<std::mutex> lock(*gCacheMutex);
|
||||
+#endif
|
||||
const UHashElement *element = uhash_find(fHashtable, &key);
|
||||
|
||||
// If the hash table contains an inProgress placeholder entry for this key,
|
||||
// this means that another thread is currently constructing the value object.
|
||||
// Loop, waiting for that construction to complete.
|
||||
while (element != NULL && _inProgress(element)) {
|
||||
+#ifndef __wasi__
|
||||
gInProgressValueAddedCond->wait(lock);
|
||||
+#endif
|
||||
element = uhash_find(fHashtable, &key);
|
||||
}
|
||||
|
||||
@@ -428,9 +458,11 @@ void UnifiedCache::_put(
|
||||
U_ASSERT(oldValue == fNoValue);
|
||||
removeSoftRef(oldValue);
|
||||
|
||||
+#ifndef __wasi__
|
||||
// Tell waiting threads that we replace in-progress status with
|
||||
// an error.
|
||||
gInProgressValueAddedCond->notify_all();
|
||||
+#endif
|
||||
}
|
||||
|
||||
void UnifiedCache::_fetch(
|
||||
diff --git a/intl/icu/source/i18n/decContext.h b/intl/icu/source/i18n/decContext.h
|
||||
index e145777d1e7a..106704b6e76d 100644
|
||||
--- a/intl/icu/source/i18n/decContext.h
|
||||
+++ b/intl/icu/source/i18n/decContext.h
|
||||
@@ -61,7 +61,9 @@
|
||||
/* #include <stdint.h> */ /* C99 standard integers */
|
||||
#endif
|
||||
#include <stdio.h> /* for printf, etc. */
|
||||
+#ifndef __wasi__
|
||||
#include <signal.h> /* for traps */
|
||||
+#endif
|
||||
|
||||
/* Extended flags setting -- set this to 0 to use only IEEE flags */
|
||||
#if !defined(DECEXTFLAG)
|
||||
diff --git a/intl/icu/source/i18n/decimfmt.cpp b/intl/icu/source/i18n/decimfmt.cpp
|
||||
index daa1129a6ab1..c8f1eda62c30 100644
|
||||
--- a/intl/icu/source/i18n/decimfmt.cpp
|
||||
+++ b/intl/icu/source/i18n/decimfmt.cpp
|
||||
@@ -480,8 +480,13 @@ DecimalFormat& DecimalFormat::operator=(const DecimalFormat& rhs) {
|
||||
DecimalFormat::~DecimalFormat() {
|
||||
if (fields == nullptr) { return; }
|
||||
|
||||
+#ifndef __wasi__
|
||||
delete fields->atomicParser.exchange(nullptr);
|
||||
delete fields->atomicCurrencyParser.exchange(nullptr);
|
||||
+#else
|
||||
+ delete fields->atomicParser;
|
||||
+ delete fields->atomicCurrencyParser;
|
||||
+#endif
|
||||
delete fields;
|
||||
}
|
||||
|
||||
@@ -1626,8 +1631,13 @@ void DecimalFormat::touch(UErrorCode& status) {
|
||||
setupFastFormat();
|
||||
|
||||
// Delete the parsers if they were made previously
|
||||
+#ifndef __wasi__
|
||||
delete fields->atomicParser.exchange(nullptr);
|
||||
delete fields->atomicCurrencyParser.exchange(nullptr);
|
||||
+#else
|
||||
+ delete fields->atomicParser;
|
||||
+ delete fields->atomicCurrencyParser;
|
||||
+#endif
|
||||
|
||||
// In order for the getters to work, we need to populate some fields in NumberFormat.
|
||||
NumberFormat::setCurrency(fields->exportedProperties.currency.get(status).getISOCurrency(), status);
|
||||
@@ -1662,7 +1672,11 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& sta
|
||||
}
|
||||
|
||||
// First try to get the pre-computed parser
|
||||
+#ifndef __wasi__
|
||||
auto* ptr = fields->atomicParser.load();
|
||||
+#else
|
||||
+ auto* ptr = fields->atomicParser;
|
||||
+#endif
|
||||
if (ptr != nullptr) {
|
||||
return ptr;
|
||||
}
|
||||
@@ -1681,6 +1695,7 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& sta
|
||||
// it is set to what is actually stored in the atomic
|
||||
// if another thread beat us to computing the parser object.
|
||||
auto* nonConstThis = const_cast<DecimalFormat*>(this);
|
||||
+#ifndef __wasi__
|
||||
if (!nonConstThis->fields->atomicParser.compare_exchange_strong(ptr, temp)) {
|
||||
// Another thread beat us to computing the parser
|
||||
delete temp;
|
||||
@@ -1689,13 +1704,21 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& sta
|
||||
// Our copy of the parser got stored in the atomic
|
||||
return temp;
|
||||
}
|
||||
+#else
|
||||
+ nonConstThis->fields->atomicParser = temp;
|
||||
+ return temp;
|
||||
+#endif
|
||||
}
|
||||
|
||||
const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) { return nullptr; }
|
||||
|
||||
// First try to get the pre-computed parser
|
||||
+#ifndef __wasi__
|
||||
auto* ptr = fields->atomicCurrencyParser.load();
|
||||
+#else
|
||||
+ auto* ptr = fields->atomicCurrencyParser;
|
||||
+#endif
|
||||
if (ptr != nullptr) {
|
||||
return ptr;
|
||||
}
|
||||
@@ -1710,6 +1733,7 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorC
|
||||
// Note: ptr starts as nullptr; during compare_exchange, it is set to what is actually stored in the
|
||||
// atomic if another thread beat us to computing the parser object.
|
||||
auto* nonConstThis = const_cast<DecimalFormat*>(this);
|
||||
+#ifndef __wasi__
|
||||
if (!nonConstThis->fields->atomicCurrencyParser.compare_exchange_strong(ptr, temp)) {
|
||||
// Another thread beat us to computing the parser
|
||||
delete temp;
|
||||
@@ -1718,6 +1742,10 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorC
|
||||
// Our copy of the parser got stored in the atomic
|
||||
return temp;
|
||||
}
|
||||
+#else
|
||||
+ nonConstThis->fields->atomicCurrencyParser = temp;
|
||||
+ return temp;
|
||||
+#endif
|
||||
}
|
||||
|
||||
void
|
||||
diff --git a/intl/icu/source/i18n/number_mapper.h b/intl/icu/source/i18n/number_mapper.h
|
||||
index d18b8b3c438c..e5b5e3fd6294 100644
|
||||
--- a/intl/icu/source/i18n/number_mapper.h
|
||||
+++ b/intl/icu/source/i18n/number_mapper.h
|
||||
@@ -7,7 +7,6 @@
|
||||
#ifndef __NUMBER_MAPPER_H__
|
||||
#define __NUMBER_MAPPER_H__
|
||||
|
||||
-#include <atomic>
|
||||
#include "number_types.h"
|
||||
#include "unicode/currpinf.h"
|
||||
#include "standardplural.h"
|
||||
@@ -15,6 +14,10 @@
|
||||
#include "number_currencysymbols.h"
|
||||
#include "numparse_impl.h"
|
||||
|
||||
+#ifndef __wasi__
|
||||
+#include <atomic>
|
||||
+#endif
|
||||
+
|
||||
U_NAMESPACE_BEGIN
|
||||
namespace number {
|
||||
namespace impl {
|
||||
@@ -183,10 +186,18 @@ struct DecimalFormatFields : public UMemory {
|
||||
LocalizedNumberFormatter formatter;
|
||||
|
||||
/** The lazy-computed parser for .parse() */
|
||||
+#ifndef __wasi__
|
||||
std::atomic<::icu::numparse::impl::NumberParserImpl*> atomicParser = {};
|
||||
+#else
|
||||
+ ::icu::numparse::impl::NumberParserImpl* atomicParser = nullptr;
|
||||
+#endif
|
||||
|
||||
/** The lazy-computed parser for .parseCurrency() */
|
||||
+#ifndef __wasi__
|
||||
std::atomic<::icu::numparse::impl::NumberParserImpl*> atomicCurrencyParser = {};
|
||||
+#else
|
||||
+ ::icu::numparse::impl::NumberParserImpl* atomicCurrencyParser = {};
|
||||
+#endif
|
||||
|
||||
/** Small object ownership warehouse for the formatter and parser */
|
||||
DecimalFormatWarehouse warehouse;
|
||||
diff --git a/intl/icu/source/i18n/numrange_fluent.cpp b/intl/icu/source/i18n/numrange_fluent.cpp
|
||||
index 33179026f8d2..ceec51431031 100644
|
||||
--- a/intl/icu/source/i18n/numrange_fluent.cpp
|
||||
+++ b/intl/icu/source/i18n/numrange_fluent.cpp
|
||||
@@ -239,28 +239,48 @@ LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS<LNF>&& src) U_N
|
||||
: NFS<LNF>(std::move(src)) {
|
||||
// Steal the compiled formatter
|
||||
LNF&& _src = static_cast<LNF&&>(src);
|
||||
+#ifndef __wasi__
|
||||
auto* stolen = _src.fAtomicFormatter.exchange(nullptr);
|
||||
delete fAtomicFormatter.exchange(stolen);
|
||||
+#else
|
||||
+ delete fAtomicFormatter;
|
||||
+ fAtomicFormatter = _src.fAtomicFormatter;
|
||||
+ _src.fAtomicFormatter = nullptr;
|
||||
+#endif
|
||||
}
|
||||
|
||||
LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(const LNF& other) {
|
||||
NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
|
||||
// Do not steal; just clear
|
||||
+#ifndef __wasi__
|
||||
delete fAtomicFormatter.exchange(nullptr);
|
||||
+#else
|
||||
+ delete fAtomicFormatter;
|
||||
+#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(LNF&& src) U_NOEXCEPT {
|
||||
NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src));
|
||||
// Steal the compiled formatter
|
||||
+#ifndef __wasi__
|
||||
auto* stolen = src.fAtomicFormatter.exchange(nullptr);
|
||||
delete fAtomicFormatter.exchange(stolen);
|
||||
+#else
|
||||
+ delete fAtomicFormatter;
|
||||
+ fAtomicFormatter = src.fAtomicFormatter;
|
||||
+ src.fAtomicFormatter = nullptr;
|
||||
+#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
LocalizedNumberRangeFormatter::~LocalizedNumberRangeFormatter() {
|
||||
+#ifndef __wasi__
|
||||
delete fAtomicFormatter.exchange(nullptr);
|
||||
+#else
|
||||
+ delete fAtomicFormatter;
|
||||
+#endif
|
||||
}
|
||||
|
||||
LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const RangeMacroProps& macros, const Locale& locale) {
|
||||
@@ -344,7 +364,11 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
|
||||
}
|
||||
|
||||
// First try to get the pre-computed formatter
|
||||
+#ifndef __wasi__
|
||||
auto* ptr = fAtomicFormatter.load();
|
||||
+#else
|
||||
+ auto* ptr = fAtomicFormatter;
|
||||
+#endif
|
||||
if (ptr != nullptr) {
|
||||
return ptr;
|
||||
}
|
||||
@@ -363,6 +387,7 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
|
||||
// it is set to what is actually stored in the atomic
|
||||
// if another thread beat us to computing the formatter object.
|
||||
auto* nonConstThis = const_cast<LocalizedNumberRangeFormatter*>(this);
|
||||
+#ifndef __wasi__
|
||||
if (!nonConstThis->fAtomicFormatter.compare_exchange_strong(ptr, temp)) {
|
||||
// Another thread beat us to computing the formatter
|
||||
delete temp;
|
||||
@@ -371,6 +396,10 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
|
||||
// Our copy of the formatter got stored in the atomic
|
||||
return temp;
|
||||
}
|
||||
+#else
|
||||
+ nonConstThis->fAtomicFormatter = temp;
|
||||
+ return temp;
|
||||
+#endif
|
||||
|
||||
}
|
||||
|
||||
diff --git a/intl/icu/source/i18n/unicode/numberrangeformatter.h b/intl/icu/source/i18n/unicode/numberrangeformatter.h
|
||||
index 4d436a769453..5adb09285797 100644
|
||||
--- a/intl/icu/source/i18n/unicode/numberrangeformatter.h
|
||||
+++ b/intl/icu/source/i18n/unicode/numberrangeformatter.h
|
||||
@@ -10,13 +10,16 @@
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
-#include <atomic>
|
||||
#include "unicode/appendable.h"
|
||||
#include "unicode/fieldpos.h"
|
||||
#include "unicode/formattedvalue.h"
|
||||
#include "unicode/fpositer.h"
|
||||
#include "unicode/numberformatter.h"
|
||||
|
||||
+#ifndef __wasi__
|
||||
+#include <atomic>
|
||||
+#endif
|
||||
+
|
||||
/**
|
||||
* \file
|
||||
* \brief C++ API: Library for localized formatting of number, currency, and unit ranges.
|
||||
@@ -194,7 +197,9 @@ class NumberRangeFormatterImpl;
|
||||
} // namespace icu::number
|
||||
U_NAMESPACE_END
|
||||
|
||||
+#ifndef __wasi__
|
||||
template struct U_I18N_API std::atomic< U_NAMESPACE_QUALIFIER number::impl::NumberRangeFormatterImpl*>;
|
||||
+#endif
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
namespace number { // icu::number
|
||||
@@ -663,7 +668,11 @@ class U_I18N_API LocalizedNumberRangeFormatter
|
||||
~LocalizedNumberRangeFormatter();
|
||||
|
||||
private:
|
||||
+#ifndef __wasi__
|
||||
std::atomic<impl::NumberRangeFormatterImpl*> fAtomicFormatter = {};
|
||||
+#else
|
||||
+ impl::NumberRangeFormatterImpl* fAtomicFormatter = nullptr;
|
||||
+#endif
|
||||
|
||||
const impl::NumberRangeFormatterImpl* getFormatter(UErrorCode& stauts) const;
|
||||
|
@ -103,6 +103,8 @@ typedef size_t uintptr_t;
|
||||
#endif
|
||||
#elif U_PLATFORM == U_PF_OS400
|
||||
/* not defined */
|
||||
#elif defined(__wasi__)
|
||||
/* not defined */
|
||||
#else
|
||||
# define U_TZSET tzset
|
||||
#endif
|
||||
@ -128,6 +130,8 @@ typedef size_t uintptr_t;
|
||||
/* not defined */
|
||||
#elif U_PLATFORM == U_PF_IPHONE
|
||||
/* not defined */
|
||||
#elif defined(__wasi__)
|
||||
/* not defined */
|
||||
#else
|
||||
# define U_TIMEZONE timezone
|
||||
#endif
|
||||
@ -141,6 +145,8 @@ typedef size_t uintptr_t;
|
||||
#endif
|
||||
#elif U_PLATFORM == U_PF_OS400
|
||||
/* not defined */
|
||||
#elif defined(__wasi__)
|
||||
/* not defined */
|
||||
#else
|
||||
# define U_TZNAME tzname
|
||||
#endif
|
||||
|
@ -41,6 +41,8 @@ U_CFUNC void uprv_unmapFile(UDataMemory *pData);
|
||||
|
||||
#if UCONFIG_NO_FILE_IO
|
||||
# define MAP_IMPLEMENTATION MAP_NONE
|
||||
#elif defined(__wasi__)
|
||||
# define MAP_IMPLEMENTATION MAP_STDIO
|
||||
#elif U_PLATFORM_USES_ONLY_WIN32_API
|
||||
# define MAP_IMPLEMENTATION MAP_WIN32
|
||||
#elif U_HAVE_MMAP || U_PLATFORM == U_PF_OS390
|
||||
|
@ -43,6 +43,7 @@ U_NAMESPACE_BEGIN
|
||||
*
|
||||
*************************************************************************************************/
|
||||
|
||||
#ifndef __wasi__
|
||||
namespace {
|
||||
std::mutex *initMutex;
|
||||
std::condition_variable *initCondition;
|
||||
@ -55,9 +56,11 @@ std::once_flag initFlag;
|
||||
std::once_flag *pInitFlag = &initFlag;
|
||||
|
||||
} // Anonymous namespace
|
||||
#endif
|
||||
|
||||
U_CDECL_BEGIN
|
||||
static UBool U_CALLCONV umtx_cleanup() {
|
||||
#ifndef __wasi__
|
||||
initMutex->~mutex();
|
||||
initCondition->~condition_variable();
|
||||
UMutex::cleanup();
|
||||
@ -66,17 +69,21 @@ static UBool U_CALLCONV umtx_cleanup() {
|
||||
// Do not use this trick anywhere else in ICU; use umtx_initOnce, not std::call_once().
|
||||
pInitFlag->~once_flag();
|
||||
pInitFlag = new(&initFlag) std::once_flag();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static void U_CALLCONV umtx_init() {
|
||||
#ifndef __wasi__
|
||||
initMutex = STATIC_NEW(std::mutex);
|
||||
initCondition = STATIC_NEW(std::condition_variable);
|
||||
ucln_common_registerCleanup(UCLN_COMMON_MUTEX, umtx_cleanup);
|
||||
#endif
|
||||
}
|
||||
U_CDECL_END
|
||||
|
||||
|
||||
#ifndef __wasi__
|
||||
std::mutex *UMutex::getMutex() {
|
||||
std::mutex *retPtr = fMutex.load(std::memory_order_acquire);
|
||||
if (retPtr == nullptr) {
|
||||
@ -93,14 +100,17 @@ std::mutex *UMutex::getMutex() {
|
||||
U_ASSERT(retPtr != nullptr);
|
||||
return retPtr;
|
||||
}
|
||||
#endif
|
||||
|
||||
UMutex *UMutex::gListHead = nullptr;
|
||||
|
||||
void UMutex::cleanup() {
|
||||
UMutex *next = nullptr;
|
||||
for (UMutex *m = gListHead; m != nullptr; m = next) {
|
||||
#ifndef __wasi__
|
||||
(*m->fMutex).~mutex();
|
||||
m->fMutex = nullptr;
|
||||
#endif
|
||||
next = m->fListLink;
|
||||
m->fListLink = nullptr;
|
||||
}
|
||||
@ -110,20 +120,24 @@ void UMutex::cleanup() {
|
||||
|
||||
U_CAPI void U_EXPORT2
|
||||
umtx_lock(UMutex *mutex) {
|
||||
#ifndef __wasi__
|
||||
if (mutex == nullptr) {
|
||||
mutex = &globalMutex;
|
||||
}
|
||||
mutex->lock();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
U_CAPI void U_EXPORT2
|
||||
umtx_unlock(UMutex* mutex)
|
||||
{
|
||||
#ifndef __wasi__
|
||||
if (mutex == nullptr) {
|
||||
mutex = &globalMutex;
|
||||
}
|
||||
mutex->unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -143,18 +157,22 @@ umtx_unlock(UMutex* mutex)
|
||||
//
|
||||
U_COMMON_API UBool U_EXPORT2
|
||||
umtx_initImplPreInit(UInitOnce &uio) {
|
||||
#ifndef __wasi__
|
||||
std::call_once(*pInitFlag, umtx_init);
|
||||
std::unique_lock<std::mutex> lock(*initMutex);
|
||||
#endif
|
||||
if (umtx_loadAcquire(uio.fState) == 0) {
|
||||
umtx_storeRelease(uio.fState, 1);
|
||||
return true; // Caller will next call the init function.
|
||||
} else {
|
||||
#ifndef __wasi__
|
||||
while (umtx_loadAcquire(uio.fState) == 1) {
|
||||
// Another thread is currently running the initialization.
|
||||
// Wait until it completes.
|
||||
initCondition->wait(lock);
|
||||
}
|
||||
U_ASSERT(uio.fState == 2);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -168,11 +186,13 @@ umtx_initImplPreInit(UInitOnce &uio) {
|
||||
|
||||
U_COMMON_API void U_EXPORT2
|
||||
umtx_initImplPostInit(UInitOnce &uio) {
|
||||
#ifndef __wasi__
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(*initMutex);
|
||||
umtx_storeRelease(uio.fState, 2);
|
||||
}
|
||||
initCondition->notify_all();
|
||||
#endif
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
@ -20,9 +20,12 @@
|
||||
#ifndef UMUTEX_H
|
||||
#define UMUTEX_H
|
||||
|
||||
#ifndef __wasi__
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
@ -37,6 +40,8 @@
|
||||
#error U_USER_ATOMICS and U_USER_MUTEX_H are not supported
|
||||
#endif
|
||||
|
||||
#ifndef __wasi__
|
||||
|
||||
// Export an explicit template instantiation of std::atomic<int32_t>.
|
||||
// When building DLLs for Windows this is required as it is used as a data member of the exported SharedObject class.
|
||||
// See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
|
||||
@ -61,6 +66,7 @@ template struct std::atomic<std::mutex *>;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
@ -70,6 +76,8 @@ U_NAMESPACE_BEGIN
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __wasi__
|
||||
|
||||
typedef std::atomic<int32_t> u_atomic_int32_t;
|
||||
#define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
|
||||
|
||||
@ -89,6 +97,28 @@ inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
|
||||
return var->fetch_sub(1) - 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
typedef int32_t u_atomic_int32_t;
|
||||
#define ATOMIC_INT32_T_INITIALIZER(val) val
|
||||
|
||||
inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
|
||||
return var;
|
||||
}
|
||||
|
||||
inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
|
||||
var = val;
|
||||
}
|
||||
|
||||
inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
|
||||
return ++(*var);
|
||||
}
|
||||
|
||||
inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
|
||||
return --(*var);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*************************************************************************************************
|
||||
*
|
||||
@ -231,17 +261,25 @@ public:
|
||||
|
||||
// requirements for C++ BasicLockable, allows UMutex to work with std::lock_guard
|
||||
void lock() {
|
||||
#ifndef __wasi__
|
||||
std::mutex *m = fMutex.load(std::memory_order_acquire);
|
||||
if (m == nullptr) { m = getMutex(); }
|
||||
m->lock();
|
||||
#endif
|
||||
}
|
||||
void unlock() {
|
||||
#ifndef __wasi__
|
||||
fMutex.load(std::memory_order_relaxed)->unlock();
|
||||
#endif
|
||||
}
|
||||
void unlock() { fMutex.load(std::memory_order_relaxed)->unlock(); }
|
||||
|
||||
static void cleanup();
|
||||
|
||||
private:
|
||||
#ifndef __wasi__
|
||||
alignas(std::mutex) char fStorage[sizeof(std::mutex)] {};
|
||||
std::atomic<std::mutex *> fMutex { nullptr };
|
||||
#endif
|
||||
|
||||
/** All initialized UMutexes are kept in a linked list, so that they can be found,
|
||||
* and the underlying std::mutex destructed, by u_cleanup().
|
||||
@ -253,7 +291,9 @@ private:
|
||||
* Initial fast check is inline, in lock(). The returned value may never
|
||||
* be nullptr.
|
||||
*/
|
||||
#ifndef __wasi__
|
||||
std::mutex *getMutex();
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
@ -13,15 +13,19 @@
|
||||
#include "unifiedcache.h"
|
||||
|
||||
#include <algorithm> // For std::max()
|
||||
#ifndef __wasi__
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
#include "uassert.h"
|
||||
#include "uhash.h"
|
||||
#include "ucln_cmn.h"
|
||||
|
||||
static icu::UnifiedCache *gCache = NULL;
|
||||
#ifndef __wasi__
|
||||
static std::mutex *gCacheMutex = nullptr;
|
||||
static std::condition_variable *gInProgressValueAddedCond;
|
||||
#endif
|
||||
static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER;
|
||||
|
||||
static const int32_t MAX_EVICT_ITERATIONS = 10;
|
||||
@ -34,10 +38,12 @@ static UBool U_CALLCONV unifiedcache_cleanup() {
|
||||
gCacheInitOnce.reset();
|
||||
delete gCache;
|
||||
gCache = nullptr;
|
||||
#ifndef __wasi__
|
||||
gCacheMutex->~mutex();
|
||||
gCacheMutex = nullptr;
|
||||
gInProgressValueAddedCond->~condition_variable();
|
||||
gInProgressValueAddedCond = nullptr;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
U_CDECL_END
|
||||
@ -72,8 +78,10 @@ static void U_CALLCONV cacheInit(UErrorCode &status) {
|
||||
ucln_common_registerCleanup(
|
||||
UCLN_COMMON_UNIFIED_CACHE, unifiedcache_cleanup);
|
||||
|
||||
#ifndef __wasi__
|
||||
gCacheMutex = STATIC_NEW(std::mutex);
|
||||
gInProgressValueAddedCond = STATIC_NEW(std::condition_variable);
|
||||
#endif
|
||||
gCache = new UnifiedCache(status);
|
||||
if (gCache == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
@ -135,28 +143,38 @@ void UnifiedCache::setEvictionPolicy(
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}
|
||||
#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
#endif
|
||||
fMaxUnused = count;
|
||||
fMaxPercentageOfInUse = percentageOfInUseItems;
|
||||
}
|
||||
|
||||
int32_t UnifiedCache::unusedCount() const {
|
||||
#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
#endif
|
||||
return uhash_count(fHashtable) - fNumValuesInUse;
|
||||
}
|
||||
|
||||
int64_t UnifiedCache::autoEvictedCount() const {
|
||||
#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
#endif
|
||||
return fAutoEvictedCount;
|
||||
}
|
||||
|
||||
int32_t UnifiedCache::keyCount() const {
|
||||
#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
#endif
|
||||
return uhash_count(fHashtable);
|
||||
}
|
||||
|
||||
void UnifiedCache::flush() const {
|
||||
#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
#endif
|
||||
|
||||
// Use a loop in case cache items that are flushed held hard references to
|
||||
// other cache items making those additional cache items eligible for
|
||||
@ -165,7 +183,9 @@ void UnifiedCache::flush() const {
|
||||
}
|
||||
|
||||
void UnifiedCache::handleUnreferencedObject() const {
|
||||
#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
#endif
|
||||
--fNumValuesInUse;
|
||||
_runEvictionSlice();
|
||||
}
|
||||
@ -184,7 +204,9 @@ void UnifiedCache::dump() {
|
||||
}
|
||||
|
||||
void UnifiedCache::dumpContents() const {
|
||||
#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
#endif
|
||||
_dumpContents();
|
||||
}
|
||||
|
||||
@ -224,7 +246,9 @@ UnifiedCache::~UnifiedCache() {
|
||||
// Now all that should be left in the cache are entries that refer to
|
||||
// each other and entries with hard references from outside the cache.
|
||||
// Nothing we can do about these so proceed to wipe out the cache.
|
||||
#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
#endif
|
||||
_flush(TRUE);
|
||||
}
|
||||
uhash_close(fHashtable);
|
||||
@ -325,7 +349,9 @@ void UnifiedCache::_putIfAbsentAndGet(
|
||||
const CacheKeyBase &key,
|
||||
const SharedObject *&value,
|
||||
UErrorCode &status) const {
|
||||
#ifndef __wasi__
|
||||
std::lock_guard<std::mutex> lock(*gCacheMutex);
|
||||
#endif
|
||||
const UHashElement *element = uhash_find(fHashtable, &key);
|
||||
if (element != NULL && !_inProgress(element)) {
|
||||
_fetch(element, value, status);
|
||||
@ -350,14 +376,18 @@ UBool UnifiedCache::_poll(
|
||||
UErrorCode &status) const {
|
||||
U_ASSERT(value == NULL);
|
||||
U_ASSERT(status == U_ZERO_ERROR);
|
||||
#ifndef __wasi__
|
||||
std::unique_lock<std::mutex> lock(*gCacheMutex);
|
||||
#endif
|
||||
const UHashElement *element = uhash_find(fHashtable, &key);
|
||||
|
||||
// If the hash table contains an inProgress placeholder entry for this key,
|
||||
// this means that another thread is currently constructing the value object.
|
||||
// Loop, waiting for that construction to complete.
|
||||
while (element != NULL && _inProgress(element)) {
|
||||
#ifndef __wasi__
|
||||
gInProgressValueAddedCond->wait(lock);
|
||||
#endif
|
||||
element = uhash_find(fHashtable, &key);
|
||||
}
|
||||
|
||||
@ -428,9 +458,11 @@ void UnifiedCache::_put(
|
||||
U_ASSERT(oldValue == fNoValue);
|
||||
removeSoftRef(oldValue);
|
||||
|
||||
#ifndef __wasi__
|
||||
// Tell waiting threads that we replace in-progress status with
|
||||
// an error.
|
||||
gInProgressValueAddedCond->notify_all();
|
||||
#endif
|
||||
}
|
||||
|
||||
void UnifiedCache::_fetch(
|
||||
|
@ -61,7 +61,9 @@
|
||||
/* #include <stdint.h> */ /* C99 standard integers */
|
||||
#endif
|
||||
#include <stdio.h> /* for printf, etc. */
|
||||
#ifndef __wasi__
|
||||
#include <signal.h> /* for traps */
|
||||
#endif
|
||||
|
||||
/* Extended flags setting -- set this to 0 to use only IEEE flags */
|
||||
#if !defined(DECEXTFLAG)
|
||||
|
@ -480,8 +480,13 @@ DecimalFormat& DecimalFormat::operator=(const DecimalFormat& rhs) {
|
||||
DecimalFormat::~DecimalFormat() {
|
||||
if (fields == nullptr) { return; }
|
||||
|
||||
#ifndef __wasi__
|
||||
delete fields->atomicParser.exchange(nullptr);
|
||||
delete fields->atomicCurrencyParser.exchange(nullptr);
|
||||
#else
|
||||
delete fields->atomicParser;
|
||||
delete fields->atomicCurrencyParser;
|
||||
#endif
|
||||
delete fields;
|
||||
}
|
||||
|
||||
@ -1626,8 +1631,13 @@ void DecimalFormat::touch(UErrorCode& status) {
|
||||
setupFastFormat();
|
||||
|
||||
// Delete the parsers if they were made previously
|
||||
#ifndef __wasi__
|
||||
delete fields->atomicParser.exchange(nullptr);
|
||||
delete fields->atomicCurrencyParser.exchange(nullptr);
|
||||
#else
|
||||
delete fields->atomicParser;
|
||||
delete fields->atomicCurrencyParser;
|
||||
#endif
|
||||
|
||||
// In order for the getters to work, we need to populate some fields in NumberFormat.
|
||||
NumberFormat::setCurrency(fields->exportedProperties.currency.get(status).getISOCurrency(), status);
|
||||
@ -1662,7 +1672,11 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& sta
|
||||
}
|
||||
|
||||
// First try to get the pre-computed parser
|
||||
#ifndef __wasi__
|
||||
auto* ptr = fields->atomicParser.load();
|
||||
#else
|
||||
auto* ptr = fields->atomicParser;
|
||||
#endif
|
||||
if (ptr != nullptr) {
|
||||
return ptr;
|
||||
}
|
||||
@ -1681,6 +1695,7 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& sta
|
||||
// it is set to what is actually stored in the atomic
|
||||
// if another thread beat us to computing the parser object.
|
||||
auto* nonConstThis = const_cast<DecimalFormat*>(this);
|
||||
#ifndef __wasi__
|
||||
if (!nonConstThis->fields->atomicParser.compare_exchange_strong(ptr, temp)) {
|
||||
// Another thread beat us to computing the parser
|
||||
delete temp;
|
||||
@ -1689,13 +1704,21 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& sta
|
||||
// Our copy of the parser got stored in the atomic
|
||||
return temp;
|
||||
}
|
||||
#else
|
||||
nonConstThis->fields->atomicParser = temp;
|
||||
return temp;
|
||||
#endif
|
||||
}
|
||||
|
||||
const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) { return nullptr; }
|
||||
|
||||
// First try to get the pre-computed parser
|
||||
#ifndef __wasi__
|
||||
auto* ptr = fields->atomicCurrencyParser.load();
|
||||
#else
|
||||
auto* ptr = fields->atomicCurrencyParser;
|
||||
#endif
|
||||
if (ptr != nullptr) {
|
||||
return ptr;
|
||||
}
|
||||
@ -1710,6 +1733,7 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorC
|
||||
// Note: ptr starts as nullptr; during compare_exchange, it is set to what is actually stored in the
|
||||
// atomic if another thread beat us to computing the parser object.
|
||||
auto* nonConstThis = const_cast<DecimalFormat*>(this);
|
||||
#ifndef __wasi__
|
||||
if (!nonConstThis->fields->atomicCurrencyParser.compare_exchange_strong(ptr, temp)) {
|
||||
// Another thread beat us to computing the parser
|
||||
delete temp;
|
||||
@ -1718,6 +1742,10 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorC
|
||||
// Our copy of the parser got stored in the atomic
|
||||
return temp;
|
||||
}
|
||||
#else
|
||||
nonConstThis->fields->atomicCurrencyParser = temp;
|
||||
return temp;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -7,7 +7,6 @@
|
||||
#ifndef __NUMBER_MAPPER_H__
|
||||
#define __NUMBER_MAPPER_H__
|
||||
|
||||
#include <atomic>
|
||||
#include "number_types.h"
|
||||
#include "unicode/currpinf.h"
|
||||
#include "standardplural.h"
|
||||
@ -15,6 +14,10 @@
|
||||
#include "number_currencysymbols.h"
|
||||
#include "numparse_impl.h"
|
||||
|
||||
#ifndef __wasi__
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
namespace number {
|
||||
namespace impl {
|
||||
@ -183,10 +186,18 @@ struct DecimalFormatFields : public UMemory {
|
||||
LocalizedNumberFormatter formatter;
|
||||
|
||||
/** The lazy-computed parser for .parse() */
|
||||
#ifndef __wasi__
|
||||
std::atomic<::icu::numparse::impl::NumberParserImpl*> atomicParser = {};
|
||||
#else
|
||||
::icu::numparse::impl::NumberParserImpl* atomicParser = nullptr;
|
||||
#endif
|
||||
|
||||
/** The lazy-computed parser for .parseCurrency() */
|
||||
#ifndef __wasi__
|
||||
std::atomic<::icu::numparse::impl::NumberParserImpl*> atomicCurrencyParser = {};
|
||||
#else
|
||||
::icu::numparse::impl::NumberParserImpl* atomicCurrencyParser = {};
|
||||
#endif
|
||||
|
||||
/** Small object ownership warehouse for the formatter and parser */
|
||||
DecimalFormatWarehouse warehouse;
|
||||
|
@ -239,28 +239,48 @@ LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS<LNF>&& src) U_N
|
||||
: NFS<LNF>(std::move(src)) {
|
||||
// Steal the compiled formatter
|
||||
LNF&& _src = static_cast<LNF&&>(src);
|
||||
#ifndef __wasi__
|
||||
auto* stolen = _src.fAtomicFormatter.exchange(nullptr);
|
||||
delete fAtomicFormatter.exchange(stolen);
|
||||
#else
|
||||
delete fAtomicFormatter;
|
||||
fAtomicFormatter = _src.fAtomicFormatter;
|
||||
_src.fAtomicFormatter = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(const LNF& other) {
|
||||
NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
|
||||
// Do not steal; just clear
|
||||
#ifndef __wasi__
|
||||
delete fAtomicFormatter.exchange(nullptr);
|
||||
#else
|
||||
delete fAtomicFormatter;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(LNF&& src) U_NOEXCEPT {
|
||||
NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src));
|
||||
// Steal the compiled formatter
|
||||
#ifndef __wasi__
|
||||
auto* stolen = src.fAtomicFormatter.exchange(nullptr);
|
||||
delete fAtomicFormatter.exchange(stolen);
|
||||
#else
|
||||
delete fAtomicFormatter;
|
||||
fAtomicFormatter = src.fAtomicFormatter;
|
||||
src.fAtomicFormatter = nullptr;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
LocalizedNumberRangeFormatter::~LocalizedNumberRangeFormatter() {
|
||||
#ifndef __wasi__
|
||||
delete fAtomicFormatter.exchange(nullptr);
|
||||
#else
|
||||
delete fAtomicFormatter;
|
||||
#endif
|
||||
}
|
||||
|
||||
LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const RangeMacroProps& macros, const Locale& locale) {
|
||||
@ -344,7 +364,11 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
|
||||
}
|
||||
|
||||
// First try to get the pre-computed formatter
|
||||
#ifndef __wasi__
|
||||
auto* ptr = fAtomicFormatter.load();
|
||||
#else
|
||||
auto* ptr = fAtomicFormatter;
|
||||
#endif
|
||||
if (ptr != nullptr) {
|
||||
return ptr;
|
||||
}
|
||||
@ -363,6 +387,7 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
|
||||
// it is set to what is actually stored in the atomic
|
||||
// if another thread beat us to computing the formatter object.
|
||||
auto* nonConstThis = const_cast<LocalizedNumberRangeFormatter*>(this);
|
||||
#ifndef __wasi__
|
||||
if (!nonConstThis->fAtomicFormatter.compare_exchange_strong(ptr, temp)) {
|
||||
// Another thread beat us to computing the formatter
|
||||
delete temp;
|
||||
@ -371,6 +396,10 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
|
||||
// Our copy of the formatter got stored in the atomic
|
||||
return temp;
|
||||
}
|
||||
#else
|
||||
nonConstThis->fAtomicFormatter = temp;
|
||||
return temp;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
@ -10,13 +10,16 @@
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include <atomic>
|
||||
#include "unicode/appendable.h"
|
||||
#include "unicode/fieldpos.h"
|
||||
#include "unicode/formattedvalue.h"
|
||||
#include "unicode/fpositer.h"
|
||||
#include "unicode/numberformatter.h"
|
||||
|
||||
#ifndef __wasi__
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief C++ API: Library for localized formatting of number, currency, and unit ranges.
|
||||
@ -194,7 +197,9 @@ class NumberRangeFormatterImpl;
|
||||
} // namespace icu::number
|
||||
U_NAMESPACE_END
|
||||
|
||||
#ifndef __wasi__
|
||||
template struct U_I18N_API std::atomic< U_NAMESPACE_QUALIFIER number::impl::NumberRangeFormatterImpl*>;
|
||||
#endif
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
namespace number { // icu::number
|
||||
@ -663,7 +668,11 @@ class U_I18N_API LocalizedNumberRangeFormatter
|
||||
~LocalizedNumberRangeFormatter();
|
||||
|
||||
private:
|
||||
#ifndef __wasi__
|
||||
std::atomic<impl::NumberRangeFormatterImpl*> fAtomicFormatter = {};
|
||||
#else
|
||||
impl::NumberRangeFormatterImpl* fAtomicFormatter = nullptr;
|
||||
#endif
|
||||
|
||||
const impl::NumberRangeFormatterImpl* getFormatter(UErrorCode& stauts) const;
|
||||
|
||||
|
@ -59,6 +59,7 @@ for patch in \
|
||||
bug-1636984-display-name-fractional-seconds.diff \
|
||||
bug-1636984-append-item-dayperiod-fractional-seconds.diff \
|
||||
bug-1534160-android-timezone.diff \
|
||||
bug-1706949-wasi-workaround.diff \
|
||||
; do
|
||||
echo "Applying local patch $patch"
|
||||
patch -d ${icu_dir}/../../ -p1 --no-backup-if-mismatch < ${icu_dir}/../icu-patches/$patch
|
||||
|
@ -6448,30 +6448,31 @@ static bool GetTimeZone(JSContext* cx, unsigned argc, Value* vp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef __wasi__
|
||||
auto getTimeZone = [](std::time_t* now) -> const char* {
|
||||
std::tm local{};
|
||||
#if defined(_WIN32)
|
||||
# if defined(_WIN32)
|
||||
_tzset();
|
||||
if (localtime_s(&local, now) == 0) {
|
||||
return _tzname[local.tm_isdst > 0];
|
||||
}
|
||||
#else
|
||||
tzset();
|
||||
# if defined(HAVE_LOCALTIME_R)
|
||||
if (localtime_r(now, &local)) {
|
||||
# else
|
||||
tzset();
|
||||
# if defined(HAVE_LOCALTIME_R)
|
||||
if (localtime_r(now, &local)) {
|
||||
# else
|
||||
std::tm* localtm = std::localtime(now);
|
||||
if (localtm) {
|
||||
*local = *localtm;
|
||||
# endif /* HAVE_LOCALTIME_R */
|
||||
# endif /* HAVE_LOCALTIME_R */
|
||||
|
||||
# if defined(HAVE_TM_ZONE_TM_GMTOFF)
|
||||
# if defined(HAVE_TM_ZONE_TM_GMTOFF)
|
||||
return local.tm_zone;
|
||||
# else
|
||||
# else
|
||||
return tzname[local.tm_isdst > 0];
|
||||
# endif /* HAVE_TM_ZONE_TM_GMTOFF */
|
||||
# endif /* HAVE_TM_ZONE_TM_GMTOFF */
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
# endif /* _WIN32 */
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
@ -6481,7 +6482,7 @@ static bool GetTimeZone(JSContext* cx, unsigned argc, Value* vp) {
|
||||
return ReturnStringCopy(cx, args, tz);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __wasi__ */
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
@ -6501,20 +6502,21 @@ static bool SetTimeZone(JSContext* cx, unsigned argc, Value* vp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef __wasi__
|
||||
auto setTimeZone = [](const char* value) {
|
||||
#if defined(_WIN32)
|
||||
# if defined(_WIN32)
|
||||
return _putenv_s("TZ", value) == 0;
|
||||
#else
|
||||
# else
|
||||
return setenv("TZ", value, true) == 0;
|
||||
#endif /* _WIN32 */
|
||||
# endif /* _WIN32 */
|
||||
};
|
||||
|
||||
auto unsetTimeZone = []() {
|
||||
#if defined(_WIN32)
|
||||
# if defined(_WIN32)
|
||||
return _putenv_s("TZ", "") == 0;
|
||||
#else
|
||||
# else
|
||||
return unsetenv("TZ") == 0;
|
||||
#endif /* _WIN32 */
|
||||
# endif /* _WIN32 */
|
||||
};
|
||||
|
||||
if (args[0].isString() && !args[0].toString()->empty()) {
|
||||
@ -6545,14 +6547,15 @@ static bool SetTimeZone(JSContext* cx, unsigned argc, Value* vp) {
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
# if defined(_WIN32)
|
||||
_tzset();
|
||||
#else
|
||||
# else
|
||||
tzset();
|
||||
#endif /* _WIN32 */
|
||||
# endif /* _WIN32 */
|
||||
|
||||
JS::ResetTimeZone();
|
||||
|
||||
#endif /* __wasi__ */
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user