OLD | NEW |
| (Empty) |
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 internal { | |
15 | |
16 template <class T> | |
17 class AtomicNumber { | |
18 public: | |
19 AtomicNumber() : value_(0) {} | |
20 explicit AtomicNumber(T initial) : value_(initial) {} | |
21 | |
22 // Returns the newly set value. | |
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 V8_INLINE T Value() { return static_cast<T>(base::Acquire_Load(&value_)); } | |
29 | |
30 V8_INLINE void SetValue(T new_value) { | |
31 base::Release_Store(&value_, static_cast<base::AtomicWord>(new_value)); | |
32 } | |
33 | |
34 V8_INLINE T operator=(T value) { | |
35 SetValue(value); | |
36 return value; | |
37 } | |
38 | |
39 private: | |
40 STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord)); | |
41 | |
42 base::AtomicWord value_; | |
43 }; | |
44 | |
45 | |
46 // Flag using T atomically. Also accepts void* as T. | |
47 template <typename T> | |
48 class AtomicValue { | |
49 public: | |
50 AtomicValue() : value_(0) {} | |
51 | |
52 explicit AtomicValue(T initial) | |
53 : value_(cast_helper<T>::to_storage_type(initial)) {} | |
54 | |
55 V8_INLINE T Value() { | |
56 return cast_helper<T>::to_return_type(base::Acquire_Load(&value_)); | |
57 } | |
58 | |
59 V8_INLINE bool TrySetValue(T old_value, T new_value) { | |
60 return base::Release_CompareAndSwap( | |
61 &value_, cast_helper<T>::to_storage_type(old_value), | |
62 cast_helper<T>::to_storage_type(new_value)) == | |
63 cast_helper<T>::to_storage_type(old_value); | |
64 } | |
65 | |
66 V8_INLINE void SetValue(T new_value) { | |
67 base::Release_Store(&value_, cast_helper<T>::to_storage_type(new_value)); | |
68 } | |
69 | |
70 private: | |
71 STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord)); | |
72 | |
73 template <typename S> | |
74 struct cast_helper { | |
75 static base::AtomicWord to_storage_type(S value) { | |
76 return static_cast<base::AtomicWord>(value); | |
77 } | |
78 static S to_return_type(base::AtomicWord value) { | |
79 return static_cast<S>(value); | |
80 } | |
81 }; | |
82 | |
83 template <typename S> | |
84 struct cast_helper<S*> { | |
85 static base::AtomicWord to_storage_type(S* value) { | |
86 return reinterpret_cast<base::AtomicWord>(value); | |
87 } | |
88 static S* to_return_type(base::AtomicWord value) { | |
89 return reinterpret_cast<S*>(value); | |
90 } | |
91 }; | |
92 | |
93 base::AtomicWord value_; | |
94 }; | |
95 | |
96 | |
97 // See utils.h for EnumSet. Storage is always base::AtomicWord. | |
98 // Requirements on E: | |
99 // - No explicit values. | |
100 // - E::kLastValue defined to be the last actually used value. | |
101 // | |
102 // Example: | |
103 // enum E { kA, kB, kC, kLastValue = kC }; | |
104 template <class E> | |
105 class AtomicEnumSet { | |
106 public: | |
107 explicit AtomicEnumSet(base::AtomicWord bits = 0) : bits_(bits) {} | |
108 | |
109 bool IsEmpty() const { return ToIntegral() == 0; } | |
110 | |
111 bool Contains(E element) const { return (ToIntegral() & Mask(element)) != 0; } | |
112 bool ContainsAnyOf(const AtomicEnumSet& set) const { | |
113 return (ToIntegral() & set.ToIntegral()) != 0; | |
114 } | |
115 | |
116 void RemoveAll() { base::Release_Store(&bits_, 0); } | |
117 | |
118 bool operator==(const AtomicEnumSet& set) const { | |
119 return ToIntegral() == set.ToIntegral(); | |
120 } | |
121 | |
122 bool operator!=(const AtomicEnumSet& set) const { | |
123 return ToIntegral() != set.ToIntegral(); | |
124 } | |
125 | |
126 AtomicEnumSet<E> operator|(const AtomicEnumSet& set) const { | |
127 return AtomicEnumSet<E>(ToIntegral() | set.ToIntegral()); | |
128 } | |
129 | |
130 // The following operations modify the underlying storage. | |
131 | |
132 #define ATOMIC_SET_WRITE(OP, NEW_VAL) \ | |
133 do { \ | |
134 base::AtomicWord old; \ | |
135 do { \ | |
136 old = base::Acquire_Load(&bits_); \ | |
137 } while (base::Release_CompareAndSwap(&bits_, old, old OP NEW_VAL) != \ | |
138 old); \ | |
139 } while (false) | |
140 | |
141 void Add(E element) { ATOMIC_SET_WRITE(|, Mask(element)); } | |
142 | |
143 void Add(const AtomicEnumSet& set) { ATOMIC_SET_WRITE(|, set.ToIntegral()); } | |
144 | |
145 void Remove(E element) { ATOMIC_SET_WRITE(&, ~Mask(element)); } | |
146 | |
147 void Remove(const AtomicEnumSet& set) { | |
148 ATOMIC_SET_WRITE(&, ~set.ToIntegral()); | |
149 } | |
150 | |
151 void Intersect(const AtomicEnumSet& set) { | |
152 ATOMIC_SET_WRITE(&, set.ToIntegral()); | |
153 } | |
154 | |
155 #undef ATOMIC_SET_OP | |
156 | |
157 private: | |
158 // Check whether there's enough storage to hold E. | |
159 STATIC_ASSERT(E::kLastValue < (sizeof(base::AtomicWord) * CHAR_BIT)); | |
160 | |
161 V8_INLINE base::AtomicWord ToIntegral() const { | |
162 return base::Acquire_Load(&bits_); | |
163 } | |
164 | |
165 V8_INLINE base::AtomicWord Mask(E element) const { | |
166 return static_cast<base::AtomicWord>(1) << element; | |
167 } | |
168 | |
169 base::AtomicWord bits_; | |
170 }; | |
171 | |
172 } // namespace internal | |
173 } // namespace v8 | |
174 | |
175 #endif // #define V8_ATOMIC_UTILS_H_ | |
OLD | NEW |