• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_BASE_ATOMIC_UTILS_H_
6 #define V8_BASE_ATOMIC_UTILS_H_
7 
8 #include <limits.h>
9 #include <type_traits>
10 
11 #include "src/base/atomicops.h"
12 #include "src/base/macros.h"
13 
14 namespace v8 {
15 namespace base {
16 
17 // Deprecated. Use std::atomic<T> for new code.
18 // Flag using T atomically. Also accepts void* as T.
19 template <typename T>
20 class AtomicValue {
21  public:
AtomicValue()22   AtomicValue() : value_(0) {}
23 
AtomicValue(T initial)24   explicit AtomicValue(T initial)
25       : value_(cast_helper<T>::to_storage_type(initial)) {}
26 
Value()27   V8_INLINE T Value() const {
28     return cast_helper<T>::to_return_type(base::Acquire_Load(&value_));
29   }
30 
SetValue(T new_value)31   V8_INLINE void SetValue(T new_value) {
32     base::Release_Store(&value_, cast_helper<T>::to_storage_type(new_value));
33   }
34 
35  private:
36   STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
37 
38   template <typename S>
39   struct cast_helper {
to_storage_typecast_helper40     static base::AtomicWord to_storage_type(S value) {
41       return static_cast<base::AtomicWord>(value);
42     }
to_return_typecast_helper43     static S to_return_type(base::AtomicWord value) {
44       return static_cast<S>(value);
45     }
46   };
47 
48   template <typename S>
49   struct cast_helper<S*> {
50     static base::AtomicWord to_storage_type(S* value) {
51       return reinterpret_cast<base::AtomicWord>(value);
52     }
53     static S* to_return_type(base::AtomicWord value) {
54       return reinterpret_cast<S*>(value);
55     }
56   };
57 
58   base::AtomicWord value_;
59 };
60 
61 // Provides atomic operations for a values stored at some address.
62 template <typename TAtomicStorageType>
63 class AsAtomicImpl {
64  public:
65   using AtomicStorageType = TAtomicStorageType;
66 
67   template <typename T>
68   static T Acquire_Load(T* addr) {
69     STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType));
70     return cast_helper<T>::to_return_type(
71         base::Acquire_Load(to_storage_addr(addr)));
72   }
73 
74   template <typename T>
75   static T Relaxed_Load(T* addr) {
76     STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType));
77     return cast_helper<T>::to_return_type(
78         base::Relaxed_Load(to_storage_addr(addr)));
79   }
80 
81   template <typename T>
82   static void Release_Store(T* addr,
83                             typename std::remove_reference<T>::type new_value) {
84     STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType));
85     base::Release_Store(to_storage_addr(addr),
86                         cast_helper<T>::to_storage_type(new_value));
87   }
88 
89   template <typename T>
90   static void Relaxed_Store(T* addr,
91                             typename std::remove_reference<T>::type new_value) {
92     STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType));
93     base::Relaxed_Store(to_storage_addr(addr),
94                         cast_helper<T>::to_storage_type(new_value));
95   }
96 
97   template <typename T>
98   static T Release_CompareAndSwap(
99       T* addr, typename std::remove_reference<T>::type old_value,
100       typename std::remove_reference<T>::type new_value) {
101     STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType));
102     return cast_helper<T>::to_return_type(base::Release_CompareAndSwap(
103         to_storage_addr(addr), cast_helper<T>::to_storage_type(old_value),
104         cast_helper<T>::to_storage_type(new_value)));
105   }
106 
107   template <typename T>
108   static T Relaxed_CompareAndSwap(
109       T* addr, typename std::remove_reference<T>::type old_value,
110       typename std::remove_reference<T>::type new_value) {
111     STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType));
112     return cast_helper<T>::to_return_type(base::Relaxed_CompareAndSwap(
113         to_storage_addr(addr), cast_helper<T>::to_storage_type(old_value),
114         cast_helper<T>::to_storage_type(new_value)));
115   }
116 
117   template <typename T>
118   static T AcquireRelease_CompareAndSwap(
119       T* addr, typename std::remove_reference<T>::type old_value,
120       typename std::remove_reference<T>::type new_value) {
121     STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType));
122     return cast_helper<T>::to_return_type(base::AcquireRelease_CompareAndSwap(
123         to_storage_addr(addr), cast_helper<T>::to_storage_type(old_value),
124         cast_helper<T>::to_storage_type(new_value)));
125   }
126 
127   // Atomically sets bits selected by the mask to the given value.
128   // Returns false if the bits are already set as needed.
129   template <typename T>
130   static bool SetBits(T* addr, T bits, T mask) {
131     STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType));
132     DCHECK_EQ(bits & ~mask, static_cast<T>(0));
133     T old_value = Relaxed_Load(addr);
134     T new_value, old_value_before_cas;
135     do {
136       if ((old_value & mask) == bits) return false;
137       new_value = (old_value & ~mask) | bits;
138       old_value_before_cas = old_value;
139       old_value = Release_CompareAndSwap(addr, old_value, new_value);
140     } while (old_value != old_value_before_cas);
141     return true;
142   }
143 
144  private:
145   template <typename U>
146   struct cast_helper {
147     static AtomicStorageType to_storage_type(U value) {
148       return static_cast<AtomicStorageType>(value);
149     }
150     static U to_return_type(AtomicStorageType value) {
151       return static_cast<U>(value);
152     }
153   };
154 
155   template <typename U>
156   struct cast_helper<U*> {
157     static AtomicStorageType to_storage_type(U* value) {
158       return reinterpret_cast<AtomicStorageType>(value);
159     }
160     static U* to_return_type(AtomicStorageType value) {
161       return reinterpret_cast<U*>(value);
162     }
163   };
164 
165   template <typename T>
166   static AtomicStorageType* to_storage_addr(T* value) {
167     return reinterpret_cast<AtomicStorageType*>(value);
168   }
169   template <typename T>
170   static const AtomicStorageType* to_storage_addr(const T* value) {
171     return reinterpret_cast<const AtomicStorageType*>(value);
172   }
173 };
174 
175 using AsAtomic8 = AsAtomicImpl<base::Atomic8>;
176 using AsAtomic32 = AsAtomicImpl<base::Atomic32>;
177 using AsAtomicWord = AsAtomicImpl<base::AtomicWord>;
178 
179 // This is similar to AsAtomicWord but it explicitly deletes functionality
180 // provided atomic access to bit representation of stored values.
181 template <typename TAtomicStorageType>
182 class AsAtomicPointerImpl : public AsAtomicImpl<TAtomicStorageType> {
183  public:
184   template <typename T>
185   static bool SetBits(T* addr, T bits, T mask) = delete;
186 };
187 
188 using AsAtomicPointer = AsAtomicPointerImpl<base::AtomicWord>;
189 
190 template <typename T,
191           typename = typename std::enable_if<std::is_unsigned<T>::value>::type>
192 inline void CheckedIncrement(std::atomic<T>* number, T amount) {
193   const T old = number->fetch_add(amount);
194   DCHECK_GE(old + amount, old);
195   USE(old);
196 }
197 
198 template <typename T,
199           typename = typename std::enable_if<std::is_unsigned<T>::value>::type>
200 inline void CheckedDecrement(std::atomic<T>* number, T amount) {
201   const T old = number->fetch_sub(amount);
202   DCHECK_GE(old, amount);
203   USE(old);
204 }
205 
206 template <typename T>
207 V8_INLINE std::atomic<T>* AsAtomicPtr(T* t) {
208   return reinterpret_cast<std::atomic<T>*>(t);
209 }
210 
211 template <typename T>
212 V8_INLINE const std::atomic<T>* AsAtomicPtr(const T* t) {
213   return reinterpret_cast<const std::atomic<T>*>(t);
214 }
215 
216 }  // namespace base
217 }  // namespace v8
218 
219 #endif  // V8_BASE_ATOMIC_UTILS_H_
220