• 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_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 base {
15 
16 template <class T>
17 class AtomicNumber {
18  public:
AtomicNumber()19   AtomicNumber() : value_(0) {}
AtomicNumber(T initial)20   explicit AtomicNumber(T initial) : value_(initial) {}
21 
22   // Returns the value after incrementing.
Increment(T increment)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   // Returns the value after decrementing.
Decrement(T decrement)29   V8_INLINE T Decrement(T decrement) {
30     return static_cast<T>(base::Barrier_AtomicIncrement(
31         &value_, -static_cast<base::AtomicWord>(decrement)));
32   }
33 
Value()34   V8_INLINE T Value() { return static_cast<T>(base::Acquire_Load(&value_)); }
35 
SetValue(T new_value)36   V8_INLINE void SetValue(T new_value) {
37     base::Release_Store(&value_, static_cast<base::AtomicWord>(new_value));
38   }
39 
40   V8_INLINE T operator=(T value) {
41     SetValue(value);
42     return value;
43   }
44 
45   V8_INLINE T operator+=(T value) { return Increment(value); }
46   V8_INLINE T operator-=(T value) { return Decrement(value); }
47 
48  private:
49   STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
50 
51   base::AtomicWord value_;
52 };
53 
54 // This type uses no barrier accessors to change atomic word. Be careful with
55 // data races.
56 template <typename T>
57 class NoBarrierAtomicValue {
58  public:
NoBarrierAtomicValue()59   NoBarrierAtomicValue() : value_(0) {}
60 
NoBarrierAtomicValue(T initial)61   explicit NoBarrierAtomicValue(T initial)
62       : value_(cast_helper<T>::to_storage_type(initial)) {}
63 
FromAddress(void * address)64   static NoBarrierAtomicValue* FromAddress(void* address) {
65     return reinterpret_cast<base::NoBarrierAtomicValue<T>*>(address);
66   }
67 
TrySetValue(T old_value,T new_value)68   V8_INLINE bool TrySetValue(T old_value, T new_value) {
69     return base::NoBarrier_CompareAndSwap(
70                &value_, cast_helper<T>::to_storage_type(old_value),
71                cast_helper<T>::to_storage_type(new_value)) ==
72            cast_helper<T>::to_storage_type(old_value);
73   }
74 
Value()75   V8_INLINE T Value() const {
76     return cast_helper<T>::to_return_type(base::NoBarrier_Load(&value_));
77   }
78 
SetValue(T new_value)79   V8_INLINE void SetValue(T new_value) {
80     base::NoBarrier_Store(&value_, cast_helper<T>::to_storage_type(new_value));
81   }
82 
83  private:
84   STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
85 
86   template <typename S>
87   struct cast_helper {
to_storage_typecast_helper88     static base::AtomicWord to_storage_type(S value) {
89       return static_cast<base::AtomicWord>(value);
90     }
to_return_typecast_helper91     static S to_return_type(base::AtomicWord value) {
92       return static_cast<S>(value);
93     }
94   };
95 
96   template <typename S>
97   struct cast_helper<S*> {
98     static base::AtomicWord to_storage_type(S* value) {
99       return reinterpret_cast<base::AtomicWord>(value);
100     }
101     static S* to_return_type(base::AtomicWord value) {
102       return reinterpret_cast<S*>(value);
103     }
104   };
105 
106   base::AtomicWord value_;
107 };
108 
109 // Flag using T atomically. Also accepts void* as T.
110 template <typename T>
111 class AtomicValue {
112  public:
113   AtomicValue() : value_(0) {}
114 
115   explicit AtomicValue(T initial)
116       : value_(cast_helper<T>::to_storage_type(initial)) {}
117 
118   V8_INLINE T Value() const {
119     return cast_helper<T>::to_return_type(base::Acquire_Load(&value_));
120   }
121 
122   V8_INLINE bool TrySetValue(T old_value, T new_value) {
123     return base::Release_CompareAndSwap(
124                &value_, cast_helper<T>::to_storage_type(old_value),
125                cast_helper<T>::to_storage_type(new_value)) ==
126            cast_helper<T>::to_storage_type(old_value);
127   }
128 
129   V8_INLINE void SetBits(T bits, T mask) {
130     DCHECK_EQ(bits & ~mask, static_cast<T>(0));
131     T old_value;
132     T new_value;
133     do {
134       old_value = Value();
135       new_value = (old_value & ~mask) | bits;
136     } while (!TrySetValue(old_value, new_value));
137   }
138 
139   V8_INLINE void SetBit(int bit) {
140     SetBits(static_cast<T>(1) << bit, static_cast<T>(1) << bit);
141   }
142 
143   V8_INLINE void ClearBit(int bit) { SetBits(0, 1 << bit); }
144 
145   V8_INLINE void SetValue(T new_value) {
146     base::Release_Store(&value_, cast_helper<T>::to_storage_type(new_value));
147   }
148 
149  private:
150   STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
151 
152   template <typename S>
153   struct cast_helper {
154     static base::AtomicWord to_storage_type(S value) {
155       return static_cast<base::AtomicWord>(value);
156     }
157     static S to_return_type(base::AtomicWord value) {
158       return static_cast<S>(value);
159     }
160   };
161 
162   template <typename S>
163   struct cast_helper<S*> {
164     static base::AtomicWord to_storage_type(S* value) {
165       return reinterpret_cast<base::AtomicWord>(value);
166     }
167     static S* to_return_type(base::AtomicWord value) {
168       return reinterpret_cast<S*>(value);
169     }
170   };
171 
172   base::AtomicWord value_;
173 };
174 
175 
176 // See utils.h for EnumSet. Storage is always base::AtomicWord.
177 // Requirements on E:
178 // - No explicit values.
179 // - E::kLastValue defined to be the last actually used value.
180 //
181 // Example:
182 // enum E { kA, kB, kC, kLastValue = kC };
183 template <class E>
184 class AtomicEnumSet {
185  public:
186   explicit AtomicEnumSet(base::AtomicWord bits = 0) : bits_(bits) {}
187 
188   bool IsEmpty() const { return ToIntegral() == 0; }
189 
190   bool Contains(E element) const { return (ToIntegral() & Mask(element)) != 0; }
191   bool ContainsAnyOf(const AtomicEnumSet& set) const {
192     return (ToIntegral() & set.ToIntegral()) != 0;
193   }
194 
195   void RemoveAll() { base::Release_Store(&bits_, 0); }
196 
197   bool operator==(const AtomicEnumSet& set) const {
198     return ToIntegral() == set.ToIntegral();
199   }
200 
201   bool operator!=(const AtomicEnumSet& set) const {
202     return ToIntegral() != set.ToIntegral();
203   }
204 
205   AtomicEnumSet<E> operator|(const AtomicEnumSet& set) const {
206     return AtomicEnumSet<E>(ToIntegral() | set.ToIntegral());
207   }
208 
209 // The following operations modify the underlying storage.
210 
211 #define ATOMIC_SET_WRITE(OP, NEW_VAL)                                     \
212   do {                                                                    \
213     base::AtomicWord old;                                                 \
214     do {                                                                  \
215       old = base::Acquire_Load(&bits_);                                   \
216     } while (base::Release_CompareAndSwap(&bits_, old, old OP NEW_VAL) != \
217              old);                                                        \
218   } while (false)
219 
220   void Add(E element) { ATOMIC_SET_WRITE(|, Mask(element)); }
221 
222   void Add(const AtomicEnumSet& set) { ATOMIC_SET_WRITE(|, set.ToIntegral()); }
223 
224   void Remove(E element) { ATOMIC_SET_WRITE(&, ~Mask(element)); }
225 
226   void Remove(const AtomicEnumSet& set) {
227     ATOMIC_SET_WRITE(&, ~set.ToIntegral());
228   }
229 
230   void Intersect(const AtomicEnumSet& set) {
231     ATOMIC_SET_WRITE(&, set.ToIntegral());
232   }
233 
234 #undef ATOMIC_SET_OP
235 
236  private:
237   // Check whether there's enough storage to hold E.
238   STATIC_ASSERT(E::kLastValue < (sizeof(base::AtomicWord) * CHAR_BIT));
239 
240   V8_INLINE base::AtomicWord ToIntegral() const {
241     return base::Acquire_Load(&bits_);
242   }
243 
244   V8_INLINE base::AtomicWord Mask(E element) const {
245     return static_cast<base::AtomicWord>(1) << element;
246   }
247 
248   base::AtomicWord bits_;
249 };
250 
251 }  // namespace base
252 }  // namespace v8
253 
254 #endif  // #define V8_ATOMIC_UTILS_H_
255