v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
atomic-utils.h
Go to the documentation of this file.
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
10#include <atomic>
11#include <type_traits>
12
13#include "src/base/atomicops.h"
14#include "src/base/macros.h"
16
17namespace v8 {
18namespace base {
19
20// Deprecated. Use std::atomic<T> for new code.
21// Flag using T atomically. Also accepts void* as T.
22template <typename T>
24 public:
26
27 explicit AtomicValue(T initial)
28 : value_(cast_helper<T>::to_storage_type(initial)) {}
29
33
37
38 private:
39 static_assert(sizeof(T) <= sizeof(base::AtomicWord));
40
41 template <typename S>
42 struct cast_helper {
44 return static_cast<base::AtomicWord>(value);
45 }
47 return static_cast<S>(value);
48 }
49 };
50
51 template <typename S>
52 struct cast_helper<S*> {
54 return reinterpret_cast<base::AtomicWord>(value);
55 }
57 return reinterpret_cast<S*>(value);
58 }
59 };
60
62};
63
64// Provides atomic operations for a values stored at some address.
65template <typename TAtomicStorageType>
67 public:
68 using AtomicStorageType = TAtomicStorageType;
69
70 template <typename T>
71 static T SeqCst_Load(T* addr) {
72 static_assert(sizeof(T) <= sizeof(AtomicStorageType));
75 }
76
77 template <typename T>
78 static T Acquire_Load(T* addr) {
79 static_assert(sizeof(T) <= sizeof(AtomicStorageType));
82 }
83
84 template <typename T>
85 static T Relaxed_Load(T* addr) {
86 static_assert(sizeof(T) <= sizeof(AtomicStorageType));
89 }
90
91 template <typename T>
92 static void SeqCst_Store(T* addr,
93 typename std::remove_reference<T>::type new_value) {
94 static_assert(sizeof(T) <= sizeof(AtomicStorageType));
97 }
98
99 template <typename T>
100 static void Release_Store(T* addr,
101 typename std::remove_reference<T>::type new_value) {
102 static_assert(sizeof(T) <= sizeof(AtomicStorageType));
105 }
106
107 template <typename T>
108 static void Relaxed_Store(T* addr,
109 typename std::remove_reference<T>::type new_value) {
110 static_assert(sizeof(T) <= sizeof(AtomicStorageType));
113 }
114
115 template <typename T>
116 static T SeqCst_Swap(T* addr,
117 typename std::remove_reference<T>::type new_value) {
118 static_assert(sizeof(T) <= sizeof(AtomicStorageType));
121 }
122
123 template <typename T>
125 T* addr, typename std::remove_reference<T>::type old_value,
126 typename std::remove_reference<T>::type new_value) {
127 static_assert(sizeof(T) <= sizeof(AtomicStorageType));
131 }
132
133 template <typename T>
135 T* addr, typename std::remove_reference<T>::type old_value,
136 typename std::remove_reference<T>::type new_value) {
137 static_assert(sizeof(T) <= sizeof(AtomicStorageType));
141 }
142
143 template <typename T>
145 T* addr, typename std::remove_reference<T>::type old_value,
146 typename std::remove_reference<T>::type new_value) {
147 static_assert(sizeof(T) <= sizeof(AtomicStorageType));
151 }
152
153 template <typename T>
155 T* addr, typename std::remove_reference<T>::type old_value,
156 typename std::remove_reference<T>::type new_value) {
157 static_assert(sizeof(T) <= sizeof(AtomicStorageType));
161 }
162
163 // Atomically sets bits selected by the mask to the given value.
164 // Returns false if the bits are already set as needed.
165 template <typename T>
166 static bool Release_SetBits(T* addr, T bits, T mask) {
167 static_assert(sizeof(T) <= sizeof(AtomicStorageType));
168 DCHECK_EQ(bits & ~mask, static_cast<T>(0));
169 T old_value = Relaxed_Load(addr);
170 T new_value, old_value_before_cas;
171 do {
172 if ((old_value & mask) == bits) return false;
173 new_value = (old_value & ~mask) | bits;
174 old_value_before_cas = old_value;
175 old_value = Release_CompareAndSwap(addr, old_value, new_value);
176 } while (old_value != old_value_before_cas);
177 return true;
178 }
179
180 // Atomically sets bits selected by the mask to the given value.
181 // Returns false if the bits are already set as needed.
182 template <typename T>
183 static bool Relaxed_SetBits(T* addr, T bits, T mask) {
184 static_assert(sizeof(T) <= sizeof(AtomicStorageType));
185 DCHECK_EQ(bits & ~mask, static_cast<T>(0));
186 T old_value = Relaxed_Load(addr);
187 T new_value, old_value_before_cas;
188 do {
189 if ((old_value & mask) == bits) return false;
190 new_value = (old_value & ~mask) | bits;
191 old_value_before_cas = old_value;
192 old_value = Relaxed_CompareAndSwap(addr, old_value, new_value);
193 } while (old_value != old_value_before_cas);
194 return true;
195 }
196
197 private:
198 template <typename U>
199 struct cast_helper {
201 return static_cast<AtomicStorageType>(value);
202 }
204 return static_cast<U>(value);
205 }
206 };
207
208 template <typename U>
209 struct cast_helper<U*> {
211 return reinterpret_cast<AtomicStorageType>(value);
212 }
214 return reinterpret_cast<U*>(value);
215 }
216 };
217 template <typename T, typename U>
218 struct cast_helper<base::StrongAlias<T, U>> {
220 return static_cast<AtomicStorageType>(value.value());
221 }
223 return base::StrongAlias<T, U>(static_cast<U>(value));
224 }
225 };
226
227 template <typename T>
229 return reinterpret_cast<AtomicStorageType*>(value);
230 }
231 template <typename T>
232 static const AtomicStorageType* to_storage_addr(const T* value) {
233 return reinterpret_cast<const AtomicStorageType*>(value);
234 }
235};
236
241
242template <int Width>
244template <>
248template <>
252template <>
256#if V8_HOST_ARCH_64_BIT
257template <>
258struct AtomicTypeFromByteWidth<8> {
259 using type = base::Atomic64;
260};
261#endif
262
263// This is similar to AsAtomicWord but it explicitly deletes functionality
264// provided atomic access to bit representation of stored values.
265template <typename TAtomicStorageType>
266class AsAtomicPointerImpl : public AsAtomicImpl<TAtomicStorageType> {
267 public:
268 template <typename T>
269 static bool SetBits(T* addr, T bits, T mask) = delete;
270};
271
273
274template <typename T>
276 std::atomic<T>* number, T amount,
277 std::memory_order order = std::memory_order_seq_cst)
278 requires std::is_unsigned<T>::value
279{
280 const T old = number->fetch_add(amount, order);
281 DCHECK_GE(old + amount, old);
282 USE(old);
283}
284
285template <typename T>
287 std::atomic<T>* number, T amount,
288 std::memory_order order = std::memory_order_seq_cst)
289 requires std::is_unsigned<T>::value
290{
291 const T old = number->fetch_sub(amount, order);
292 DCHECK_GE(old, amount);
293 USE(old);
294}
295
296template <typename T>
297V8_INLINE std::atomic<T>* AsAtomicPtr(T* t) {
298 static_assert(sizeof(T) == sizeof(std::atomic<T>));
299 static_assert(alignof(T) >= alignof(std::atomic<T>));
300 return reinterpret_cast<std::atomic<T>*>(t);
301}
302
303template <typename T>
304V8_INLINE const std::atomic<T>* AsAtomicPtr(const T* t) {
305 static_assert(sizeof(T) == sizeof(std::atomic<T>));
306 static_assert(alignof(T) >= alignof(std::atomic<T>));
307 return reinterpret_cast<const std::atomic<T>*>(t);
308}
309
310} // namespace base
311} // namespace v8
312
313#endif // V8_BASE_ATOMIC_UTILS_H_
#define T
static T Relaxed_CompareAndSwap(T *addr, typename std::remove_reference< T >::type old_value, typename std::remove_reference< T >::type new_value)
static void Release_Store(T *addr, typename std::remove_reference< T >::type new_value)
static T AcquireRelease_CompareAndSwap(T *addr, typename std::remove_reference< T >::type old_value, typename std::remove_reference< T >::type new_value)
static void SeqCst_Store(T *addr, typename std::remove_reference< T >::type new_value)
static T Acquire_Load(T *addr)
static void Relaxed_Store(T *addr, typename std::remove_reference< T >::type new_value)
static T Release_CompareAndSwap(T *addr, typename std::remove_reference< T >::type old_value, typename std::remove_reference< T >::type new_value)
static bool Release_SetBits(T *addr, T bits, T mask)
static const AtomicStorageType * to_storage_addr(const T *value)
static T SeqCst_Swap(T *addr, typename std::remove_reference< T >::type new_value)
static T SeqCst_Load(T *addr)
static T SeqCst_CompareAndSwap(T *addr, typename std::remove_reference< T >::type old_value, typename std::remove_reference< T >::type new_value)
static T Relaxed_Load(T *addr)
static AtomicStorageType * to_storage_addr(T *value)
static bool Relaxed_SetBits(T *addr, T bits, T mask)
TAtomicStorageType AtomicStorageType
static bool SetBits(T *addr, T bits, T mask)=delete
V8_INLINE void SetValue(T new_value)
V8_INLINE T Value() const
base::AtomicWord value_
uint32_t const mask
void Relaxed_Store(volatile Atomic8 *ptr, Atomic8 value)
Definition atomicops.h:189
Atomic32 AtomicWord
Definition atomicops.h:76
Atomic8 Release_CompareAndSwap(volatile Atomic8 *ptr, Atomic8 old_value, Atomic8 new_value)
Definition atomicops.h:155
Atomic8 Relaxed_CompareAndSwap(volatile Atomic8 *ptr, Atomic8 old_value, Atomic8 new_value)
Definition atomicops.h:104
Atomic8 Relaxed_Load(volatile const Atomic8 *ptr)
Definition atomicops.h:234
Atomic32 SeqCst_CompareAndSwap(volatile Atomic32 *ptr, Atomic32 old_value, Atomic32 new_value)
Definition atomicops.h:181
Atomic8 SeqCst_Load(volatile const Atomic8 *ptr)
Definition atomicops.h:259
int16_t Atomic16
Definition atomicops.h:58
char Atomic8
Definition atomicops.h:57
Atomic8 Acquire_Load(volatile const Atomic8 *ptr)
Definition atomicops.h:249
Atomic32 SeqCst_AtomicExchange(volatile Atomic32 *ptr, Atomic32 new_value)
Definition atomicops.h:134
void CheckedDecrement(std::atomic< T > *number, T amount, std::memory_order order=std::memory_order_seq_cst)
void Release_Store(volatile Atomic8 *ptr, Atomic8 value)
Definition atomicops.h:204
int32_t Atomic32
Definition atomicops.h:59
V8_INLINE std::atomic< T > * AsAtomicPtr(T *t)
void SeqCst_Store(volatile Atomic8 *ptr, Atomic8 value)
Definition atomicops.h:219
void CheckedIncrement(std::atomic< T > *number, T amount, std::memory_order order=std::memory_order_seq_cst)
Atomic32 AcquireRelease_CompareAndSwap(volatile Atomic32 *ptr, Atomic32 old_value, Atomic32 new_value)
Definition atomicops.h:172
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define USE(...)
Definition macros.h:293
static AtomicStorageType to_storage_type(U *value)
static U * to_return_type(AtomicStorageType value)
static base::StrongAlias< T, U > to_return_type(AtomicStorageType value)
static AtomicStorageType to_storage_type(base::StrongAlias< T, U > value)
static U to_return_type(AtomicStorageType value)
static AtomicStorageType to_storage_type(U value)
static base::AtomicWord to_storage_type(S *value)
static S * to_return_type(base::AtomicWord value)
static S to_return_type(base::AtomicWord value)
static base::AtomicWord to_storage_type(S value)
#define V8_INLINE
Definition v8config.h:500
std::unique_ptr< ValueMirror > value