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