slots-atomic-inl.h 3.47 KB
Newer Older
1 2 3 4 5 6 7 8
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_OBJECTS_SLOTS_ATOMIC_INL_H_
#define V8_OBJECTS_SLOTS_ATOMIC_INL_H_

#include "src/base/atomic-utils.h"
9
#include "src/objects/compressed-slots.h"
10 11 12 13 14 15 16 17 18 19 20 21
#include "src/objects/slots.h"

namespace v8 {
namespace internal {

// This class is intended to be used as a wrapper for elements of an array
// that is passed in to STL functions such as std::sort. It ensures that
// elements accesses are atomic.
// Usage example:
//   FixedArray array;
//   AtomicSlot start(array->GetFirstElementAddress());
//   std::sort(start, start + given_length,
22 23
//             [](Tagged_t a, Tagged_t b) {
//               // Decompress a and b if necessary.
24 25
//               return my_comparison(a, b);
//             });
26
// Note how the comparator operates on Tagged_t values, representing the raw
27 28
// data found at the given heap location, so you probably want to construct
// an Object from it.
29
class AtomicSlot : public SlotBase<AtomicSlot, Tagged_t> {
30 31 32 33 34
 public:
  // This class is a stand-in for "Address&" that uses custom atomic
  // read/write operations for the actual memory accesses.
  class Reference {
   public:
35
    explicit Reference(Tagged_t* address) : address_(address) {}
36
    Reference(const Reference&) V8_NOEXCEPT = default;
37

38
    Reference& operator=(const Reference& other) V8_NOEXCEPT {
39 40
      AsAtomicTagged::Relaxed_Store(
          address_, AsAtomicTagged::Relaxed_Load(other.address_));
41 42
      return *this;
    }
43 44
    Reference& operator=(Tagged_t value) {
      AsAtomicTagged::Relaxed_Store(address_, value);
45 46 47 48 49
      return *this;
    }

    // Values of type AtomicSlot::reference must be implicitly convertible
    // to AtomicSlot::value_type.
50
    operator Tagged_t() const { return AsAtomicTagged::Relaxed_Load(address_); }
51 52

    void swap(Reference& other) {
53
      Tagged_t tmp = value();
54 55
      AsAtomicTagged::Relaxed_Store(address_, other.value());
      AsAtomicTagged::Relaxed_Store(other.address_, tmp);
56 57 58 59 60 61 62 63 64 65 66
    }

    bool operator<(const Reference& other) const {
      return value() < other.value();
    }

    bool operator==(const Reference& other) const {
      return value() == other.value();
    }

   private:
67
    Tagged_t value() const { return AsAtomicTagged::Relaxed_Load(address_); }
68

69
    Tagged_t* address_;
70 71 72 73
  };

  // The rest of this class follows C++'s "RandomAccessIterator" requirements.
  // Most of the heavy lifting is inherited from SlotBase.
74 75 76 77 78
  using difference_type = int;
  using value_type = Tagged_t;
  using reference = Reference;
  using pointer = void*;  // Must be present, but should not be used.
  using iterator_category = std::random_access_iterator_tag;
79 80 81 82

  AtomicSlot() : SlotBase(kNullAddress) {}
  explicit AtomicSlot(Address address) : SlotBase(address) {}
  explicit AtomicSlot(ObjectSlot slot) : SlotBase(slot.address()) {}
83
  explicit AtomicSlot(MaybeObjectSlot slot) : SlotBase(slot.address()) {}
84 85

  Reference operator*() const {
86
    return Reference(reinterpret_cast<Tagged_t*>(address()));
87 88
  }
  Reference operator[](difference_type i) const {
89
    return Reference(reinterpret_cast<Tagged_t*>(address() + i * kTaggedSize));
90 91 92 93 94
  }

  friend void swap(Reference lhs, Reference rhs) { lhs.swap(rhs); }

  friend difference_type operator-(AtomicSlot a, AtomicSlot b) {
95
    return static_cast<int>(a.address() - b.address()) / kTaggedSize;
96 97 98 99 100 101 102
  }
};

}  // namespace internal
}  // namespace v8

#endif  // V8_OBJECTS_SLOTS_ATOMIC_INL_H_