LCOV - code coverage report
Current view: top level - src/base - atomic-utils.h (source / functions) Hit Total Coverage
Test: app.info Lines: 47 47 100.0 %
Date: 2017-10-20 Functions: 40 44 90.9 %

          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             : #include <type_traits>
      10             : 
      11             : #include "src/base/atomicops.h"
      12             : #include "src/base/macros.h"
      13             : 
      14             : namespace v8 {
      15             : namespace base {
      16             : 
      17             : template <class T>
      18             : class AtomicNumber {
      19             :  public:
      20      588081 :   AtomicNumber() : value_(0) {}
      21     1846670 :   explicit AtomicNumber(T initial) : value_(initial) {}
      22             : 
      23             :   // Returns the value after incrementing.
      24             :   V8_INLINE T Increment(T increment) {
      25             :     return static_cast<T>(base::Barrier_AtomicIncrement(
      26   230031518 :         &value_, static_cast<base::AtomicWord>(increment)));
      27             :   }
      28             : 
      29             :   // Returns the value after decrementing.
      30             :   V8_INLINE T Decrement(T decrement) {
      31             :     return static_cast<T>(base::Barrier_AtomicIncrement(
      32     1907079 :         &value_, -static_cast<base::AtomicWord>(decrement)));
      33             :   }
      34             : 
      35             :   V8_INLINE T Value() const {
      36    11717681 :     return static_cast<T>(base::Acquire_Load(&value_));
      37             :   }
      38             : 
      39             :   V8_INLINE void SetValue(T new_value) {
      40     2614688 :     base::Release_Store(&value_, static_cast<base::AtomicWord>(new_value));
      41             :   }
      42             : 
      43             :   V8_INLINE T operator=(T value) {
      44             :     SetValue(value);
      45             :     return value;
      46             :   }
      47             : 
      48             :   V8_INLINE T operator+=(T value) { return Increment(value); }
      49             :   V8_INLINE T operator-=(T value) { return Decrement(value); }
      50             : 
      51             :  private:
      52             :   STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
      53             : 
      54             :   base::AtomicWord value_;
      55             : };
      56             : 
      57             : // Flag using T atomically. Also accepts void* as T.
      58             : template <typename T>
      59             : class AtomicValue {
      60             :  public:
      61   330428792 :   AtomicValue() : value_(0) {}
      62             : 
      63             :   explicit AtomicValue(T initial)
      64     2292545 :       : value_(cast_helper<T>::to_storage_type(initial)) {}
      65             : 
      66             :   V8_INLINE T Value() const {
      67   932637686 :     return cast_helper<T>::to_return_type(base::Acquire_Load(&value_));
      68             :   }
      69             : 
      70             :   V8_INLINE bool TrySetValue(T old_value, T new_value) {
      71             :     return base::Release_CompareAndSwap(
      72             :                &value_, cast_helper<T>::to_storage_type(old_value),
      73     4788779 :                cast_helper<T>::to_storage_type(new_value)) ==
      74     4793065 :            cast_helper<T>::to_storage_type(old_value);
      75             :   }
      76             : 
      77             :   V8_INLINE void SetBits(T bits, T mask) {
      78             :     DCHECK_EQ(bits & ~mask, static_cast<T>(0));
      79             :     T old_value;
      80             :     T new_value;
      81             :     do {
      82             :       old_value = Value();
      83             :       new_value = (old_value & ~mask) | bits;
      84             :     } while (!TrySetValue(old_value, new_value));
      85             :   }
      86             : 
      87             :   V8_INLINE void SetBit(int bit) {
      88             :     SetBits(static_cast<T>(1) << bit, static_cast<T>(1) << bit);
      89             :   }
      90             : 
      91             :   V8_INLINE void ClearBit(int bit) { SetBits(0, 1 << bit); }
      92             : 
      93             :   V8_INLINE void SetValue(T new_value) {
      94     7187844 :     base::Release_Store(&value_, cast_helper<T>::to_storage_type(new_value));
      95             :   }
      96             : 
      97             :  private:
      98             :   STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
      99             : 
     100             :   template <typename S>
     101             :   struct cast_helper {
     102    17422273 :     static base::AtomicWord to_storage_type(S value) {
     103    17422273 :       return static_cast<base::AtomicWord>(value);
     104             :     }
     105    52240458 :     static S to_return_type(base::AtomicWord value) {
     106    52240458 :       return static_cast<S>(value);
     107             :     }
     108             :   };
     109             : 
     110             :   template <typename S>
     111             :   struct cast_helper<S*> {
     112     9250241 :     static base::AtomicWord to_storage_type(S* value) {
     113     9250241 :       return reinterpret_cast<base::AtomicWord>(value);
     114             :     }
     115   874799594 :     static S* to_return_type(base::AtomicWord value) {
     116   874799594 :       return reinterpret_cast<S*>(value);
     117             :     }
     118             :   };
     119             : 
     120             :   base::AtomicWord value_;
     121             : };
     122             : 
     123             : class AsAtomic32 {
     124             :  public:
     125             :   template <typename T>
     126             :   static T Acquire_Load(T* addr) {
     127             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32));
     128             :     return to_return_type<T>(base::Acquire_Load(to_storage_addr(addr)));
     129             :   }
     130             : 
     131             :   template <typename T>
     132             :   static T Relaxed_Load(T* addr) {
     133             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32));
     134             :     return to_return_type<T>(base::Relaxed_Load(to_storage_addr(addr)));
     135             :   }
     136             : 
     137             :   template <typename T>
     138             :   static void Release_Store(T* addr,
     139             :                             typename std::remove_reference<T>::type new_value) {
     140             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32));
     141             :     base::Release_Store(to_storage_addr(addr), to_storage_type(new_value));
     142             :   }
     143             : 
     144             :   template <typename T>
     145             :   static void Relaxed_Store(T* addr,
     146             :                             typename std::remove_reference<T>::type new_value) {
     147             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32));
     148             :     base::Relaxed_Store(to_storage_addr(addr), to_storage_type(new_value));
     149             :   }
     150             : 
     151             :   template <typename T>
     152             :   static T Release_CompareAndSwap(
     153             :       T* addr, typename std::remove_reference<T>::type old_value,
     154             :       typename std::remove_reference<T>::type new_value) {
     155             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32));
     156             :     return to_return_type<T>(base::Release_CompareAndSwap(
     157             :         to_storage_addr(addr), to_storage_type(old_value),
     158             :         to_storage_type(new_value)));
     159             :   }
     160             : 
     161             :   // Atomically sets bits selected by the mask to the given value.
     162             :   // Returns false if the bits are already set as needed.
     163             :   template <typename T>
     164  5468364730 :   static bool SetBits(T* addr, T bits, T mask) {
     165             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic32));
     166             :     DCHECK_EQ(bits & ~mask, static_cast<T>(0));
     167             :     T old_value;
     168             :     T new_value;
     169  1350231101 :     do {
     170             :       old_value = Relaxed_Load(addr);
     171  5468403858 :       if ((old_value & mask) == bits) return false;
     172  1350231101 :       new_value = (old_value & ~mask) | bits;
     173             :     } while (Release_CompareAndSwap(addr, old_value, new_value) != old_value);
     174             :     return true;
     175             :   }
     176             : 
     177             :  private:
     178             :   template <typename T>
     179             :   static base::Atomic32 to_storage_type(T value) {
     180  1350231101 :     return static_cast<base::Atomic32>(value);
     181             :   }
     182             :   template <typename T>
     183             :   static T to_return_type(base::Atomic32 value) {
     184  1350231101 :     return static_cast<T>(value);
     185             :   }
     186             :   template <typename T>
     187             :   static base::Atomic32* to_storage_addr(T* value) {
     188             :     return reinterpret_cast<base::Atomic32*>(value);
     189             :   }
     190             :   template <typename T>
     191             :   static const base::Atomic32* to_storage_addr(const T* value) {
     192             :     return reinterpret_cast<const base::Atomic32*>(value);
     193             :   }
     194             : };
     195             : 
     196             : class AsAtomicWord {
     197             :  public:
     198             :   template <typename T>
     199             :   static T Acquire_Load(T* addr) {
     200             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
     201             :     return to_return_type<T>(base::Acquire_Load(to_storage_addr(addr)));
     202             :   }
     203             : 
     204             :   template <typename T>
     205             :   static T Relaxed_Load(T* addr) {
     206             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
     207             :     return to_return_type<T>(base::Relaxed_Load(to_storage_addr(addr)));
     208             :   }
     209             : 
     210             :   template <typename T>
     211             :   static void Release_Store(T* addr,
     212             :                             typename std::remove_reference<T>::type new_value) {
     213             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
     214             :     base::Release_Store(to_storage_addr(addr), to_storage_type(new_value));
     215             :   }
     216             : 
     217             :   template <typename T>
     218             :   static void Relaxed_Store(T* addr,
     219             :                             typename std::remove_reference<T>::type new_value) {
     220             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
     221             :     base::Relaxed_Store(to_storage_addr(addr), to_storage_type(new_value));
     222             :   }
     223             : 
     224             :   template <typename T>
     225             :   static T Release_CompareAndSwap(
     226             :       T* addr, typename std::remove_reference<T>::type old_value,
     227             :       typename std::remove_reference<T>::type new_value) {
     228             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
     229             :     return to_return_type<T>(base::Release_CompareAndSwap(
     230             :         to_storage_addr(addr), to_storage_type(old_value),
     231             :         to_storage_type(new_value)));
     232             :   }
     233             : 
     234             :   // Atomically sets bits selected by the mask to the given value.
     235             :   // Returns false if the bits are already set as needed.
     236             :   template <typename T>
     237        7079 :   static bool SetBits(T* addr, T bits, T mask) {
     238             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
     239             :     DCHECK_EQ(bits & ~mask, static_cast<T>(0));
     240             :     T old_value;
     241             :     T new_value;
     242        7079 :     do {
     243             :       old_value = Relaxed_Load(addr);
     244        7079 :       if ((old_value & mask) == bits) return false;
     245        7079 :       new_value = (old_value & ~mask) | bits;
     246             :     } while (Release_CompareAndSwap(addr, old_value, new_value) != old_value);
     247             :     return true;
     248             :   }
     249             : 
     250             :  private:
     251             :   template <typename T>
     252             :   static base::AtomicWord to_storage_type(T value) {
     253        7079 :     return static_cast<base::AtomicWord>(value);
     254             :   }
     255             :   template <typename T>
     256             :   static T to_return_type(base::AtomicWord value) {
     257        7079 :     return static_cast<T>(value);
     258             :   }
     259             :   template <typename T>
     260             :   static base::AtomicWord* to_storage_addr(T* value) {
     261             :     return reinterpret_cast<base::AtomicWord*>(value);
     262             :   }
     263             :   template <typename T>
     264             :   static const base::AtomicWord* to_storage_addr(const T* value) {
     265             :     return reinterpret_cast<const base::AtomicWord*>(value);
     266             :   }
     267             : };
     268             : 
     269             : class AsAtomic8 {
     270             :  public:
     271             :   template <typename T>
     272             :   static T Acquire_Load(T* addr) {
     273             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic8));
     274             :     return to_return_type<T>(base::Acquire_Load(to_storage_addr(addr)));
     275             :   }
     276             : 
     277             :   template <typename T>
     278             :   static T Relaxed_Load(T* addr) {
     279             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic8));
     280             :     return to_return_type<T>(base::Relaxed_Load(to_storage_addr(addr)));
     281             :   }
     282             : 
     283             :   template <typename T>
     284             :   static void Release_Store(T* addr,
     285             :                             typename std::remove_reference<T>::type new_value) {
     286             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic8));
     287             :     base::Release_Store(to_storage_addr(addr), to_storage_type(new_value));
     288             :   }
     289             : 
     290             :   template <typename T>
     291             :   static void Relaxed_Store(T* addr,
     292             :                             typename std::remove_reference<T>::type new_value) {
     293             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic8));
     294             :     base::Relaxed_Store(to_storage_addr(addr), to_storage_type(new_value));
     295             :   }
     296             : 
     297             :   template <typename T>
     298             :   static T Release_CompareAndSwap(
     299             :       T* addr, typename std::remove_reference<T>::type old_value,
     300             :       typename std::remove_reference<T>::type new_value) {
     301             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::Atomic8));
     302             :     return to_return_type<T>(base::Release_CompareAndSwap(
     303             :         to_storage_addr(addr), to_storage_type(old_value),
     304             :         to_storage_type(new_value)));
     305             :   }
     306             : 
     307             :  private:
     308             :   template <typename T>
     309             :   static base::Atomic8 to_storage_type(T value) {
     310     1158398 :     return static_cast<base::Atomic8>(value);
     311             :   }
     312             :   template <typename T>
     313             :   static T to_return_type(base::Atomic8 value) {
     314         336 :     return static_cast<T>(value);
     315             :   }
     316             :   template <typename T>
     317             :   static base::Atomic8* to_storage_addr(T* value) {
     318             :     return reinterpret_cast<base::Atomic8*>(value);
     319             :   }
     320             :   template <typename T>
     321             :   static const base::Atomic8* to_storage_addr(const T* value) {
     322             :     return reinterpret_cast<const base::Atomic8*>(value);
     323             :   }
     324             : };
     325             : 
     326             : class AsAtomicPointer {
     327             :  public:
     328             :   template <typename T>
     329             :   static T Acquire_Load(T* addr) {
     330             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
     331             :     return to_return_type<T>(base::Acquire_Load(to_storage_addr(addr)));
     332             :   }
     333             : 
     334             :   template <typename T>
     335   196488048 :   static T Relaxed_Load(T* addr) {
     336             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
     337   196488048 :     return to_return_type<T>(base::Relaxed_Load(to_storage_addr(addr)));
     338             :   }
     339             : 
     340             :   template <typename T>
     341             :   static void Release_Store(T* addr,
     342             :                             typename std::remove_reference<T>::type new_value) {
     343             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
     344             :     base::Release_Store(to_storage_addr(addr), to_storage_type(new_value));
     345             :   }
     346             : 
     347             :   template <typename T>
     348             :   static void Relaxed_Store(T* addr,
     349             :                             typename std::remove_reference<T>::type new_value) {
     350             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
     351             :     base::Relaxed_Store(to_storage_addr(addr), to_storage_type(new_value));
     352             :   }
     353             : 
     354             :   template <typename T>
     355   105885645 :   static T Release_CompareAndSwap(
     356             :       T* addr, typename std::remove_reference<T>::type old_value,
     357             :       typename std::remove_reference<T>::type new_value) {
     358             :     STATIC_ASSERT(sizeof(T) <= sizeof(base::AtomicWord));
     359             :     return to_return_type<T>(base::Release_CompareAndSwap(
     360             :         to_storage_addr(addr), to_storage_type(old_value),
     361   105885645 :         to_storage_type(new_value)));
     362             :   }
     363             : 
     364             :  private:
     365             :   template <typename T>
     366             :   static base::AtomicWord to_storage_type(T value) {
     367   105885645 :     return reinterpret_cast<base::AtomicWord>(value);
     368             :   }
     369             :   template <typename T>
     370             :   static T to_return_type(base::AtomicWord value) {
     371  3880333218 :     return reinterpret_cast<T>(value);
     372             :   }
     373             :   template <typename T>
     374             :   static base::AtomicWord* to_storage_addr(T* value) {
     375             :     return reinterpret_cast<base::AtomicWord*>(value);
     376             :   }
     377             :   template <typename T>
     378             :   static const base::AtomicWord* to_storage_addr(const T* value) {
     379             :     return reinterpret_cast<const base::AtomicWord*>(value);
     380             :   }
     381             : };
     382             : 
     383             : // This class is intended to be used as a wrapper for elements of an array
     384             : // that is passed in to STL functions such as std::sort. It ensures that
     385             : // elements accesses are atomic.
     386             : // Usage example:
     387             : //   Object** given_array;
     388             : //   AtomicElement<Object*>* wrapped =
     389             : //       reinterpret_cast<AtomicElement<Object*>(given_array);
     390             : //   std::sort(wrapped, wrapped + given_length, cmp);
     391             : // where the cmp function uses the value() accessor to compare the elements.
     392             : template <typename T>
     393             : class AtomicElement {
     394             :  public:
     395    21102212 :   AtomicElement(const AtomicElement<T>& other) {
     396             :     AsAtomicPointer::Relaxed_Store(
     397    42204424 :         &value_, AsAtomicPointer::Relaxed_Load(&other.value_));
     398    21102212 :   }
     399             : 
     400    57241961 :   void operator=(const AtomicElement<T>& other) {
     401             :     AsAtomicPointer::Relaxed_Store(
     402   114483922 :         &value_, AsAtomicPointer::Relaxed_Load(&other.value_));
     403    57241961 :   }
     404             : 
     405   176260026 :   T value() const { return AsAtomicPointer::Relaxed_Load(&value_); }
     406             : 
     407             :   bool operator<(const AtomicElement<T>& other) const {
     408             :     return value() < other.value();
     409             :   }
     410             : 
     411             :   bool operator==(const AtomicElement<T>& other) const {
     412             :     return value() == other.value();
     413             :   }
     414             : 
     415             :  private:
     416             :   T value_;
     417             : };
     418             : 
     419             : }  // namespace base
     420             : }  // namespace v8
     421             : 
     422             : #endif  // #define V8_ATOMIC_UTILS_H_

Generated by: LCOV version 1.10