diff --git a/src/mono/mono/metadata/icall-signatures.h b/src/mono/mono/metadata/icall-signatures.h index d45f1a569c31e8..221fcae8d58865 100644 --- a/src/mono/mono/metadata/icall-signatures.h +++ b/src/mono/mono/metadata/icall-signatures.h @@ -57,7 +57,7 @@ // mono_icall_sig_void_int32 // mono_icall_sig_void_object // mono_icall_sig_void_ptr -// mono_icall_sig_bool_ptr_ptrref +// mono_icall_sig_boolean_ptr_ptrref // mono_icall_sig_double_double_double // mono_icall_sig_float_float_float // mono_icall_sig_int_obj_ptr @@ -94,7 +94,7 @@ // mono_icall_sig_void_ptr_ptr // mono_icall_sig_void_ptr_ptrref // mono_icall_sig_void_uint32_ptrref -// mono_icall_sig_bool_ptr_int32_ptrref +// mono_icall_sig_boolean_ptr_int32_ptrref // mono_icall_sig_int32_int32_ptr_ptrref // mono_icall_sig_int32_ptr_int32_ptr // mono_icall_sig_int32_ptr_int32_ptrref @@ -182,7 +182,7 @@ ICALL_SIG (2, (void, int)) \ ICALL_SIG (2, (void, int32)) \ ICALL_SIG (2, (void, object)) \ ICALL_SIG (2, (void, ptr)) \ -ICALL_SIG (3, (bool, ptr, ptrref)) \ +ICALL_SIG (3, (boolean, ptr, ptrref)) \ ICALL_SIG (3, (double, double, double)) \ ICALL_SIG (3, (float, float, float)) \ ICALL_SIG (3, (int, obj, ptr)) \ @@ -222,7 +222,7 @@ ICALL_SIG (3, (void, ptr, object)) \ ICALL_SIG (3, (void, ptr, ptr)) \ ICALL_SIG (3, (void, ptr, ptrref)) \ ICALL_SIG (3, (void, uint32, ptrref)) \ -ICALL_SIG (4, (bool, ptr, int32, ptrref)) \ +ICALL_SIG (4, (boolean, ptr, int32, ptrref)) \ ICALL_SIG (4, (int32, int32, ptr, ptrref)) \ ICALL_SIG (4, (int32, ptr, int32, ptr)) \ ICALL_SIG (4, (int32, ptr, int32, ptrref)) \ diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index c5c21f7ec75fcb..75d06bace0fe8c 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -7186,8 +7186,7 @@ mono_lookup_icall_symbol (MonoMethod *m) // // mono_create_icall_signatures depends on this order. Handle with care. typedef enum ICallSigType { - ICALL_SIG_TYPE_bool = 0x00, - ICALL_SIG_TYPE_boolean = ICALL_SIG_TYPE_bool, + ICALL_SIG_TYPE_boolean = 0x00, ICALL_SIG_TYPE_double = 0x01, ICALL_SIG_TYPE_float = 0x02, ICALL_SIG_TYPE_int = 0x03, @@ -7265,7 +7264,7 @@ mono_create_icall_signatures (void) typedef gsize G_MAY_ALIAS gsize_a; MonoType * const lookup [ ] = { - m_class_get_byval_arg (mono_defaults.boolean_class), // ICALL_SIG_TYPE_bool + m_class_get_byval_arg (mono_defaults.boolean_class), // ICALL_SIG_TYPE_boolean m_class_get_byval_arg (mono_defaults.double_class), // ICALL_SIG_TYPE_double m_class_get_byval_arg (mono_defaults.single_class), // ICALL_SIG_TYPE_float m_class_get_byval_arg (mono_defaults.int32_class), // ICALL_SIG_TYPE_int diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index a5fbebee0c5e94..2cd2dbc234f21d 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -14612,8 +14612,8 @@ add_preinit_got_slots (MonoAotCompile *acfg) #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE static MonoMethodSignature * const * const interp_in_static_sigs [] = { - &mono_icall_sig_bool_ptr_int32_ptrref, - &mono_icall_sig_bool_ptr_ptrref, + &mono_icall_sig_boolean_ptr_int32_ptrref, + &mono_icall_sig_boolean_ptr_ptrref, &mono_icall_sig_int32_int32_ptrref, &mono_icall_sig_int32_int32_ptr_ptrref, &mono_icall_sig_int32_ptr_int32_ptr, diff --git a/src/mono/mono/tools/offsets-tool/offsets-tool.py b/src/mono/mono/tools/offsets-tool/offsets-tool.py index dd30025c1e7bf8..2dbaa1c2eacb68 100644 --- a/src/mono/mono/tools/offsets-tool/offsets-tool.py +++ b/src/mono/mono/tools/offsets-tool/offsets-tool.py @@ -94,7 +94,9 @@ def require_emscipten_path (args): self.target_args += ["-target", args.abi] else: require_emscipten_path (args) - self.sys_includes = [args.emscripten_path + "/system/include", args.emscripten_path + "/system/include/libc", args.emscripten_path + "/system/lib/libc/musl/arch/emscripten", args.emscripten_path + "/system/lib/libc/musl/include", args.emscripten_path + "/system/lib/libc/musl/arch/generic"] + clang_path = os.path.dirname(args.libclang) + self.sys_includes = [args.emscripten_path + "/system/include", args.emscripten_path + "/system/include/libc", args.emscripten_path + "/system/lib/libc/musl/arch/emscripten", args.emscripten_path + "/system/lib/libc/musl/include", args.emscripten_path + "/system/lib/libc/musl/arch/generic", + clang_path + "/../lib/clang/16/include"] self.target = Target ("TARGET_WASM", None, []) self.target_args += ["-target", args.abi] diff --git a/src/mono/mono/utils/atomic.h b/src/mono/mono/utils/atomic.h index 7d00cbcd7403e0..5d276fa7612523 100644 --- a/src/mono/mono/utils/atomic.h +++ b/src/mono/mono/utils/atomic.h @@ -25,7 +25,281 @@ F/MonoDroid( 1568): shared runtime initialization error: Cannot load library: re Apple targets have historically being problematic, xcode 4.6 would miscompile the intrinsic. */ -#if defined(HOST_WIN32) +/* For each platform, decide what atomic implementation to use. + * + * Generally, we can enable C11 atomics if the header is available and if all the primitive types we + * care about (int, long, void*, long long) are lock-free. + * + * Note that we generally don't want the compiler's locking implementation because it may take a + * global lock, in which case if the atomic is used by both the GC implementation and runtime + * internals we may have deadlocks during GC suspend. + * + * It might be possible to use some Mono specific implementation for specific types (e.g. long long) + * on some platforms if the standard atomics for some type are not lock-free (for example: long + * long). We might be able to use a GC-aware lock, for example. + * + */ +#undef MONO_USE_C11_ATOMIC +#undef MONO_USE_WIN32_ATOMIC +#undef MONO_USE_GCC_ATOMIC +#undef MONO_USE_EMULATED_ATOMIC + +#if defined(MONO_GENERATING_OFFSETS) + /* + * Hack: for the offsets tool, define MONO_USE_EMULATED_ATOMIC since it doesn't actually need to see + * the impementation, and the stdatomic ones cause problems on some Linux configurations where + * libclang sees the platform header, not the clang one. + */ +# define MONO_USE_EMULATED_ATOMIC 1 +#elif defined(_MSC_VER) || defined(HOST_WIN32) + /* + * we need two things to switch to C11 atomics on Windows: + * + * 1. MSVC atomics support is not experimental, or we pass /experimental:c11atomics + * + * 2. We build our C++ code with C++23 or later (otherwise MSVC will complain about including + * stdatomic.h) + * + */ +# define MONO_USE_WIN32_ATOMIC 1 +#elif defined(HOST_IOS) || defined(HOST_OSX) || defined(HOST_WATCHOS) || defined(HOST_TVOS) +# define MONO_USE_C11_ATOMIC 1 +#elif defined(HOST_ANDROID) + /* on Android-x86 ATOMIC_LONG_LONG_LOCK_FREE == 1, not 2 like we want. */ + /* on Andriod-x64 ATOMIC_LONG_LOCK_FREE == 1, not 2 */ + /* on Android-armv7 ATOMIC_INT_LOCK_FREE == 1, not 2 */ +# if defined(HOST_ARM64) +# define MONO_USE_C11_ATOMIC 1 +# elif defined(USE_GCC_ATOMIC_OPS) +# define MONO_USE_GCC_ATOMIC 1 +# else +# define MONO_USE_EMULATED_ATOMIC 1 +# endif +#elif defined(HOST_LINUX) + /* FIXME: probably need arch checks */ +# define MONO_USE_C11_ATOMIC 1 +#elif defined(HOST_WASI) || defined(HOST_BROWSER) +# define MONO_USE_C11_ATOMIC 1 +#elif defined(USE_GCC_ATOMIC_OPS) +/* Prefer GCC atomic ops if the target supports it (see configure.ac). */ +# define MONO_USE_GCC_ATOMIC 1 +#else +# define MONO_USE_EMULATED_ATOMIC 1 +#endif + +#if defined(MONO_USE_C11_ATOMIC) + +#include + +static inline gint32 +mono_atomic_cas_i32 (volatile gint32 *dest, gint32 exch, gint32 comp) +{ + g_static_assert (sizeof (atomic_int) == sizeof (*dest) && ATOMIC_INT_LOCK_FREE == 2); + (void)atomic_compare_exchange_strong ((volatile atomic_int *)dest, &comp, exch); + return comp; +} + +static inline gint64 +mono_atomic_cas_i64 (volatile gint64 *dest, gint64 exch, gint64 comp) +{ +#if SIZEOF_LONG == 8 + g_static_assert (sizeof (atomic_long) == sizeof (*dest) && ATOMIC_LONG_LOCK_FREE == 2); + (void)atomic_compare_exchange_strong ((volatile atomic_long *)dest, (long*)&comp, exch); + return comp; +#elif SIZEOF_LONG_LONG == 8 + g_static_assert (sizeof (atomic_llong) == sizeof (*dest) && ATOMIC_LLONG_LOCK_FREE == 2); + (void)atomic_compare_exchange_strong ((volatile atomic_llong *)dest, (long long*)&comp, exch); + return comp; +#else +#error gint64 not same size atomic_llong or atomic_long, don't define MONO_USE_STDATOMIC +#endif +} + +static inline gpointer +mono_atomic_cas_ptr (volatile gpointer *dest, gpointer exch, gpointer comp) +{ + g_static_assert(ATOMIC_POINTER_LOCK_FREE == 2); + (void)atomic_compare_exchange_strong ((volatile _Atomic(gpointer) *)dest, &comp, exch); + return comp; +} + +static inline gint32 +mono_atomic_fetch_add_i32 (volatile gint32 *dest, gint32 add); +static inline gint64 +mono_atomic_fetch_add_i64 (volatile gint64 *dest, gint64 add); + +static inline gint32 +mono_atomic_add_i32 (volatile gint32 *dest, gint32 add) +{ + // mono_atomic_add_ is supposed to return the value that is stored. + // the atomic_add intrinsic returns the previous value instead. + // so we return prev+add which should be the new value + return mono_atomic_fetch_add_i32 (dest, add) + add; +} + +static inline gint64 +mono_atomic_add_i64 (volatile gint64 *dest, gint64 add) +{ + return mono_atomic_fetch_add_i64 (dest, add) + add; +} + +static inline gint32 +mono_atomic_inc_i32 (volatile gint32 *dest) +{ + return mono_atomic_add_i32 (dest, 1); +} + +static inline gint64 +mono_atomic_inc_i64 (volatile gint64 *dest) +{ + return mono_atomic_add_i64 (dest, 1); +} + +static inline gint32 +mono_atomic_dec_i32 (volatile gint32 *dest) +{ + return mono_atomic_add_i32 (dest, -1); +} + +static inline gint64 +mono_atomic_dec_i64 (volatile gint64 *dest) +{ + return mono_atomic_add_i64 (dest, -1); +} + +static inline gint32 +mono_atomic_xchg_i32 (volatile gint32 *dest, gint32 exch) +{ + g_static_assert (sizeof (atomic_int) == sizeof (*dest) && ATOMIC_INT_LOCK_FREE == 2); + return atomic_exchange ((volatile atomic_int *)dest, exch); +} + +static inline gint64 +mono_atomic_xchg_i64 (volatile gint64 *dest, gint64 exch) +{ +#if SIZEOF_LONG == 8 + g_static_assert (sizeof (atomic_long) == sizeof (*dest) && ATOMIC_LONG_LOCK_FREE == 2); + return atomic_exchange ((volatile atomic_long *)dest, exch); +#elif SIZEOF_LONG_LONG == 8 + g_static_assert (sizeof (atomic_llong) == sizeof (*dest) && ATOMIC_LLONG_LOCK_FREE == 2); + return atomic_exchange ((volatile atomic_llong *)dest, exch); +#else +#error gint64 not same size atomic_llong or atomic_long, don't define MONO_USE_STDATOMIC +#endif +} + +static inline gpointer +mono_atomic_xchg_ptr (volatile gpointer *dest, gpointer exch) +{ + g_static_assert (ATOMIC_POINTER_LOCK_FREE == 2); + return atomic_exchange ((volatile _Atomic(gpointer) *)dest, exch); +} + +static inline gint32 +mono_atomic_fetch_add_i32 (volatile gint32 *dest, gint32 add) +{ + g_static_assert (sizeof (atomic_int) == sizeof (*dest) && ATOMIC_INT_LOCK_FREE == 2); + return atomic_fetch_add ((volatile atomic_int *)dest, add); +} + +static inline gint64 +mono_atomic_fetch_add_i64 (volatile gint64 *dest, gint64 add) +{ +#if SIZEOF_LONG == 8 + g_static_assert (sizeof (atomic_long) == sizeof (*dest) && ATOMIC_LONG_LOCK_FREE == 2); + return atomic_fetch_add ((volatile atomic_long *)dest, add); +#elif SIZEOF_LONG_LONG == 8 + g_static_assert (sizeof (atomic_llong) == sizeof (*dest) && ATOMIC_LLONG_LOCK_FREE == 2); + return atomic_fetch_add ((volatile atomic_llong *)dest, add); +#else +#error gint64 not same size atomic_llong or atomic_long, don't define MONO_USE_STDATOMIC +#endif +} + +static inline gint8 +mono_atomic_load_i8 (volatile gint8 *src) +{ + g_static_assert (sizeof (atomic_char) == sizeof (*src) && ATOMIC_CHAR_LOCK_FREE == 2); + return atomic_load ((volatile atomic_char *)src); +} + +static inline gint16 +mono_atomic_load_i16 (volatile gint16 *src) +{ + g_static_assert (sizeof (atomic_short) == sizeof (*src) && ATOMIC_SHORT_LOCK_FREE == 2); + return atomic_load ((volatile atomic_short *)src); +} + +static inline gint32 mono_atomic_load_i32 (volatile gint32 *src) +{ + g_static_assert (sizeof (atomic_int) == sizeof (*src) && ATOMIC_INT_LOCK_FREE == 2); + return atomic_load ((volatile atomic_int *)src); +} + +static inline gint64 +mono_atomic_load_i64 (volatile gint64 *src) +{ +#if SIZEOF_LONG == 8 + g_static_assert (sizeof (atomic_long) == sizeof (*src) && ATOMIC_LONG_LOCK_FREE == 2); + return atomic_load ((volatile atomic_long *)src); +#elif SIZEOF_LONG_LONG == 8 + g_static_assert (sizeof (atomic_llong) == sizeof (*src) && ATOMIC_LLONG_LOCK_FREE == 2); + return atomic_load ((volatile atomic_llong *)src); +#else +#error gint64 not same size atomic_llong or atomic_long, don't define MONO_USE_STDATOMIC +#endif +} + +static inline gpointer +mono_atomic_load_ptr (volatile gpointer *src) +{ + g_static_assert (ATOMIC_POINTER_LOCK_FREE == 2); + return atomic_load ((volatile _Atomic(gpointer) *)src); +} + +static inline void +mono_atomic_store_i8 (volatile gint8 *dst, gint8 val) +{ + g_static_assert (sizeof (atomic_char) == sizeof (*dst) && ATOMIC_CHAR_LOCK_FREE == 2); + atomic_store ((volatile atomic_char *)dst, val); +} + +static inline void +mono_atomic_store_i16 (volatile gint16 *dst, gint16 val) +{ + g_static_assert (sizeof (atomic_short) == sizeof (*dst) && ATOMIC_SHORT_LOCK_FREE == 2); + atomic_store ((volatile atomic_short *)dst, val); +} + +static inline void +mono_atomic_store_i32 (volatile gint32 *dst, gint32 val) +{ + g_static_assert (sizeof (atomic_int) == sizeof (*dst) && ATOMIC_INT_LOCK_FREE == 2); + atomic_store ((atomic_int *)dst, val); +} + +static inline void +mono_atomic_store_i64 (volatile gint64 *dst, gint64 val) +{ +#if SIZEOF_LONG == 8 + g_static_assert (sizeof (atomic_long) == sizeof (*dst) && ATOMIC_LONG_LOCK_FREE == 2); + atomic_store ((volatile atomic_long *)dst, val); +#elif SIZEOF_LONG_LONG == 8 + g_static_assert (sizeof (atomic_llong) == sizeof (*dst) && ATOMIC_LLONG_LOCK_FREE == 2); + atomic_store ((volatile atomic_llong *)dst, val); +#else +#error gint64 not same size atomic_llong or atomic_long, don't define MONO_USE_STDATOMIC +#endif +} + +static inline void +mono_atomic_store_ptr (volatile gpointer *dst, gpointer val) +{ + g_static_assert (ATOMIC_POINTER_LOCK_FREE == 2); + atomic_store ((volatile _Atomic(gpointer) *)dst, val); +} + +#elif defined(MONO_USE_WIN32_ATOMIC) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN @@ -204,8 +478,8 @@ mono_atomic_store_ptr (volatile gpointer *dst, gpointer val) InterlockedExchangePointer ((PVOID volatile *)dst, (PVOID)val); } -/* Prefer GCC atomic ops if the target supports it (see configure.ac). */ -#elif defined(USE_GCC_ATOMIC_OPS) + +#elif defined(MONO_USE_GCC_ATOMIC) /* * As of this comment (August 2016), all current Clang versions get atomic @@ -453,7 +727,7 @@ static inline void mono_atomic_store_i64(volatile gint64 *dst, gint64 val) mono_atomic_xchg_i64 (dst, val); } -#else +#elif defined(MONO_USE_EMULATED_ATOMIC) #define WAPI_NO_ATOMIC_ASM @@ -482,6 +756,8 @@ extern void mono_atomic_store_i32(volatile gint32 *dst, gint32 val); extern void mono_atomic_store_i64(volatile gint64 *dst, gint64 val); extern void mono_atomic_store_ptr(volatile gpointer *dst, gpointer val); +#else +#error one of MONO_USE_C11_ATOMIC, MONO_USE_WIN32_ATOMIC, MONO_USE_GCC_ATOMIC or MONO_USE_EMULATED_ATOMIC must be defined #endif #if SIZEOF_VOID_P == 4