Skip to content

Commit be50023

Browse files
Apply WASI support patch against ICU source tree (#35) (#43)
* Cherry-pick "ICU-22838 Add WebAssembly/WASI cross-compilation support" The original patch is still under review in the upstream ICU project, but it is needed to unblock the swift-foundation build on WebAssembly. See unicode-org/icu#3067 * [Build] Update compile definitions for WASI target `U_TIMEZONE` must not be defined and dynamic loading features must be disabled for WASI target. Co-authored-by: Yuta Saito <[email protected]>
1 parent 8a12a1c commit be50023

File tree

11 files changed

+216
-26
lines changed

11 files changed

+216
-26
lines changed

CMakeLists.txt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,20 +57,22 @@ if(CMAKE_SYSTEM_NAME STREQUAL Windows)
5757
$<$<COMPILE_LANGUAGE:C,CXX>:U_TIMEZONE=_timezone>
5858
$<$<COMPILE_LANGUAGE:C,CXX>:_CRT_SECURE_NO_DEPRECATE>
5959
$<$<COMPILE_LANGUAGE:C,CXX>:U_PLATFORM_USES_ONLY_WIN32_API>)
60-
else()
61-
add_compile_definitions(
62-
$<$<COMPILE_LANGUAGE:C,CXX>:U_TIMEZONE=timezone>)
63-
endif()
64-
# WASI specific settings
65-
if(CMAKE_SYSTEM_NAME STREQUAL WASI)
60+
elseif(CMAKE_SYSTEM_NAME STREQUAL WASI)
61+
# WASI specific settings
6662
add_compile_definitions(
6763
$<$<COMPILE_LANGUAGE:C,CXX>:U_HAVE_TZSET=0>
6864
$<$<COMPILE_LANGUAGE:C,CXX>:U_HAVE_TZNAME=0>
6965
$<$<COMPILE_LANGUAGE:C,CXX>:U_HAVE_TIMEZONE=0>
66+
$<$<COMPILE_LANGUAGE:C,CXX>:HAVE_DLFCN_H=0>
67+
$<$<COMPILE_LANGUAGE:C,CXX>:HAVE_DLOPEN=0>
68+
$<$<COMPILE_LANGUAGE:C,CXX>:U_ENABLE_DYLOAD=0>
7069
$<$<COMPILE_LANGUAGE:C,CXX>:_WASI_EMULATED_SIGNAL>
7170
$<$<COMPILE_LANGUAGE:C,CXX>:_WASI_EMULATED_MMAN>)
7271
add_link_options("-Lwasi-emulated-signal")
7372
add_link_options("-Lwasi-emulated-mman")
73+
else()
74+
add_compile_definitions(
75+
$<$<COMPILE_LANGUAGE:C,CXX>:U_TIMEZONE=timezone>)
7476
endif()
7577

7678
if(BUILD_SHARED_LIBS)

Package.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ var buildSettings: [CXXSetting] = [
3838
.define("U_COMMON_IMPLEMENTATION"),
3939
.define("U_I18N_IMPLEMENTATION"),
4040
.define("U_IO_IMPLEMENTATION"),
41+
.define("HAVE_DLFCN_H", to: "0", .when(platforms: [.wasi])),
42+
.define("HAVE_DLOPEN", to: "0", .when(platforms: [.wasi])),
43+
.define("U_ENABLE_DYLOAD", to: "0", .when(platforms: [.wasi])),
44+
4145
// Where data are stored
4246
.define("ICU_DATA_DIR", to: "\"/usr/share/icu/\""),
4347
.define("USE_PACKAGE_DATA", to: "1"),

icuSources/common/putilimp.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ typedef size_t uintptr_t;
103103
#endif
104104
#elif U_PLATFORM == U_PF_OS400
105105
/* not defined */
106+
#elif defined(__wasi__)
107+
/* not defined */
106108
#else
107109
# define U_TZSET tzset
108110
#endif
@@ -128,6 +130,8 @@ typedef size_t uintptr_t;
128130
/* not defined */
129131
#elif U_PLATFORM == U_PF_IPHONE
130132
/* not defined */
133+
#elif defined(__wasi__)
134+
/* not defined */
131135
#else
132136
# define U_TIMEZONE timezone
133137
#endif
@@ -141,6 +145,8 @@ typedef size_t uintptr_t;
141145
#endif
142146
#elif U_PLATFORM == U_PF_OS400
143147
/* not defined */
148+
#elif defined(__wasi__)
149+
/* not defined */
144150
#else
145151
# define U_TZNAME tzname
146152
#endif

icuSources/common/umutex.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ U_NAMESPACE_BEGIN
4343
*
4444
*************************************************************************************************/
4545

46+
#if U_HAVE_ATOMICS
4647
namespace {
4748
std::mutex *initMutex;
4849
std::condition_variable *initCondition;
@@ -55,9 +56,11 @@ std::once_flag initFlag;
5556
std::once_flag *pInitFlag = &initFlag;
5657

5758
} // Anonymous namespace
59+
#endif
5860

5961
U_CDECL_BEGIN
6062
static UBool U_CALLCONV umtx_cleanup() {
63+
#if U_HAVE_ATOMICS
6164
initMutex->~mutex();
6265
initCondition->~condition_variable();
6366
UMutex::cleanup();
@@ -66,17 +69,21 @@ static UBool U_CALLCONV umtx_cleanup() {
6669
// Do not use this trick anywhere else in ICU; use umtx_initOnce, not std::call_once().
6770
pInitFlag->~once_flag();
6871
pInitFlag = new(&initFlag) std::once_flag();
72+
#endif
6973
return true;
7074
}
7175

7276
static void U_CALLCONV umtx_init() {
77+
#if U_HAVE_ATOMICS
7378
initMutex = STATIC_NEW(std::mutex);
7479
initCondition = STATIC_NEW(std::condition_variable);
7580
ucln_common_registerCleanup(UCLN_COMMON_MUTEX, umtx_cleanup);
81+
#endif
7682
}
7783
U_CDECL_END
7884

7985

86+
#if U_HAVE_ATOMICS
8087
std::mutex *UMutex::getMutex() {
8188
std::mutex *retPtr = fMutex.load(std::memory_order_acquire);
8289
if (retPtr == nullptr) {
@@ -93,14 +100,17 @@ std::mutex *UMutex::getMutex() {
93100
U_ASSERT(retPtr != nullptr);
94101
return retPtr;
95102
}
103+
#endif
96104

97105
UMutex *UMutex::gListHead = nullptr;
98106

99107
void UMutex::cleanup() {
100108
UMutex *next = nullptr;
101109
for (UMutex *m = gListHead; m != nullptr; m = next) {
110+
#if U_HAVE_ATOMICS
102111
(*m->fMutex).~mutex();
103112
m->fMutex = nullptr;
113+
#endif
104114
next = m->fListLink;
105115
m->fListLink = nullptr;
106116
}
@@ -110,20 +120,24 @@ void UMutex::cleanup() {
110120

111121
U_CAPI void U_EXPORT2
112122
umtx_lock(UMutex *mutex) {
123+
#if U_HAVE_ATOMICS
113124
if (mutex == nullptr) {
114125
mutex = &globalMutex;
115126
}
116127
mutex->lock();
128+
#endif
117129
}
118130

119131

120132
U_CAPI void U_EXPORT2
121133
umtx_unlock(UMutex* mutex)
122134
{
135+
#if U_HAVE_ATOMICS
123136
if (mutex == nullptr) {
124137
mutex = &globalMutex;
125138
}
126139
mutex->unlock();
140+
#endif
127141
}
128142

129143

@@ -143,18 +157,22 @@ umtx_unlock(UMutex* mutex)
143157
//
144158
U_COMMON_API UBool U_EXPORT2
145159
umtx_initImplPreInit(UInitOnce &uio) {
160+
#if U_HAVE_ATOMICS
146161
std::call_once(*pInitFlag, umtx_init);
147162
std::unique_lock<std::mutex> lock(*initMutex);
163+
#endif
148164
if (umtx_loadAcquire(uio.fState) == 0) {
149165
umtx_storeRelease(uio.fState, 1);
150166
return true; // Caller will next call the init function.
151167
} else {
168+
#if U_HAVE_ATOMICS
152169
while (umtx_loadAcquire(uio.fState) == 1) {
153170
// Another thread is currently running the initialization.
154171
// Wait until it completes.
155172
initCondition->wait(lock);
156173
}
157174
U_ASSERT(uio.fState == 2);
175+
#endif
158176
return false;
159177
}
160178
}
@@ -168,11 +186,13 @@ umtx_initImplPreInit(UInitOnce &uio) {
168186

169187
U_COMMON_API void U_EXPORT2
170188
umtx_initImplPostInit(UInitOnce &uio) {
189+
#if U_HAVE_ATOMICS
171190
{
172191
std::unique_lock<std::mutex> lock(*initMutex);
173192
umtx_storeRelease(uio.fState, 2);
174193
}
175194
initCondition->notify_all();
195+
#endif
176196
}
177197

178198
U_NAMESPACE_END

icuSources/common/umutex.h

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@
2020
#ifndef UMUTEX_H
2121
#define UMUTEX_H
2222

23-
#include <atomic>
24-
#include <condition_variable>
25-
#include <mutex>
2623
#include <type_traits>
2724

2825
#include <_foundation_unicode/utypes.h>
@@ -37,6 +34,12 @@
3734
#error U_USER_ATOMICS and U_USER_MUTEX_H are not supported
3835
#endif
3936

37+
#if U_HAVE_ATOMICS
38+
39+
#include <atomic>
40+
#include <condition_variable>
41+
#include <mutex>
42+
4043
// Export an explicit template instantiation of std::atomic<int32_t>.
4144
// When building DLLs for Windows this is required as it is used as a data member of the exported SharedObject class.
4245
// See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
@@ -61,6 +64,7 @@ template struct std::atomic<std::mutex *>;
6164
#endif
6265
#endif
6366

67+
#endif
6468

6569
U_NAMESPACE_BEGIN
6670

@@ -70,6 +74,8 @@ U_NAMESPACE_BEGIN
7074
*
7175
****************************************************************************/
7276

77+
#if U_HAVE_ATOMICS
78+
7379
typedef std::atomic<int32_t> u_atomic_int32_t;
7480

7581
inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
@@ -88,6 +94,29 @@ inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
8894
return var->fetch_sub(1) - 1;
8995
}
9096

97+
#else
98+
99+
// No atomic operations available. Use a simple int32_t instead.
100+
101+
typedef int32_t u_atomic_int32_t;
102+
103+
inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
104+
return var;
105+
}
106+
107+
inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
108+
var = val;
109+
}
110+
111+
inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
112+
return ++(*var);
113+
}
114+
115+
inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
116+
return --(*var);
117+
}
118+
119+
#endif
91120

92121
/*************************************************************************************************
93122
*
@@ -227,17 +256,25 @@ class U_COMMON_API UMutex {
227256

228257
// requirements for C++ BasicLockable, allows UMutex to work with std::lock_guard
229258
void lock() {
259+
#if U_HAVE_ATOMICS
230260
std::mutex *m = fMutex.load(std::memory_order_acquire);
231261
if (m == nullptr) { m = getMutex(); }
232262
m->lock();
263+
#endif
264+
}
265+
void unlock() {
266+
#if U_HAVE_ATOMICS
267+
fMutex.load(std::memory_order_relaxed)->unlock();
268+
#endif
233269
}
234-
void unlock() { fMutex.load(std::memory_order_relaxed)->unlock(); }
235270

236271
static void cleanup();
237272

238273
private:
274+
#if U_HAVE_ATOMICS
239275
alignas(std::mutex) char fStorage[sizeof(std::mutex)] {};
240276
std::atomic<std::mutex *> fMutex { nullptr };
277+
#endif
241278

242279
/** All initialized UMutexes are kept in a linked list, so that they can be found,
243280
* and the underlying std::mutex destructed, by u_cleanup().
@@ -249,7 +286,9 @@ class U_COMMON_API UMutex {
249286
* Initial fast check is inline, in lock(). The returned value may never
250287
* be nullptr.
251288
*/
289+
#if U_HAVE_ATOMICS
252290
std::mutex *getMutex();
291+
#endif
253292
};
254293

255294

0 commit comments

Comments
 (0)