diff --git a/mfbt/Atomics.h b/mfbt/Atomics.h index 32ab3688411..72cf2894578 100644 --- a/mfbt/Atomics.h +++ b/mfbt/Atomics.h @@ -830,6 +830,11 @@ namespace detail { template class AtomicBase { + // We only support 32-bit types on 32-bit Windows, which constrains our + // implementation elsewhere. But we support pointer-sized types everywhere. + static_assert(sizeof(T) == 4 || (sizeof(uintptr_t) == 8 && sizeof(T) == 8), + "mozilla/Atomics.h only supports 32-bit and pointer-sized types"); + protected: typedef typename detail::AtomicIntrinsics Intrinsics; typename Intrinsics::ValueType mValue; @@ -838,13 +843,13 @@ class AtomicBase AtomicBase() : mValue() {} AtomicBase(T aInit) { Intrinsics::store(mValue, aInit); } - T operator++(int) { return Intrinsics::inc(mValue); } - T operator--(int) { return Intrinsics::dec(mValue); } - T operator++() { return Intrinsics::inc(mValue) + 1; } - T operator--() { return Intrinsics::dec(mValue) - 1; } - operator T() const { return Intrinsics::load(mValue); } + T operator=(T aValue) { + Intrinsics::store(mValue, aValue); + return aValue; + } + /** * Performs an atomic swap operation. aValue is stored and the previous * value of this variable is returned. @@ -852,6 +857,7 @@ class AtomicBase T exchange(T aValue) { return Intrinsics::exchange(mValue, aValue); } + /** * Performs an atomic compare-and-swap operation and returns true if it * succeeded. This is equivalent to atomically doing @@ -872,16 +878,35 @@ class AtomicBase AtomicBase(const AtomicBase& aCopy) MOZ_DELETE; }; +template +class AtomicBaseIncDec : public AtomicBase +{ + typedef typename detail::AtomicBase Base; + + public: + AtomicBaseIncDec() : Base() {} + AtomicBaseIncDec(T aInit) : Base(aInit) {} + + using Base::operator=; + + T operator++(int) { return Base::Intrinsics::inc(Base::mValue); } + T operator--(int) { return Base::Intrinsics::dec(Base::mValue); } + T operator++() { return Base::Intrinsics::inc(Base::mValue) + 1; } + T operator--() { return Base::Intrinsics::dec(Base::mValue) - 1; } + + private: + template + AtomicBaseIncDec(const AtomicBaseIncDec& aCopy) MOZ_DELETE; +}; + } // namespace detail /** * A wrapper for a type that enforces that all memory accesses are atomic. * - * In general, where a variable |T foo| exists, |Atomic foo| can be - * used in its place. In addition to atomic store and load operations, - * compound assignment and increment/decrement operators are implemented - * which perform the corresponding read-modify-write operation - * atomically. Finally, an atomic swap method is provided. + * In general, where a variable |T foo| exists, |Atomic foo| can be used in + * its place. Implementations for integral and pointer types are provided + * below. * * Atomic accesses are sequentially consistent by default. You should * use the default unless you are tall enough to ride the @@ -893,21 +918,30 @@ class AtomicBase * deliberate design choice that enables static atomic variables to be declared * without introducing extra static constructors. */ -template -class Atomic : public detail::AtomicBase -{ - // We only support 32-bit types on 32-bit Windows, which constrains our - // implementation elsewhere. But we support pointer-sized types everywhere. - static_assert(sizeof(T) == 4 || (sizeof(uintptr_t) == 8 && sizeof(T) == 8), - "mozilla/Atomics.h only supports 32-bit and pointer-sized types"); - // Regardless of the OS, we only support integral types here. - static_assert(IsIntegral::value, "can only have integral atomic variables"); +template +class Atomic; - typedef typename detail::AtomicBase Base; +/** + * Atomic implementation for integral types. + * + * In addition to atomic store and load operations, compound assignment and + * increment/decrement operators are implemented which perform the + * corresponding read-modify-write operation atomically. Finally, an atomic + * swap method is provided. + */ +template +class Atomic::value>::Type> + : public detail::AtomicBaseIncDec +{ + typedef typename detail::AtomicBaseIncDec Base; public: - Atomic() : detail::AtomicBase() {} - Atomic(T aInit) : detail::AtomicBase(aInit) {} + Atomic() : Base() {} + Atomic(T aInit) : Base(aInit) {} + + using Base::operator=; T operator+=(T delta) { return Base::Intrinsics::add(Base::mValue, delta) + delta; } T operator-=(T delta) { return Base::Intrinsics::sub(Base::mValue, delta) - delta; } @@ -915,55 +949,36 @@ class Atomic : public detail::AtomicBase T operator^=(T val) { return Base::Intrinsics::xor_(Base::mValue, val) ^ val; } T operator&=(T val) { return Base::Intrinsics::and_(Base::mValue, val) & val; } - T operator=(T aValue) { - Base::Intrinsics::store(Base::mValue, aValue); - return aValue; - } - private: Atomic(Atomic& aOther) MOZ_DELETE; }; /** - * A partial specialization of Atomic for pointer variables. + * Atomic implementation for pointer types. * - * Like Atomic, Atomic is equivalent in most respects to a regular T* - * variable. An atomic compare-and-swap primitive for pointer variables is - * provided, as are atomic increment and decement operators. Also provided - * are the compound assignment operators for addition and subtraction. - * Atomic swap (via exchange()) is included as well. - * - * Atomic accesses are sequentially consistent by default. You should - * use the default unless you are tall enough to ride the - * memory-ordering roller coaster (if you're not sure, you aren't) and - * you have a compelling reason to do otherwise. - * - * There is one exception to the case of atomic memory accesses: providing an - * initial value of the atomic value is not guaranteed to be atomic. This is a - * deliberate design choice that enables static atomic variables to be declared - * without introducing extra static constructors. + * An atomic compare-and-swap primitive for pointer variables is provided, as + * are atomic increment and decement operators. Also provided are the compound + * assignment operators for addition and subtraction. Atomic swap (via + * exchange()) is included as well. */ template -class Atomic : public detail::AtomicBase +class Atomic : public detail::AtomicBaseIncDec { - typedef typename detail::AtomicBase Base; + typedef typename detail::AtomicBaseIncDec Base; public: - Atomic() : detail::AtomicBase() {} - Atomic(T* aInit) : detail::AtomicBase(aInit) {} + Atomic() : Base() {} + Atomic(T* aInit) : Base(aInit) {} - T* operator +=(ptrdiff_t delta) { + using Base::operator=; + + T* operator+=(ptrdiff_t delta) { return Base::Intrinsics::add(Base::mValue, delta) + delta; } - T* operator -=(ptrdiff_t delta) { + T* operator-=(ptrdiff_t delta) { return Base::Intrinsics::sub(Base::mValue, delta) - delta; } - T* operator=(T* aValue) { - Base::Intrinsics::store(Base::mValue, aValue); - return aValue; - } - private: Atomic(Atomic& aOther) MOZ_DELETE; };