diff --git a/eng/Versions.props b/eng/Versions.props
index b2e4931d09e..aba8d06cd49 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -8,4 +8,7 @@
8.0.0-beta.23067.5
+
+ 16
+
diff --git a/eng/azure-pipelines.yml b/eng/azure-pipelines.yml
index 8a4e2cb750a..6f4e35baa89 100644
--- a/eng/azure-pipelines.yml
+++ b/eng/azure-pipelines.yml
@@ -77,6 +77,51 @@ stages:
artifactName: Artifacts_Browser_Threading
condition: and(succeeded(), ne(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest'))
+ ############ WASI BUILD ############
+ - job: Build_Wasi
+ displayName: Wasi
+ timeoutInMinutes: 360
+ pool:
+ ${{ if eq(variables['System.TeamProject'], 'public') }}:
+ vmImage: ubuntu-20.04
+ ${{ if eq(variables['System.TeamProject'], 'internal') }}:
+ name: NetCore1ESPool-Internal
+ demands: ImageOverride -equals Build.Ubuntu.1804.Amd64
+ container:
+ image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-webassembly
+ steps:
+ - bash: |
+ ./build.sh --ci --restore --build --configuration $(_BuildConfig) /p:TargetOS=Wasi /p:TargetArchitecture=wasm $(_InternalBuildArgs)
+ displayName: Build
+ - task: PublishPipelineArtifact@1
+ displayName: Upload artifacts
+ inputs:
+ targetPath: 'artifacts/bin'
+ artifactName: Artifacts_Wasi
+ condition: and(succeeded(), ne(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest'))
+
+ - job: Build_Wasi_Threading
+ displayName: Wasi_Threading
+ timeoutInMinutes: 360
+ pool:
+ ${{ if eq(variables['System.TeamProject'], 'public') }}:
+ vmImage: ubuntu-20.04
+ ${{ if eq(variables['System.TeamProject'], 'internal') }}:
+ name: NetCore1ESPool-Internal
+ demands: ImageOverride -equals Build.Ubuntu.1804.Amd64
+ container:
+ image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-webassembly
+ steps:
+ - bash: |
+ ./build.sh --ci --restore --build --configuration $(_BuildConfig) /p:TargetOS=Wasi /p:TargetArchitecture=wasm /p:WasmEnableThreads=true $(_InternalBuildArgs)
+ displayName: Build
+ - task: PublishPipelineArtifact@1
+ displayName: Upload artifacts
+ inputs:
+ targetPath: 'artifacts/bin'
+ artifactName: Artifacts_Wasi_Threading
+ condition: and(succeeded(), ne(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest'))
+
############ iOS BUILD ############
- job: Build_iOS
displayName: iOS
@@ -168,6 +213,8 @@ stages:
dependsOn:
- Build_Browser
- Build_Browser_Threading
+ - Build_Wasi
+ - Build_Wasi_Threading
- Build_iOS
- Build_MacCatalyst
- Build_tvOS
@@ -188,6 +235,14 @@ stages:
inputs:
artifact: Artifacts_Browser_Threading
path: 'artifacts/bin/browser-threading'
+ - task: DownloadPipelineArtifact@2
+ inputs:
+ artifact: Artifacts_Wasi
+ path: 'artifacts/bin'
+ - task: DownloadPipelineArtifact@2
+ inputs:
+ artifact: Artifacts_Wasi_Threading
+ path: 'artifacts/bin/wasi-threading'
- task: DownloadPipelineArtifact@2
inputs:
artifact: Artifacts_iOS
diff --git a/eng/icu.mk b/eng/icu.mk
index 0cd7ce0fa69..bee46795c07 100644
--- a/eng/icu.mk
+++ b/eng/icu.mk
@@ -91,8 +91,8 @@ data-$(2): $(TARGET_OBJDIR)/$(1)/.stamp-configure | $(TARGET_OBJDIR)/$(1) $(TARG
endef
-ifeq ($(TARGET_OS),browser)
-$(eval $(call TargetBuildTemplate,icudt_browser,icudt))
+ifeq ($(TARGET_ARCHITECTURE),wasm)
+$(eval $(call TargetBuildTemplate,icudt_wasm,icudt))
else
$(eval $(call TargetBuildTemplate,icudt_mobile,icudt))
endif
diff --git a/eng/icu.proj b/eng/icu.proj
index da08c33e49d..ffb4d60dc7f 100644
--- a/eng/icu.proj
+++ b/eng/icu.proj
@@ -1,5 +1,7 @@
-
+
+
+
@@ -7,10 +9,15 @@
<_ExtraParams Condition="'$(WasmEnableThreads)' == 'true'">WASM_ENABLE_THREADS=true
+
+
+ $(RepoRoot)artifacts/wasi-sdk
+
+
@@ -37,4 +44,19 @@
Lines="@(_ItemsFromEmscriptenVersionFile->Replace('"', ''))"
Overwrite="true" />
+
+
+
+
+ <_WasiLocalPath>$(RepoRoot)\artifacts
+ <_WasiSdkUrl Condition="$([MSBuild]::IsOSPlatform('Linux'))">https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$(WasiSdkVersion)/wasi-sdk-$(WasiSdkVersion).0-linux.tar.gz
+ <_WasiSdkUrl Condition="$([MSBuild]::IsOSPlatform('OSX'))">https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$(WasiSdkVersion)/wasi-sdk-$(WasiSdkVersion).0-macos.tar.gz
+
+
+
+
+
+
diff --git a/eng/icu.wasi.mk b/eng/icu.wasi.mk
new file mode 100644
index 00000000000..199ba8898e8
--- /dev/null
+++ b/eng/icu.wasi.mk
@@ -0,0 +1,29 @@
+# TODO: add other host platform/arch combinations
+UNAME_S := $(shell uname -s)
+UNAME_M := $(shell uname -m)
+UNAME_R := $(shell uname -r)
+
+ifeq ($(UNAME_S),Linux)
+ HOST_PLATFORM=x86_64-pc-linux-gnu
+endif
+ifeq ($(UNAME_S),Darwin)
+ ifeq ($(UNAME_M),arm64)
+ HOST_PLATFORM=arm64-apple-darwin$(UNAME_R)
+ endif
+ ifeq ($(UNAME_M),x86_64)
+ HOST_PLATFORM=x86_64-apple-darwin$(UNAME_R)
+ endif
+endif
+ifeq ($(WASM_ENABLE_THREADS),true)
+ THREADS_FLAG="-pthread"
+endif
+
+CONFIGURE_COMPILER_FLAGS += \
+ CFLAGS="-Oz -fno-exceptions -Wno-sign-compare $(THREADS_FLAG) $(ICU_DEFINES)" \
+ CXXFLAGS="-Oz -fno-exceptions -Wno-sign-compare $(THREADS_FLAG) $(ICU_DEFINES)" \
+ CC="$(WASI_SDK_PATH)/bin/clang --sysroot=$(WASI_SDK_PATH)/share/wasi-sysroot" \
+ CXX="$(WASI_SDK_PATH)/bin/clang++ --sysroot=$(WASI_SDK_PATH)/share/wasi-sysroot" \
+ --host=$(HOST_PLATFORM) --build=wasm32
+
+check-env:
+ :
\ No newline at end of file
diff --git a/icu-filters/icudt_browser.json b/icu-filters/icudt_wasm.json
similarity index 100%
rename from icu-filters/icudt_browser.json
rename to icu-filters/icudt_wasm.json
diff --git a/icu-patches/patches/020-MSFT-Patch-ICU_wasi_workaround.patch b/icu-patches/patches/020-MSFT-Patch-ICU_wasi_workaround.patch
new file mode 100644
index 00000000000..c5732f589f1
--- /dev/null
+++ b/icu-patches/patches/020-MSFT-Patch-ICU_wasi_workaround.patch
@@ -0,0 +1,714 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Meri Khamoyan
+Date: Thu, 19 Jan 2023 18:21:31 +0100
+Subject: Fix icu for wasi
+# Handle WASI lack of support for and .
+#
+# WASI issue: https://github.com/WebAssembly/wasi-sdk/issues/180
+
+diff --git a/icu/icu4c/source/common/putilimp.h b/icu/icu4c/source/common/putilimp.h
+index a325c6c359ad26f1c7202ff4700afa39b5d284c3..ab5e8ac68ad6c1e92feecce83ef0b42c21450115 100644
+--- a/icu/icu4c/source/common/putilimp.h
++++ b/icu/icu4c/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/icu/icu4c/source/common/umapfile.h b/icu/icu4c/source/common/umapfile.h
+index 92bd567a2a98952845eb489391092a6a64d9dfbc..4ed1112bc6dfaf96e6d106d4fead783229a87ab5 100644
+--- a/icu/icu4c/source/common/umapfile.h
++++ b/icu/icu4c/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/icu/icu4c/source/common/umutex.cpp b/icu/icu4c/source/common/umutex.cpp
+index ccbee9960a39e7bea47b4f76a41e30ae671e5f0f..729644eed9c93699db2676c3b8d20878d886ba38 100644
+--- a/icu/icu4c/source/common/umutex.cpp
++++ b/icu/icu4c/source/common/umutex.cpp
+@@ -42,7 +42,7 @@ U_NAMESPACE_BEGIN
+ * ICU Mutex wrappers.
+ *
+ *************************************************************************************************/
+-
++#ifndef __wasi__
+ namespace {
+ std::mutex *initMutex;
+ std::condition_variable *initCondition;
+@@ -55,9 +55,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 +68,20 @@ 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 +98,16 @@ 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 +117,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 +154,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 +183,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/icu/icu4c/source/common/umutex.h b/icu/icu4c/source/common/umutex.h
+index 8d76b3f3e6f59628779774cbb993307655b2729b..3f3ba1defc5b5d3e532bb4b592dd3d9cdc05b880 100644
+--- a/icu/icu4c/source/common/umutex.h
++++ b/icu/icu4c/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"
+@@ -36,7 +39,7 @@
+ // See issue ICU-20185.
+ #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.
+@@ -60,7 +63,7 @@ template struct std::atomic;
+ template struct std::atomic;
+ #endif
+ #endif
+-
++#endif
+
+ U_NAMESPACE_BEGIN
+
+@@ -69,7 +72,7 @@ U_NAMESPACE_BEGIN
+ * Low Level Atomic Operations, ICU wrappers for.
+ *
+ ****************************************************************************/
+-
++#ifndef __wasi__
+ typedef std::atomic u_atomic_int32_t;
+ #define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
+
+@@ -89,7 +92,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
+ /*************************************************************************************************
+ *
+ * UInitOnce Definitions.
+@@ -231,18 +255,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 +284,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/icu/icu4c/source/common/unifiedcache.cpp b/icu/icu4c/source/common/unifiedcache.cpp
+index 493ab79f6d9067e2e90e2dbf20dc41a6d24fae18..c5ca7ef97f018115aee85a09dfcee985a43ed453 100644
+--- a/icu/icu4c/source/common/unifiedcache.cpp
++++ b/icu/icu4c/source/common/unifiedcache.cpp
+@@ -13,15 +13,19 @@
+ #include "unifiedcache.h"
+
+ #include // For std::max()
++#ifndef __wasi__
+ #include
++#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
+@@ -71,9 +77,10 @@ static void U_CALLCONV cacheInit(UErrorCode &status) {
+ U_ASSERT(gCache == NULL);
+ 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,29 +142,38 @@ void UnifiedCache::setEvictionPolicy(
+ 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.
+@@ -165,7 +181,9 @@ void UnifiedCache::flush() const {
+ }
+
+ void UnifiedCache::handleUnreferencedObject() const {
++#ifndef __wasi__
+ std::lock_guard lock(*gCacheMutex);
++#endif
+ --fNumValuesInUse;
+ _runEvictionSlice();
+ }
+@@ -184,7 +202,9 @@ void UnifiedCache::dump() {
+ }
+
+ void UnifiedCache::dumpContents() const {
++#ifndef __wasi__
+ std::lock_guard lock(*gCacheMutex);
++#endif
+ _dumpContents();
+ }
+
+@@ -224,7 +244,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 lock(*gCacheMutex);
++#endif
+ _flush(TRUE);
+ }
+ uhash_close(fHashtable);
+@@ -325,7 +347,9 @@ 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 != NULL && !_inProgress(element)) {
+ _fetch(element, value, status);
+@@ -350,14 +374,18 @@ UBool UnifiedCache::_poll(
+ UErrorCode &status) const {
+ U_ASSERT(value == NULL);
+ 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 != NULL && _inProgress(element)) {
++#ifndef __wasi__
+ gInProgressValueAddedCond->wait(lock);
++#endif
+ element = uhash_find(fHashtable, &key);
+ }
+
+@@ -430,7 +458,9 @@ void UnifiedCache::_put(
+
+ // Tell waiting threads that we replace in-progress status with
+ // an error.
++#ifndef __wasi__
+ gInProgressValueAddedCond->notify_all();
++#endif
+ }
+
+ void UnifiedCache::_fetch(
+diff --git a/icu/icu4c/source/i18n/decContext.h b/icu/icu4c/source/i18n/decContext.h
+index 59ab65e59271ac769d50864a10cb66cfd9d8607e..20f3526be8101233327be451f8c9d78d9b6f3c8b 100644
+--- a/icu/icu4c/source/i18n/decContext.h
++++ b/icu/icu4c/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/icu/icu4c/source/i18n/decimfmt.cpp b/icu/icu4c/source/i18n/decimfmt.cpp
+index daa1129a6ab1d70e9ee83c4f74f31fb640a3066f..9858ac901d841db5ff36be238f93226cadb58a74 100644
+--- a/icu/icu4c/source/i18n/decimfmt.cpp
++++ b/icu/icu4c/source/i18n/decimfmt.cpp
+@@ -479,9 +479,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 +1630,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 +1671,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 +1694,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 +1703,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 +1732,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 +1741,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/icu/icu4c/source/i18n/number_mapper.h b/icu/icu4c/source/i18n/number_mapper.h
+index 9ecd776b3b4795512159c3e60c3b2c32cbb81c50..6f55d27e6c5d93a5bbdfb2aeef7e5b55732a173f 100644
+--- a/icu/icu4c/source/i18n/number_mapper.h
++++ b/icu/icu4c/source/i18n/number_mapper.h
+@@ -7,7 +7,9 @@
+ #ifndef __NUMBER_MAPPER_H__
+ #define __NUMBER_MAPPER_H__
+
++#ifndef __wasi__
+ #include
++#endif
+ #include "number_types.h"
+ #include "unicode/currpinf.h"
+ #include "standardplural.h"
+@@ -193,11 +195,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/icu/icu4c/source/i18n/numrange_fluent.cpp b/icu/icu4c/source/i18n/numrange_fluent.cpp
+index d9286d1d713d2cecc5d803ee4c181a1360c53c99..5568c0a51f4be55439481bd90cebb2373d0d72e6 100644
+--- a/icu/icu4c/source/i18n/numrange_fluent.cpp
++++ b/icu/icu4c/source/i18n/numrange_fluent.cpp
+@@ -240,28 +240,49 @@ LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS&& src) U_N
+ : 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) {
+ 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) U_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) {
+@@ -345,7 +366,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;
+ }
+@@ -364,6 +389,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(this);
++#ifndef __wasi__
+ if (!nonConstThis->fAtomicFormatter.compare_exchange_strong(ptr, temp)) {
+ // Another thread beat us to computing the formatter
+ delete temp;
+@@ -372,6 +398,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/icu/icu4c/source/i18n/unicode/numberrangeformatter.h b/icu/icu4c/source/i18n/unicode/numberrangeformatter.h
+index 4e0a15badb14b8b7dd907ff34ca0f8e427071546..52253908aee0a39bb940d92f26dffc3675cb918f 100644
+--- a/icu/icu4c/source/i18n/unicode/numberrangeformatter.h
++++ b/icu/icu4c/source/i18n/unicode/numberrangeformatter.h
+@@ -9,8 +9,9 @@
+ #if U_SHOW_CPLUSPLUS_API
+
+ #if !UCONFIG_NO_FORMATTING
+-
++#ifndef __wasi__
+ #include
++#endif
+ #include "unicode/appendable.h"
+ #include "unicode/fieldpos.h"
+ #include "unicode/formattedvalue.h"
+@@ -77,7 +78,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,8 +549,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;
+
+ explicit LocalizedNumberRangeFormatter(
diff --git a/icu/icu4c/source/common/putilimp.h b/icu/icu4c/source/common/putilimp.h
index a325c6c359a..ab5e8ac68ad 100644
--- a/icu/icu4c/source/common/putilimp.h
+++ b/icu/icu4c/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/icu/icu4c/source/common/umapfile.h b/icu/icu4c/source/common/umapfile.h
index 92bd567a2a9..4ed1112bc6d 100644
--- a/icu/icu4c/source/common/umapfile.h
+++ b/icu/icu4c/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/icu/icu4c/source/common/umutex.cpp b/icu/icu4c/source/common/umutex.cpp
index ccbee9960a3..729644eed9c 100644
--- a/icu/icu4c/source/common/umutex.cpp
+++ b/icu/icu4c/source/common/umutex.cpp
@@ -42,7 +42,7 @@ U_NAMESPACE_BEGIN
* ICU Mutex wrappers.
*
*************************************************************************************************/
-
+#ifndef __wasi__
namespace {
std::mutex *initMutex;
std::condition_variable *initCondition;
@@ -55,9 +55,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 +68,20 @@ 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 +98,16 @@ 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 +117,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 +154,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 +183,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/icu/icu4c/source/common/umutex.h b/icu/icu4c/source/common/umutex.h
index 8d76b3f3e6f..3f3ba1defc5 100644
--- a/icu/icu4c/source/common/umutex.h
+++ b/icu/icu4c/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"
@@ -36,7 +39,7 @@
// See issue ICU-20185.
#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.
@@ -60,7 +63,7 @@ template struct std::atomic;
template struct std::atomic;
#endif
#endif
-
+#endif
U_NAMESPACE_BEGIN
@@ -69,7 +72,7 @@ U_NAMESPACE_BEGIN
* Low Level Atomic Operations, ICU wrappers for.
*
****************************************************************************/
-
+#ifndef __wasi__
typedef std::atomic u_atomic_int32_t;
#define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
@@ -89,7 +92,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
/*************************************************************************************************
*
* UInitOnce Definitions.
@@ -231,18 +255,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 +284,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/icu/icu4c/source/common/unifiedcache.cpp b/icu/icu4c/source/common/unifiedcache.cpp
index 493ab79f6d9..c5ca7ef97f0 100644
--- a/icu/icu4c/source/common/unifiedcache.cpp
+++ b/icu/icu4c/source/common/unifiedcache.cpp
@@ -13,15 +13,19 @@
#include "unifiedcache.h"
#include // For std::max()
+#ifndef __wasi__
#include
+#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
@@ -71,9 +77,10 @@ static void U_CALLCONV cacheInit(UErrorCode &status) {
U_ASSERT(gCache == NULL);
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,29 +142,38 @@ void UnifiedCache::setEvictionPolicy(
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.
@@ -165,7 +181,9 @@ void UnifiedCache::flush() const {
}
void UnifiedCache::handleUnreferencedObject() const {
+#ifndef __wasi__
std::lock_guard lock(*gCacheMutex);
+#endif
--fNumValuesInUse;
_runEvictionSlice();
}
@@ -184,7 +202,9 @@ void UnifiedCache::dump() {
}
void UnifiedCache::dumpContents() const {
+#ifndef __wasi__
std::lock_guard lock(*gCacheMutex);
+#endif
_dumpContents();
}
@@ -224,7 +244,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 lock(*gCacheMutex);
+#endif
_flush(TRUE);
}
uhash_close(fHashtable);
@@ -325,7 +347,9 @@ 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 != NULL && !_inProgress(element)) {
_fetch(element, value, status);
@@ -350,14 +374,18 @@ UBool UnifiedCache::_poll(
UErrorCode &status) const {
U_ASSERT(value == NULL);
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 != NULL && _inProgress(element)) {
+#ifndef __wasi__
gInProgressValueAddedCond->wait(lock);
+#endif
element = uhash_find(fHashtable, &key);
}
@@ -430,7 +458,9 @@ void UnifiedCache::_put(
// Tell waiting threads that we replace in-progress status with
// an error.
+#ifndef __wasi__
gInProgressValueAddedCond->notify_all();
+#endif
}
void UnifiedCache::_fetch(
diff --git a/icu/icu4c/source/i18n/decContext.h b/icu/icu4c/source/i18n/decContext.h
index 59ab65e5927..20f3526be81 100644
--- a/icu/icu4c/source/i18n/decContext.h
+++ b/icu/icu4c/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/icu/icu4c/source/i18n/decimfmt.cpp b/icu/icu4c/source/i18n/decimfmt.cpp
index daa1129a6ab..9858ac901d8 100644
--- a/icu/icu4c/source/i18n/decimfmt.cpp
+++ b/icu/icu4c/source/i18n/decimfmt.cpp
@@ -479,9 +479,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 +1630,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 +1671,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 +1694,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 +1703,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 +1732,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 +1741,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/icu/icu4c/source/i18n/number_mapper.h b/icu/icu4c/source/i18n/number_mapper.h
index 9ecd776b3b4..6f55d27e6c5 100644
--- a/icu/icu4c/source/i18n/number_mapper.h
+++ b/icu/icu4c/source/i18n/number_mapper.h
@@ -7,7 +7,9 @@
#ifndef __NUMBER_MAPPER_H__
#define __NUMBER_MAPPER_H__
+#ifndef __wasi__
#include
+#endif
#include "number_types.h"
#include "unicode/currpinf.h"
#include "standardplural.h"
@@ -193,11 +195,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/icu/icu4c/source/i18n/numrange_fluent.cpp b/icu/icu4c/source/i18n/numrange_fluent.cpp
index d9286d1d713..5568c0a51f4 100644
--- a/icu/icu4c/source/i18n/numrange_fluent.cpp
+++ b/icu/icu4c/source/i18n/numrange_fluent.cpp
@@ -240,28 +240,49 @@ LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS&& src) U_N
: 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) {
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) U_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) {
@@ -345,7 +366,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;
}
@@ -364,6 +389,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(this);
+#ifndef __wasi__
if (!nonConstThis->fAtomicFormatter.compare_exchange_strong(ptr, temp)) {
// Another thread beat us to computing the formatter
delete temp;
@@ -372,6 +398,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/icu/icu4c/source/i18n/unicode/numberrangeformatter.h b/icu/icu4c/source/i18n/unicode/numberrangeformatter.h
index 4e0a15badb1..52253908aee 100644
--- a/icu/icu4c/source/i18n/unicode/numberrangeformatter.h
+++ b/icu/icu4c/source/i18n/unicode/numberrangeformatter.h
@@ -9,8 +9,9 @@
#if U_SHOW_CPLUSPLUS_API
#if !UCONFIG_NO_FORMATTING
-
+#ifndef __wasi__
#include
+#endif
#include "unicode/appendable.h"
#include "unicode/fieldpos.h"
#include "unicode/formattedvalue.h"
@@ -77,7 +78,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,8 +549,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;
explicit LocalizedNumberRangeFormatter(