1 // Copyright 2015 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_ATOMIC_UTILS_H_ 6 #define V8_ATOMIC_UTILS_H_ 7 8 #include <limits.h> 9 10 #include "src/base/atomicops.h" 11 #include "src/base/macros.h" 12 13 namespace v8 { 14 namespace internal { 15 16 template <class T> 17 class AtomicNumber { 18 public: 19 AtomicNumber() : value_(0) {} 20 explicit AtomicNumber(T initial) : value_(initial) {} 21 22 // Returns the newly set value. 23 V8_INLINE T Increment(T increment) { 24 return static_cast<T>(base::Barrier_AtomicIncrement( 25 &value_, static_cast<base::AtomicWord>(increment))); 26 } 27 28 V8_INLINE T Value() { return static_cast<T>(base::Acquire_Load(&value_)); } 29 30 V8_INLINE void SetValue(T new_value) { 31 base::Release_Store(&value_, static_cast<base::AtomicWord>(new_value)); 32 } 33 34 V8_INLINE T operator=(T value) { 35 SetValue(value); 36 return value; 37 } 38 39 private: 40 STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord)); 41 42 base::AtomicWord value_; 43 }; 44 45 46 // Flag using T atomically. Also accepts void* as T. 47 template <typename T> 48 class AtomicValue { 49 public: 50 AtomicValue() : value_(0) {} 51 52 explicit AtomicValue(T initial) 53 : value_(cast_helper<T>::to_storage_type(initial)) {} 54 55 V8_INLINE T Value() { 56 return cast_helper<T>::to_return_type(base::Acquire_Load(&value_)); 57 } 58 59 V8_INLINE bool TrySetValue(T old_value, T new_value) { 60 return base::Release_CompareAndSwap( 61 &value_, cast_helper<T>::to_storage_type(old_value), 62 cast_helper<T>::to_storage_type(new_value)) == 63 cast_helper<T>::to_storage_type(old_value); 64 } 65 66 V8_INLINE void SetValue(T new_value) { 67 base::Release_Store(&value_, cast_helper<T>::to_storage_type(new_value)); 68 } 69 70 private: 71 STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord)); 72 73 template <typename S> 74 struct cast_helper { 75 static base::AtomicWord to_storage_type(S value) { 76 return static_cast<base::AtomicWord>(value); 77 } 78 static S to_return_type(base::AtomicWord value) { 79 return static_cast<S>(value); 80 } 81 }; 82 83 template <typename S> 84 struct cast_helper<S*> { 85 static base::AtomicWord to_storage_type(S* value) { 86 return reinterpret_cast<base::AtomicWord>(value); 87 } 88 static S* to_return_type(base::AtomicWord value) { 89 return reinterpret_cast<S*>(value); 90 } 91 }; 92 93 base::AtomicWord value_; 94 }; 95 96 97 // See utils.h for EnumSet. Storage is always base::AtomicWord. 98 // Requirements on E: 99 // - No explicit values. 100 // - E::kLastValue defined to be the last actually used value. 101 // 102 // Example: 103 // enum E { kA, kB, kC, kLastValue = kC }; 104 template <class E> 105 class AtomicEnumSet { 106 public: 107 explicit AtomicEnumSet(base::AtomicWord bits = 0) : bits_(bits) {} 108 109 bool IsEmpty() const { return ToIntegral() == 0; } 110 111 bool Contains(E element) const { return (ToIntegral() & Mask(element)) != 0; } 112 bool ContainsAnyOf(const AtomicEnumSet& set) const { 113 return (ToIntegral() & set.ToIntegral()) != 0; 114 } 115 116 void RemoveAll() { base::Release_Store(&bits_, 0); } 117 118 bool operator==(const AtomicEnumSet& set) const { 119 return ToIntegral() == set.ToIntegral(); 120 } 121 122 bool operator!=(const AtomicEnumSet& set) const { 123 return ToIntegral() != set.ToIntegral(); 124 } 125 126 AtomicEnumSet<E> operator|(const AtomicEnumSet& set) const { 127 return AtomicEnumSet<E>(ToIntegral() | set.ToIntegral()); 128 } 129 130 // The following operations modify the underlying storage. 131 132 #define ATOMIC_SET_WRITE(OP, NEW_VAL) \ 133 do { \ 134 base::AtomicWord old; \ 135 do { \ 136 old = base::Acquire_Load(&bits_); \ 137 } while (base::Release_CompareAndSwap(&bits_, old, old OP NEW_VAL) != \ 138 old); \ 139 } while (false) 140 141 void Add(E element) { ATOMIC_SET_WRITE(|, Mask(element)); } 142 143 void Add(const AtomicEnumSet& set) { ATOMIC_SET_WRITE(|, set.ToIntegral()); } 144 145 void Remove(E element) { ATOMIC_SET_WRITE(&, ~Mask(element)); } 146 147 void Remove(const AtomicEnumSet& set) { 148 ATOMIC_SET_WRITE(&, ~set.ToIntegral()); 149 } 150 151 void Intersect(const AtomicEnumSet& set) { 152 ATOMIC_SET_WRITE(&, set.ToIntegral()); 153 } 154 155 #undef ATOMIC_SET_OP 156 157 private: 158 // Check whether there's enough storage to hold E. 159 STATIC_ASSERT(E::kLastValue < (sizeof(base::AtomicWord) * CHAR_BIT)); 160 161 V8_INLINE base::AtomicWord ToIntegral() const { 162 return base::Acquire_Load(&bits_); 163 } 164 165 V8_INLINE base::AtomicWord Mask(E element) const { 166 return static_cast<base::AtomicWord>(1) << element; 167 } 168 169 base::AtomicWord bits_; 170 }; 171 172 } // namespace internal 173 } // namespace v8 174 175 #endif // #define V8_ATOMIC_UTILS_H_ 176