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_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:
22 180257301 : AtomicValue() : value_(0) {}
23 :
24 : explicit AtomicValue(T initial)
25 1890278 : : value_(cast_helper<T>::to_storage_type(initial)) {}
26 :
27 : V8_INLINE T Value() const {
28 12471061 : return cast_helper<T>::to_return_type(base::Acquire_Load(&value_));
29 : }
30 :
31 : V8_INLINE void SetValue(T new_value) {
32 1963351 : 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 {
40 2 : static base::AtomicWord to_storage_type(S value) {
41 2 : return static_cast<base::AtomicWord>(value);
42 : }
43 1282660 : static S to_return_type(base::AtomicWord value) {
44 1282701 : return static_cast<S>(value);
45 : }
46 : };
47 :
48 : template <typename S>
49 : struct cast_helper<S*> {
50 137158 : static base::AtomicWord to_storage_type(S* value) {
51 137158 : return reinterpret_cast<base::AtomicWord>(value);
52 : }
53 4966535 : static S* to_return_type(base::AtomicWord value) {
54 4966602 : 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 26293280 : static T Relaxed_Load(T* addr) {
76 : STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType));
77 : return cast_helper<T>::to_return_type(
78 26293280 : 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 : // Atomically sets bits selected by the mask to the given value.
108 : // Returns false if the bits are already set as needed.
109 : template <typename T>
110 5626208680 : static bool SetBits(T* addr, T bits, T mask) {
111 : STATIC_ASSERT(sizeof(T) <= sizeof(AtomicStorageType));
112 : DCHECK_EQ(bits & ~mask, static_cast<T>(0));
113 : T old_value;
114 : T new_value;
115 1323770662 : do {
116 : old_value = Relaxed_Load(addr);
117 5626398328 : if ((old_value & mask) == bits) return false;
118 1323770662 : new_value = (old_value & ~mask) | bits;
119 : } while (Release_CompareAndSwap(addr, old_value, new_value) != old_value);
120 : return true;
121 : }
122 :
123 : private:
124 : template <typename U>
125 : struct cast_helper {
126 : static AtomicStorageType to_storage_type(U value) {
127 1378297761 : return static_cast<AtomicStorageType>(value);
128 : }
129 : static U to_return_type(AtomicStorageType value) {
130 1437899218 : return static_cast<U>(value);
131 : }
132 : };
133 :
134 : template <typename U>
135 : struct cast_helper<U*> {
136 : static AtomicStorageType to_storage_type(U* value) {
137 : return reinterpret_cast<AtomicStorageType>(value);
138 : }
139 : static U* to_return_type(AtomicStorageType value) {
140 460741327 : return reinterpret_cast<U*>(value);
141 : }
142 : };
143 :
144 : template <typename T>
145 : static AtomicStorageType* to_storage_addr(T* value) {
146 : return reinterpret_cast<AtomicStorageType*>(value);
147 : }
148 : template <typename T>
149 : static const AtomicStorageType* to_storage_addr(const T* value) {
150 : return reinterpret_cast<const AtomicStorageType*>(value);
151 : }
152 : };
153 :
154 : using AsAtomic8 = AsAtomicImpl<base::Atomic8>;
155 : using AsAtomic32 = AsAtomicImpl<base::Atomic32>;
156 : using AsAtomicWord = AsAtomicImpl<base::AtomicWord>;
157 :
158 : // This is similar to AsAtomicWord but it explicitly deletes functionality
159 : // provided atomic access to bit representation of stored values.
160 : template <typename TAtomicStorageType>
161 : class AsAtomicPointerImpl : public AsAtomicImpl<TAtomicStorageType> {
162 : public:
163 : template <typename T>
164 : static bool SetBits(T* addr, T bits, T mask) = delete;
165 : };
166 :
167 : using AsAtomicPointer = AsAtomicPointerImpl<base::AtomicWord>;
168 :
169 : template <typename T,
170 : typename = typename std::enable_if<std::is_unsigned<T>::value>::type>
171 : inline void CheckedIncrement(std::atomic<T>* number, T amount) {
172 : const T old = number->fetch_add(amount);
173 : DCHECK_GE(old + amount, old);
174 : USE(old);
175 : }
176 :
177 : template <typename T,
178 : typename = typename std::enable_if<std::is_unsigned<T>::value>::type>
179 : inline void CheckedDecrement(std::atomic<T>* number, T amount) {
180 : const T old = number->fetch_sub(amount);
181 : DCHECK_GE(old, amount);
182 : USE(old);
183 : }
184 :
185 : } // namespace base
186 : } // namespace v8
187 :
188 : #endif // V8_BASE_ATOMIC_UTILS_H_
|