Line data Source code
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 : #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 : template <class T>
18 : class AtomicNumber {
19 : public:
20 588081 : AtomicNumber() : value_(0) {}
21 1846670 : explicit AtomicNumber(T initial) : value_(initial) {}
22 :
23 : // Returns the value after incrementing.
24 : V8_INLINE T Increment(T increment) {
25 : return static_cast<T>(base::Barrier_AtomicIncrement(
26 230031518 : &value_, static_cast<base::AtomicWord>(increment)));
27 : }
28 :
29 : // Returns the value after decrementing.
30 : V8_INLINE T Decrement(T decrement) {
31 : return static_cast<T>(base::Barrier_AtomicIncrement(
32 1907079 : &value_, -static_cast<base::AtomicWord>(decrement)));
33 : }
34 :
35 : V8_INLINE T Value() const {
36 11717681 : return static_cast<T>(base::Acquire_Load(&value_));
37 : }
38 :
39 : V8_INLINE void SetValue(T new_value) {
40 2614688 : base::Release_Store(&value_, static_cast<base::AtomicWord>(new_value));
41 : }
42 :
43 : V8_INLINE T operator=(T value) {
44 : SetValue(value);
45 : return value;
46 : }
47 :
48 : V8_INLINE T operator+=(T value) { return Increment(value); }
49 : V8_INLINE T operator-=(T value) { return Decrement(value); }
50 :
51 : private:
52 : STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
53 :
54 : base::AtomicWord value_;
55 : };
56 :
57 : // Flag using T atomically. Also accepts void* as T.
58 : template <typename T>
59 : class AtomicValue {
60 : public:
61 330428792 : AtomicValue() : value_(0) {}
62 :
63 : explicit AtomicValue(T initial)
64 2292545 : : value_(cast_helper<T>::to_storage_type(initial)) {}
65 :
66 : V8_INLINE T Value() const {
67 932637686 : return cast_helper<T>::to_return_type(base::Acquire_Load(&value_));
68 : }
69 :
70 : V8_INLINE bool TrySetValue(T old_value, T new_value) {
71 : return base::Release_CompareAndSwap(
72 : &value_, cast_helper<T>::to_storage_type(old_value),
73 4788779 : cast_helper<T>::to_storage_type(new_value)) ==
74 4793065 : cast_helper<T>::to_storage_type(old_value);
75 : }
76 :
77 : V8_INLINE void SetBits(T bits, T mask) {
78 : DCHECK_EQ(bits & ~mask, static_cast<T>(0));
79 : T old_value;
80 : T new_value;
81 : do {
82 : old_value = Value();
83 : new_value = (old_value & ~mask) | bits;
84 : } while (!TrySetValue(old_value, new_value));
85 : }
86 :
87 : V8_INLINE void SetBit(int bit) {
88 : SetBits(static_cast<T>(1) << bit, static_cast<T>(1) << bit);
89 : }
90 :
91 : V8_INLINE void ClearBit(int bit) { SetBits(0, 1 << bit); }
92 :
93 : V8_INLINE void SetValue(T new_value) {
94 7187844 : base::Release_Store(&value_, cast_helper<T>::to_storage_type(new_value));
95 : }
96 :
97 : private:
98 : STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
99 :
100 : template <typename S>
101 : struct cast_helper {
102 17422273 : static base::AtomicWord to_storage_type(S value) {
103 17422273 : return static_cast<base::AtomicWord>(value);
104 : }
105 52240458 : static S to_return_type(base::AtomicWord value) {
106 52240458 : return static_cast<S>(value);
107 : }
108 : };
109 :
110 : template <typename S>
111 : struct cast_helper<S*> {
112 9250241 : static base::AtomicWord to_storage_type(S* value) {
113 9250241 : return reinterpret_cast<base::AtomicWord>(value);
114 : }
115 874799594 : static S* to_return_type(base::AtomicWord value) {
116 874799594 : return reinterpret_cast<S*>(value);
117 : }
118 : };
119 :
120 : base::AtomicWord value_;
121 : };
122 :
123 : class AsAtomic32 {
124 : public:
125 : template <typename T>
126 : static T Acquire_Load(T* addr) {
127 : STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32));
128 : return to_return_type<T>(base::Acquire_Load(to_storage_addr(addr)));
129 : }
130 :
131 : template <typename T>
132 : static T Relaxed_Load(T* addr) {
133 : STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32));
134 : return to_return_type<T>(base::Relaxed_Load(to_storage_addr(addr)));
135 : }
136 :
137 : template <typename T>
138 : static void Release_Store(T* addr,
139 : typename std::remove_reference<T>::type new_value) {
140 : STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32));
141 : base::Release_Store(to_storage_addr(addr), to_storage_type(new_value));
142 : }
143 :
144 : template <typename T>
145 : static void Relaxed_Store(T* addr,
146 : typename std::remove_reference<T>::type new_value) {
147 : STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32));
148 : base::Relaxed_Store(to_storage_addr(addr), to_storage_type(new_value));
149 : }
150 :
151 : template <typename T>
152 : static T Release_CompareAndSwap(
153 : T* addr, typename std::remove_reference<T>::type old_value,
154 : typename std::remove_reference<T>::type new_value) {
155 : STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32));
156 : return to_return_type<T>(base::Release_CompareAndSwap(
157 : to_storage_addr(addr), to_storage_type(old_value),
158 : to_storage_type(new_value)));
159 : }
160 :
161 : // Atomically sets bits selected by the mask to the given value.
162 : // Returns false if the bits are already set as needed.
163 : template <typename T>
164 5468364730 : static bool SetBits(T* addr, T bits, T mask) {
165 : STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32));
166 : DCHECK_EQ(bits & ~mask, static_cast<T>(0));
167 : T old_value;
168 : T new_value;
169 1350231101 : do {
170 : old_value = Relaxed_Load(addr);
171 5468403858 : if ((old_value & mask) == bits) return false;
172 1350231101 : new_value = (old_value & ~mask) | bits;
173 : } while (Release_CompareAndSwap(addr, old_value, new_value) != old_value);
174 : return true;
175 : }
176 :
177 : private:
178 : template <typename T>
179 : static base::Atomic32 to_storage_type(T value) {
180 1350231101 : return static_cast<base::Atomic32>(value);
181 : }
182 : template <typename T>
183 : static T to_return_type(base::Atomic32 value) {
184 1350231101 : return static_cast<T>(value);
185 : }
186 : template <typename T>
187 : static base::Atomic32* to_storage_addr(T* value) {
188 : return reinterpret_cast<base::Atomic32*>(value);
189 : }
190 : template <typename T>
191 : static const base::Atomic32* to_storage_addr(const T* value) {
192 : return reinterpret_cast<const base::Atomic32*>(value);
193 : }
194 : };
195 :
196 : class AsAtomicWord {
197 : public:
198 : template <typename T>
199 : static T Acquire_Load(T* addr) {
200 : STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
201 : return to_return_type<T>(base::Acquire_Load(to_storage_addr(addr)));
202 : }
203 :
204 : template <typename T>
205 : static T Relaxed_Load(T* addr) {
206 : STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
207 : return to_return_type<T>(base::Relaxed_Load(to_storage_addr(addr)));
208 : }
209 :
210 : template <typename T>
211 : static void Release_Store(T* addr,
212 : typename std::remove_reference<T>::type new_value) {
213 : STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
214 : base::Release_Store(to_storage_addr(addr), to_storage_type(new_value));
215 : }
216 :
217 : template <typename T>
218 : static void Relaxed_Store(T* addr,
219 : typename std::remove_reference<T>::type new_value) {
220 : STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
221 : base::Relaxed_Store(to_storage_addr(addr), to_storage_type(new_value));
222 : }
223 :
224 : template <typename T>
225 : static T Release_CompareAndSwap(
226 : T* addr, typename std::remove_reference<T>::type old_value,
227 : typename std::remove_reference<T>::type new_value) {
228 : STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
229 : return to_return_type<T>(base::Release_CompareAndSwap(
230 : to_storage_addr(addr), to_storage_type(old_value),
231 : to_storage_type(new_value)));
232 : }
233 :
234 : // Atomically sets bits selected by the mask to the given value.
235 : // Returns false if the bits are already set as needed.
236 : template <typename T>
237 7079 : static bool SetBits(T* addr, T bits, T mask) {
238 : STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
239 : DCHECK_EQ(bits & ~mask, static_cast<T>(0));
240 : T old_value;
241 : T new_value;
242 7079 : do {
243 : old_value = Relaxed_Load(addr);
244 7079 : if ((old_value & mask) == bits) return false;
245 7079 : new_value = (old_value & ~mask) | bits;
246 : } while (Release_CompareAndSwap(addr, old_value, new_value) != old_value);
247 : return true;
248 : }
249 :
250 : private:
251 : template <typename T>
252 : static base::AtomicWord to_storage_type(T value) {
253 7079 : return static_cast<base::AtomicWord>(value);
254 : }
255 : template <typename T>
256 : static T to_return_type(base::AtomicWord value) {
257 7079 : return static_cast<T>(value);
258 : }
259 : template <typename T>
260 : static base::AtomicWord* to_storage_addr(T* value) {
261 : return reinterpret_cast<base::AtomicWord*>(value);
262 : }
263 : template <typename T>
264 : static const base::AtomicWord* to_storage_addr(const T* value) {
265 : return reinterpret_cast<const base::AtomicWord*>(value);
266 : }
267 : };
268 :
269 : class AsAtomic8 {
270 : public:
271 : template <typename T>
272 : static T Acquire_Load(T* addr) {
273 : STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic8));
274 : return to_return_type<T>(base::Acquire_Load(to_storage_addr(addr)));
275 : }
276 :
277 : template <typename T>
278 : static T Relaxed_Load(T* addr) {
279 : STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic8));
280 : return to_return_type<T>(base::Relaxed_Load(to_storage_addr(addr)));
281 : }
282 :
283 : template <typename T>
284 : static void Release_Store(T* addr,
285 : typename std::remove_reference<T>::type new_value) {
286 : STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic8));
287 : base::Release_Store(to_storage_addr(addr), to_storage_type(new_value));
288 : }
289 :
290 : template <typename T>
291 : static void Relaxed_Store(T* addr,
292 : typename std::remove_reference<T>::type new_value) {
293 : STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic8));
294 : base::Relaxed_Store(to_storage_addr(addr), to_storage_type(new_value));
295 : }
296 :
297 : template <typename T>
298 : static T Release_CompareAndSwap(
299 : T* addr, typename std::remove_reference<T>::type old_value,
300 : typename std::remove_reference<T>::type new_value) {
301 : STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic8));
302 : return to_return_type<T>(base::Release_CompareAndSwap(
303 : to_storage_addr(addr), to_storage_type(old_value),
304 : to_storage_type(new_value)));
305 : }
306 :
307 : private:
308 : template <typename T>
309 : static base::Atomic8 to_storage_type(T value) {
310 1158398 : return static_cast<base::Atomic8>(value);
311 : }
312 : template <typename T>
313 : static T to_return_type(base::Atomic8 value) {
314 336 : return static_cast<T>(value);
315 : }
316 : template <typename T>
317 : static base::Atomic8* to_storage_addr(T* value) {
318 : return reinterpret_cast<base::Atomic8*>(value);
319 : }
320 : template <typename T>
321 : static const base::Atomic8* to_storage_addr(const T* value) {
322 : return reinterpret_cast<const base::Atomic8*>(value);
323 : }
324 : };
325 :
326 : class AsAtomicPointer {
327 : public:
328 : template <typename T>
329 : static T Acquire_Load(T* addr) {
330 : STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
331 : return to_return_type<T>(base::Acquire_Load(to_storage_addr(addr)));
332 : }
333 :
334 : template <typename T>
335 196488048 : static T Relaxed_Load(T* addr) {
336 : STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
337 196488048 : return to_return_type<T>(base::Relaxed_Load(to_storage_addr(addr)));
338 : }
339 :
340 : template <typename T>
341 : static void Release_Store(T* addr,
342 : typename std::remove_reference<T>::type new_value) {
343 : STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
344 : base::Release_Store(to_storage_addr(addr), to_storage_type(new_value));
345 : }
346 :
347 : template <typename T>
348 : static void Relaxed_Store(T* addr,
349 : typename std::remove_reference<T>::type new_value) {
350 : STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
351 : base::Relaxed_Store(to_storage_addr(addr), to_storage_type(new_value));
352 : }
353 :
354 : template <typename T>
355 105885645 : static T Release_CompareAndSwap(
356 : T* addr, typename std::remove_reference<T>::type old_value,
357 : typename std::remove_reference<T>::type new_value) {
358 : STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
359 : return to_return_type<T>(base::Release_CompareAndSwap(
360 : to_storage_addr(addr), to_storage_type(old_value),
361 105885645 : to_storage_type(new_value)));
362 : }
363 :
364 : private:
365 : template <typename T>
366 : static base::AtomicWord to_storage_type(T value) {
367 105885645 : return reinterpret_cast<base::AtomicWord>(value);
368 : }
369 : template <typename T>
370 : static T to_return_type(base::AtomicWord value) {
371 3880333218 : return reinterpret_cast<T>(value);
372 : }
373 : template <typename T>
374 : static base::AtomicWord* to_storage_addr(T* value) {
375 : return reinterpret_cast<base::AtomicWord*>(value);
376 : }
377 : template <typename T>
378 : static const base::AtomicWord* to_storage_addr(const T* value) {
379 : return reinterpret_cast<const base::AtomicWord*>(value);
380 : }
381 : };
382 :
383 : // This class is intended to be used as a wrapper for elements of an array
384 : // that is passed in to STL functions such as std::sort. It ensures that
385 : // elements accesses are atomic.
386 : // Usage example:
387 : // Object** given_array;
388 : // AtomicElement<Object*>* wrapped =
389 : // reinterpret_cast<AtomicElement<Object*>(given_array);
390 : // std::sort(wrapped, wrapped + given_length, cmp);
391 : // where the cmp function uses the value() accessor to compare the elements.
392 : template <typename T>
393 : class AtomicElement {
394 : public:
395 21102212 : AtomicElement(const AtomicElement<T>& other) {
396 : AsAtomicPointer::Relaxed_Store(
397 42204424 : &value_, AsAtomicPointer::Relaxed_Load(&other.value_));
398 21102212 : }
399 :
400 57241961 : void operator=(const AtomicElement<T>& other) {
401 : AsAtomicPointer::Relaxed_Store(
402 114483922 : &value_, AsAtomicPointer::Relaxed_Load(&other.value_));
403 57241961 : }
404 :
405 176260026 : T value() const { return AsAtomicPointer::Relaxed_Load(&value_); }
406 :
407 : bool operator<(const AtomicElement<T>& other) const {
408 : return value() < other.value();
409 : }
410 :
411 : bool operator==(const AtomicElement<T>& other) const {
412 : return value() == other.value();
413 : }
414 :
415 : private:
416 : T value_;
417 : };
418 :
419 : } // namespace base
420 : } // namespace v8
421 :
422 : #endif // #define V8_ATOMIC_UTILS_H_
|