diff options
Diffstat (limited to 'deps/v8/src/base/atomic-utils.h')
-rw-r--r-- | deps/v8/src/base/atomic-utils.h | 173 |
1 files changed, 170 insertions, 3 deletions
diff --git a/deps/v8/src/base/atomic-utils.h b/deps/v8/src/base/atomic-utils.h index f4f43fc817..a7f5b3ca8e 100644 --- a/deps/v8/src/base/atomic-utils.h +++ b/deps/v8/src/base/atomic-utils.h @@ -6,6 +6,7 @@ #define V8_ATOMIC_UTILS_H_ #include <limits.h> +#include <type_traits> #include "src/base/atomicops.h" #include "src/base/macros.h" @@ -68,18 +69,18 @@ class NoBarrierAtomicValue { } V8_INLINE bool TrySetValue(T old_value, T new_value) { - return base::NoBarrier_CompareAndSwap( + return base::Relaxed_CompareAndSwap( &value_, cast_helper<T>::to_storage_type(old_value), cast_helper<T>::to_storage_type(new_value)) == cast_helper<T>::to_storage_type(old_value); } V8_INLINE T Value() const { - return cast_helper<T>::to_return_type(base::NoBarrier_Load(&value_)); + return cast_helper<T>::to_return_type(base::Relaxed_Load(&value_)); } V8_INLINE void SetValue(T new_value) { - base::NoBarrier_Store(&value_, cast_helper<T>::to_storage_type(new_value)); + base::Relaxed_Store(&value_, cast_helper<T>::to_storage_type(new_value)); } private: @@ -250,6 +251,172 @@ class AtomicEnumSet { base::AtomicWord bits_; }; +class AsAtomic32 { + public: + template <typename T> + static T Acquire_Load(T* addr) { + STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32)); + return to_return_type<T>(base::Acquire_Load(to_storage_addr(addr))); + } + + template <typename T> + static T Relaxed_Load(T* addr) { + STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32)); + return to_return_type<T>(base::Relaxed_Load(to_storage_addr(addr))); + } + + template <typename T> + static void Release_Store(T* addr, + typename std::remove_reference<T>::type new_value) { + STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32)); + base::Release_Store(to_storage_addr(addr), to_storage_type(new_value)); + } + + template <typename T> + static void Relaxed_Store(T* addr, + typename std::remove_reference<T>::type new_value) { + STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32)); + base::Relaxed_Store(to_storage_addr(addr), to_storage_type(new_value)); + } + + template <typename T> + static T Release_CompareAndSwap( + T* addr, typename std::remove_reference<T>::type old_value, + typename std::remove_reference<T>::type new_value) { + STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32)); + return to_return_type<T>(base::Release_CompareAndSwap( + to_storage_addr(addr), to_storage_type(old_value), + to_storage_type(new_value))); + } + + // Atomically sets bits selected by the mask to the given value. + // Returns false if the bits are already set as needed. + template <typename T> + static bool SetBits(T* addr, T bits, T mask) { + STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32)); + DCHECK_EQ(bits & ~mask, static_cast<T>(0)); + T old_value; + T new_value; + do { + old_value = Relaxed_Load(addr); + if ((old_value & mask) == bits) return false; + new_value = (old_value & ~mask) | bits; + } while (Release_CompareAndSwap(addr, old_value, new_value) != old_value); + return true; + } + + private: + template <typename T> + static base::Atomic32 to_storage_type(T value) { + return static_cast<base::Atomic32>(value); + } + template <typename T> + static T to_return_type(base::Atomic32 value) { + return static_cast<T>(value); + } + template <typename T> + static base::Atomic32* to_storage_addr(T* value) { + return reinterpret_cast<base::Atomic32*>(value); + } + template <typename T> + static const base::Atomic32* to_storage_addr(const T* value) { + return reinterpret_cast<const base::Atomic32*>(value); + } +}; + +class AsAtomicWord { + public: + template <typename T> + static T Acquire_Load(T* addr) { + STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord)); + return to_return_type<T>(base::Acquire_Load(to_storage_addr(addr))); + } + + template <typename T> + static T Relaxed_Load(T* addr) { + STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord)); + return to_return_type<T>(base::Relaxed_Load(to_storage_addr(addr))); + } + + template <typename T> + static void Release_Store(T* addr, + typename std::remove_reference<T>::type new_value) { + STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord)); + base::Release_Store(to_storage_addr(addr), to_storage_type(new_value)); + } + + template <typename T> + static void Relaxed_Store(T* addr, + typename std::remove_reference<T>::type new_value) { + STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord)); + base::Relaxed_Store(to_storage_addr(addr), to_storage_type(new_value)); + } + + template <typename T> + static T Release_CompareAndSwap( + T* addr, typename std::remove_reference<T>::type old_value, + typename std::remove_reference<T>::type new_value) { + STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord)); + return to_return_type<T>(base::Release_CompareAndSwap( + to_storage_addr(addr), to_storage_type(old_value), + to_storage_type(new_value))); + } + + private: + template <typename T> + static base::AtomicWord to_storage_type(T value) { + return reinterpret_cast<base::AtomicWord>(value); + } + template <typename T> + static T to_return_type(base::AtomicWord value) { + return reinterpret_cast<T>(value); + } + template <typename T> + static base::AtomicWord* to_storage_addr(T* value) { + return reinterpret_cast<base::AtomicWord*>(value); + } + template <typename T> + static const base::AtomicWord* to_storage_addr(const T* value) { + return reinterpret_cast<const base::AtomicWord*>(value); + } +}; + +// This class is intended to be used as a wrapper for elements of an array +// that is passed in to STL functions such as std::sort. It ensures that +// elements accesses are atomic. +// Usage example: +// Object** given_array; +// AtomicElement<Object*>* wrapped = +// reinterpret_cast<AtomicElement<Object*>(given_array); +// std::sort(wrapped, wrapped + given_length, cmp); +// where the cmp function uses the value() accessor to compare the elements. +template <typename T> +class AtomicElement { + public: + AtomicElement(const AtomicElement<T>& other) { + AsAtomicWord::Relaxed_Store(&value_, + AsAtomicWord::Relaxed_Load(&other.value_)); + } + + void operator=(const AtomicElement<T>& other) { + AsAtomicWord::Relaxed_Store(&value_, + AsAtomicWord::Relaxed_Load(&other.value_)); + } + + T value() const { return AsAtomicWord::Relaxed_Load(&value_); } + + bool operator<(const AtomicElement<T>& other) const { + return value() < other.value(); + } + + bool operator==(const AtomicElement<T>& other) const { + return value() == other.value(); + } + + private: + T value_; +}; + } // namespace base } // namespace v8 |