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 :
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:
19 511063 : AtomicNumber() : value_(0) {}
20 877980 : explicit AtomicNumber(T initial) : value_(initial) {}
21 :
22 : // Returns the value after incrementing.
23 : V8_INLINE T Increment(T increment) {
24 : return static_cast<T>(base::Barrier_AtomicIncrement(
25 38232656 : &value_, static_cast<base::AtomicWord>(increment)));
26 : }
27 :
28 : // Returns the value after decrementing.
29 : V8_INLINE T Decrement(T decrement) {
30 : return static_cast<T>(base::Barrier_AtomicIncrement(
31 4072160 : &value_, -static_cast<base::AtomicWord>(decrement)));
32 : }
33 :
34 : V8_INLINE T Value() const {
35 3335375 : return static_cast<T>(base::Acquire_Load(&value_));
36 : }
37 :
38 : V8_INLINE void SetValue(T new_value) {
39 2384954 : 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:
61 : NoBarrierAtomicValue() : value_(0) {}
62 :
63 : explicit NoBarrierAtomicValue(T initial)
64 : : value_(cast_helper<T>::to_storage_type(initial)) {}
65 :
66 : static NoBarrierAtomicValue* FromAddress(void* address) {
67 : return reinterpret_cast<base::NoBarrierAtomicValue<T>*>(address);
68 : }
69 :
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 30873231 : cast_helper<T>::to_storage_type(new_value)) ==
74 31512821 : cast_helper<T>::to_storage_type(old_value);
75 : }
76 :
77 : V8_INLINE T Value() const {
78 1204927797 : return cast_helper<T>::to_return_type(base::NoBarrier_Load(&value_));
79 : }
80 :
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 {
90 : static base::AtomicWord to_storage_type(S value) {
91 : return static_cast<base::AtomicWord>(value);
92 : }
93 374133958 : static S to_return_type(base::AtomicWord value) {
94 374133958 : return static_cast<S>(value);
95 : }
96 : };
97 :
98 : template <typename S>
99 : struct cast_helper<S*> {
100 91427299 : static base::AtomicWord to_storage_type(S* value) {
101 91427299 : return reinterpret_cast<base::AtomicWord>(value);
102 : }
103 829411387 : static S* to_return_type(base::AtomicWord value) {
104 829411387 : 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 757803779 : AtomicValue() : value_(0) {}
116 :
117 : explicit AtomicValue(T initial)
118 1465295 : : value_(cast_helper<T>::to_storage_type(initial)) {}
119 :
120 : V8_INLINE T Value() const {
121 1461289066 : 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 151416892 : cast_helper<T>::to_storage_type(new_value)) ==
128 150906812 : 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 132715378 : do {
136 : old_value = Value();
137 132703409 : new_value = (old_value & ~mask) | bits;
138 : } while (!TrySetValue(old_value, new_value));
139 : }
140 :
141 : V8_INLINE void SetBit(int bit) {
142 128954161 : SetBits(static_cast<T>(1) << bit, static_cast<T>(1) << bit);
143 : }
144 :
145 14 : V8_INLINE void ClearBit(int bit) { SetBits(0, 1 << bit); }
146 :
147 : V8_INLINE void SetValue(T new_value) {
148 89503800 : 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 531213005 : static base::AtomicWord to_storage_type(S value) {
157 531213005 : return static_cast<base::AtomicWord>(value);
158 : }
159 689169342 : static S to_return_type(base::AtomicWord value) {
160 689169342 : return static_cast<S>(value);
161 : }
162 : };
163 :
164 : template <typename S>
165 : struct cast_helper<S*> {
166 27276954 : static base::AtomicWord to_storage_type(S* value) {
167 27276954 : return reinterpret_cast<base::AtomicWord>(value);
168 : }
169 775323840 : static S* to_return_type(base::AtomicWord value) {
170 775323840 : 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_
|