Home | History | Annotate | Download | only in src
      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_
    176