diff options
Diffstat (limited to 'mfbt/WasiAtomic.h')
-rw-r--r-- | mfbt/WasiAtomic.h | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/mfbt/WasiAtomic.h b/mfbt/WasiAtomic.h new file mode 100644 index 0000000000..ba222e91c0 --- /dev/null +++ b/mfbt/WasiAtomic.h @@ -0,0 +1,200 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_WasiAtomic_h +#define mozilla_WasiAtomic_h + +// Clang >= 14 supports <atomic> for wasm targets. +#if _LIBCPP_VERSION >= 14000 +# include <atomic> +#else + +# include <cstddef> // For ptrdiff_t +# include <cstdint> + +// WASI doesn't support <atomic> and we use it as single-threaded for now. +// This is a stub implementation of std atomics to build WASI port of SM. + +namespace std { +enum memory_order { + relaxed, + consume, // load-consume + acquire, // load-acquire + release, // store-release + acq_rel, // store-release load-acquire + seq_cst // store-release load-acquire +}; + +inline constexpr auto memory_order_relaxed = memory_order::relaxed; +inline constexpr auto memory_order_consume = memory_order::consume; +inline constexpr auto memory_order_acquire = memory_order::acquire; +inline constexpr auto memory_order_release = memory_order::release; +inline constexpr auto memory_order_acq_rel = memory_order::acq_rel; +inline constexpr auto memory_order_seq_cst = memory_order::seq_cst; + +template <class T> +struct atomic { + using value_type = T; + value_type value_; + + atomic() noexcept = default; + constexpr atomic(T desired) noexcept : value_{desired} {} + + atomic(const atomic&) = delete; + atomic& operator=(const atomic&) = delete; + atomic& operator=(const atomic&) volatile = delete; + ~atomic() noexcept = default; + + T load(memory_order m = memory_order_seq_cst) const volatile noexcept { + return value_; + } + + void store(T desired, + memory_order m = memory_order_seq_cst) volatile noexcept { + value_ = desired; + } + + T operator=(T desired) volatile noexcept { return value_ = desired; } + + T exchange(T desired, + memory_order m = memory_order_seq_cst) volatile noexcept { + T tmp = value_; + value_ = desired; + return tmp; + } + + bool compare_exchange_weak(T& expected, T desired, memory_order, + memory_order) volatile noexcept { + expected = desired; + return true; + } + + bool compare_exchange_weak( + T& expected, T desired, + memory_order m = memory_order_seq_cst) volatile noexcept { + expected = desired; + return true; + } + + bool compare_exchange_strong(T& expected, T desired, memory_order, + memory_order) volatile noexcept { + expected = desired; + return true; + } + + bool compare_exchange_strong( + T& expected, T desired, + memory_order m = memory_order_seq_cst) volatile noexcept { + expected = desired; + return true; + } + + T fetch_add(T arg, memory_order m = memory_order_seq_cst) volatile noexcept { + T previous = value_; + value_ = value_ + arg; + return previous; + } + + T fetch_sub(T arg, memory_order m = memory_order_seq_cst) volatile noexcept { + T previous = value_; + value_ = value_ - arg; + return previous; + } + + T fetch_or(T arg, memory_order m = memory_order_seq_cst) volatile noexcept { + T previous = value_; + value_ = value_ | arg; + return previous; + } + + T fetch_xor(T arg, memory_order m = memory_order_seq_cst) volatile noexcept { + T previous = value_; + value_ = value_ ^ arg; + return previous; + } + + T fetch_and(T arg, memory_order m = memory_order_seq_cst) volatile noexcept { + T previous = value_; + value_ = value_ & arg; + return previous; + } +}; + +template <class T> +struct atomic<T*> { + using value_type = T*; + using difference_type = ptrdiff_t; + + value_type value_; + + atomic() noexcept = default; + constexpr atomic(T* desired) noexcept : value_{desired} {} + atomic(const atomic&) = delete; + atomic& operator=(const atomic&) = delete; + atomic& operator=(const atomic&) volatile = delete; + + T* load(memory_order m = memory_order_seq_cst) const volatile noexcept { + return value_; + } + + void store(T* desired, + memory_order m = memory_order_seq_cst) volatile noexcept { + value_ = desired; + } + + T* operator=(T* other) volatile noexcept { return value_ = other; } + + T* exchange(T* desired, + memory_order m = memory_order_seq_cst) volatile noexcept { + T* previous = value_; + value_ = desired; + return previous; + } + + bool compare_exchange_weak(T*& expected, T* desired, memory_order s, + memory_order f) volatile noexcept { + expected = desired; + return true; + } + + bool compare_exchange_weak( + T*& expected, T* desired, + memory_order m = memory_order_seq_cst) volatile noexcept { + expected = desired; + return true; + } + + bool compare_exchange_strong(T*& expected, T* desired, memory_order s, + memory_order f) volatile noexcept { + expected = desired; + return true; + } + + T* fetch_add(ptrdiff_t arg, + memory_order m = memory_order_seq_cst) volatile noexcept { + T* previous = value_; + value_ = value_ + arg; + return previous; + } + + T* fetch_sub(ptrdiff_t arg, + memory_order m = memory_order_seq_cst) volatile noexcept { + T* previous = value_; + value_ = value_ - arg; + return previous; + } +}; + +using atomic_uint8_t = atomic<uint8_t>; +using atomic_uint16_t = atomic<uint16_t>; +using atomic_uint32_t = atomic<uint32_t>; +using atomic_uint64_t = atomic<uint64_t>; + +} // namespace std + +#endif + +#endif // mozilla_WasiAtomic_h |