From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- intl/icu-patches/bug-1706949-wasi-workaround.diff | 769 ++++++++++++++++++++++ 1 file changed, 769 insertions(+) create mode 100644 intl/icu-patches/bug-1706949-wasi-workaround.diff (limited to 'intl/icu-patches/bug-1706949-wasi-workaround.diff') 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 0000000000..6d64fa81c1 --- /dev/null +++ b/intl/icu-patches/bug-1706949-wasi-workaround.diff @@ -0,0 +1,769 @@ +# Handle WASI lack of support for and . +# +# WASI issue: https://github.com/WebAssembly/wasi-sdk/issues/180 + +diff --git a/intl/icu/source/common/putilimp.h b/intl/icu/source/common/putilimp.h +index 5b95a68..7097232 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 92bd567..4ed1112 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 ccbee99..6c3452c 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 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 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 8d76b3f..c1a58db 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 + #include + #include ++#endif ++ + #include + + #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. + // 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; + #endif + #endif + ++#endif + + U_NAMESPACE_BEGIN + +@@ -70,6 +76,8 @@ U_NAMESPACE_BEGIN + * + ****************************************************************************/ + ++#ifndef __wasi__ ++ + typedef std::atomic 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 @@ class U_COMMON_API UMutex { + + // 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 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 @@ class U_COMMON_API UMutex { + * 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 +--- a/intl/icu/source/common/unifiedcache.cpp ++++ b/intl/icu/source/common/unifiedcache.cpp +@@ -11,19 +11,23 @@ + */ + + #include "unifiedcache.h" + + #include // For std::max() +-#include ++#ifndef __wasi__ ++ #include ++#endif + + #include "uassert.h" + #include "uhash.h" + #include "ucln_cmn.h" + + static icu::UnifiedCache *gCache = nullptr; ++#ifndef __wasi__ + static std::mutex *gCacheMutex = nullptr; + static std::condition_variable *gInProgressValueAddedCond; ++#endif + static icu::UInitOnce gCacheInitOnce {}; + + static const int32_t MAX_EVICT_ITERATIONS = 10; + static const int32_t DEFAULT_MAX_UNUSED = 1000; + static const int32_t DEFAULT_PERCENTAGE_OF_IN_USE = 100; +@@ -32,14 +36,16 @@ static const int32_t DEFAULT_PERCENTAGE_OF_IN_USE = 100; + U_CDECL_BEGIN + 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 + + +@@ -70,12 +76,14 @@ CacheKeyBase::~CacheKeyBase() { + static void U_CALLCONV cacheInit(UErrorCode &status) { + U_ASSERT(gCache == nullptr); + 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 == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + } + if (U_FAILURE(status)) { +@@ -133,41 +141,53 @@ void UnifiedCache::setEvictionPolicy( + } + if (count < 0 || percentageOfInUseItems < 0) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return; + } ++#ifndef __wasi__ + std::lock_guard lock(*gCacheMutex); ++#endif + fMaxUnused = count; + fMaxPercentageOfInUse = percentageOfInUseItems; + } + + int32_t UnifiedCache::unusedCount() const { ++#ifndef __wasi__ + std::lock_guard lock(*gCacheMutex); ++#endif + return uhash_count(fHashtable) - fNumValuesInUse; + } + + int64_t UnifiedCache::autoEvictedCount() const { ++#ifndef __wasi__ + std::lock_guard lock(*gCacheMutex); ++#endif + return fAutoEvictedCount; + } + + int32_t UnifiedCache::keyCount() const { ++#ifndef __wasi__ + std::lock_guard lock(*gCacheMutex); ++#endif + return uhash_count(fHashtable); + } + + void UnifiedCache::flush() const { ++#ifndef __wasi__ + std::lock_guard 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 + // flushing. + while (_flush(false)); + } + + void UnifiedCache::handleUnreferencedObject() const { ++#ifndef __wasi__ + std::lock_guard lock(*gCacheMutex); ++#endif + --fNumValuesInUse; + _runEvictionSlice(); + } + + #ifdef UNIFIED_CACHE_DEBUG +@@ -182,11 +202,13 @@ void UnifiedCache::dump() { + } + cache->dumpContents(); + } + + void UnifiedCache::dumpContents() const { ++#ifndef __wasi__ + std::lock_guard lock(*gCacheMutex); ++#endif + _dumpContents(); + } + + // Dumps content of cache. + // On entry, gCacheMutex must be held. +@@ -222,11 +244,13 @@ UnifiedCache::~UnifiedCache() { + flush(); + { + // 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 lock(*gCacheMutex); ++#endif + _flush(true); + } + uhash_close(fHashtable); + fHashtable = nullptr; + delete fNoValue; +@@ -323,11 +347,13 @@ void UnifiedCache::_putNew( + + void UnifiedCache::_putIfAbsentAndGet( + const CacheKeyBase &key, + const SharedObject *&value, + UErrorCode &status) const { ++#ifndef __wasi__ + std::lock_guard lock(*gCacheMutex); ++#endif + const UHashElement *element = uhash_find(fHashtable, &key); + if (element != nullptr && !_inProgress(element)) { + _fetch(element, value, status); + return; + } +@@ -348,18 +374,22 @@ UBool UnifiedCache::_poll( + const CacheKeyBase &key, + const SharedObject *&value, + UErrorCode &status) const { + U_ASSERT(value == nullptr); + U_ASSERT(status == U_ZERO_ERROR); ++#ifndef __wasi__ + std::unique_lock 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 != nullptr && _inProgress(element)) { ++#ifndef __wasi__ + gInProgressValueAddedCond->wait(lock); ++#endif + element = uhash_find(fHashtable, &key); + } + + // If the hash table contains an entry for the key, + // fetch out the contents and return them. +@@ -426,13 +456,15 @@ void UnifiedCache::_put( + UHashElement *ptr = const_cast(element); + ptr->value.pointer = (void *) value; + 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( + const UHashElement *element, + const SharedObject *&value, +diff --git a/intl/icu/source/i18n/decContext.h b/intl/icu/source/i18n/decContext.h +index 59ab65e..20f3526 100644 +--- a/intl/icu/source/i18n/decContext.h ++++ b/intl/icu/source/i18n/decContext.h +@@ -61,7 +61,9 @@ + /* #include */ /* C99 standard integers */ + #endif + #include /* for printf, etc. */ ++#ifndef __wasi__ + #include /* 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 daa1129..c8f1eda 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(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(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 9ecd776..d094289 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 + #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 ++#endif ++ + U_NAMESPACE_BEGIN + namespace number { + namespace impl { +@@ -193,10 +196,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 +--- a/intl/icu/source/i18n/numrange_fluent.cpp ++++ b/intl/icu/source/i18n/numrange_fluent.cpp +@@ -238,33 +238,53 @@ LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(LocalizedNumberRang + + LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS&& src) noexcept + : NFS(std::move(src)) { + // Steal the compiled formatter + LNF&& _src = static_cast(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) { + if (this == &other) { return *this; } // self-assignment: no-op + NFS::operator=(static_cast&>(other)); + // Do not steal; just clear ++#ifndef __wasi__ + delete fAtomicFormatter.exchange(nullptr); ++#else ++ delete fAtomicFormatter; ++#endif + return *this; + } + + LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(LNF&& src) noexcept { + NFS::operator=(static_cast&&>(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) { + fMacros = macros; + fMacros.locale = locale; +@@ -344,11 +364,15 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const { + if (U_FAILURE(status)) { + return nullptr; + } + + // First try to get the pre-computed formatter ++#ifndef __wasi__ + auto* ptr = fAtomicFormatter.load(); ++#else ++ auto* ptr = fAtomicFormatter; ++#endif + if (ptr != nullptr) { + return ptr; + } + + // Try computing the formatter on our own +@@ -364,18 +388,23 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const { + + // 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 formatter object. + auto* nonConstThis = const_cast(this); ++#ifndef __wasi__ + if (!nonConstThis->fAtomicFormatter.compare_exchange_strong(ptr, temp)) { + // Another thread beat us to computing the formatter + delete temp; + return ptr; + } else { + // Our copy of the formatter got stored in the atomic + return temp; + } ++#else ++ nonConstThis->fAtomicFormatter = temp; ++ return temp; ++#endif + + } + + + #endif /* #if !UCONFIG_NO_FORMATTING */ +diff --git a/intl/icu/source/i18n/unicode/numberrangeformatter.h b/intl/icu/source/i18n/unicode/numberrangeformatter.h +index b9a4600..0ba2fa0 100644 +--- a/intl/icu/source/i18n/unicode/numberrangeformatter.h ++++ b/intl/icu/source/i18n/unicode/numberrangeformatter.h +@@ -10,7 +10,6 @@ + + #if !UCONFIG_NO_FORMATTING + +-#include + #include "unicode/appendable.h" + #include "unicode/fieldpos.h" + #include "unicode/formattedvalue.h" +@@ -18,6 +17,10 @@ + #include "unicode/numberformatter.h" + #include "unicode/unumberrangeformatter.h" + ++#ifndef __wasi__ ++#include ++#endif ++ + /** + * \file + * \brief C++ API: Library for localized formatting of number, currency, and unit ranges. +@@ -77,7 +80,9 @@ struct UFormattedNumberRangeImpl; + } // 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 +@@ -546,7 +551,11 @@ class U_I18N_API LocalizedNumberRangeFormatter + ~LocalizedNumberRangeFormatter(); + + private: ++#ifndef __wasi__ + std::atomic fAtomicFormatter = {}; ++#else ++ impl::NumberRangeFormatterImpl* fAtomicFormatter = nullptr; ++#endif + + const impl::NumberRangeFormatterImpl* getFormatter(UErrorCode& stauts) const; + -- cgit v1.2.3