• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
AtomicNumber()19   AtomicNumber() : value_(0) {}
AtomicNumber(T initial)20   explicit AtomicNumber(T initial) : value_(initial) {}
21 
22   // Returns the newly set value.
Increment(T increment)23   V8_INLINE T Increment(T increment) {
24     return static_cast<T>(base::Barrier_AtomicIncrement(
25         &value_, static_cast<base::AtomicWord>(increment)));
26   }
27 
Value()28   V8_INLINE T Value() { return static_cast<T>(base::Acquire_Load(&value_)); }
29 
SetValue(T new_value)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:
AtomicValue()50   AtomicValue() : value_(0) {}
51 
AtomicValue(T initial)52   explicit AtomicValue(T initial)
53       : value_(cast_helper<T>::to_storage_type(initial)) {}
54 
Value()55   V8_INLINE T Value() {
56     return cast_helper<T>::to_return_type(base::Acquire_Load(&value_));
57   }
58 
TrySetValue(T old_value,T new_value)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 
SetValue(T new_value)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 {
to_storage_typecast_helper75     static base::AtomicWord to_storage_type(S value) {
76       return static_cast<base::AtomicWord>(value);
77     }
to_return_typecast_helper78     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_
176