1 // Copyright 2018 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_OBJECTS_SLOTS_ATOMIC_INL_H_ 6 #define V8_OBJECTS_SLOTS_ATOMIC_INL_H_ 7 8 #include "src/base/atomic-utils.h" 9 #include "src/objects/compressed-slots.h" 10 #include "src/objects/slots.h" 11 12 namespace v8 { 13 namespace internal { 14 15 // This class is intended to be used as a wrapper for elements of an array 16 // that is passed in to STL functions such as std::sort. It ensures that 17 // elements accesses are atomic. 18 // Usage example: 19 // FixedArray array; 20 // AtomicSlot start(array->GetFirstElementAddress()); 21 // std::sort(start, start + given_length, 22 // [](Tagged_t a, Tagged_t b) { 23 // // Decompress a and b if necessary. 24 // return my_comparison(a, b); 25 // }); 26 // Note how the comparator operates on Tagged_t values, representing the raw 27 // data found at the given heap location, so you probably want to construct 28 // an Object from it. 29 class AtomicSlot : public SlotBase<AtomicSlot, Tagged_t> { 30 public: 31 // This class is a stand-in for "Address&" that uses custom atomic 32 // read/write operations for the actual memory accesses. 33 class Reference { 34 public: Reference(Tagged_t * address)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 AsAtomicTagged::Relaxed_Store( 40 address_, AsAtomicTagged::Relaxed_Load(other.address_)); 41 return *this; 42 } 43 Reference& operator=(Tagged_t value) { 44 AsAtomicTagged::Relaxed_Store(address_, value); 45 return *this; 46 } 47 48 // Values of type AtomicSlot::reference must be implicitly convertible 49 // to AtomicSlot::value_type. Tagged_t()50 operator Tagged_t() const { return AsAtomicTagged::Relaxed_Load(address_); } 51 swap(Reference & other)52 void swap(Reference& other) { 53 Tagged_t tmp = value(); 54 AsAtomicTagged::Relaxed_Store(address_, other.value()); 55 AsAtomicTagged::Relaxed_Store(other.address_, tmp); 56 } 57 58 bool operator<(const Reference& other) const { 59 return value() < other.value(); 60 } 61 62 bool operator==(const Reference& other) const { 63 return value() == other.value(); 64 } 65 66 private: value()67 Tagged_t value() const { return AsAtomicTagged::Relaxed_Load(address_); } 68 69 Tagged_t* address_; 70 }; 71 72 // The rest of this class follows C++'s "RandomAccessIterator" requirements. 73 // Most of the heavy lifting is inherited from SlotBase. 74 using difference_type = int; 75 using value_type = Tagged_t; 76 using reference = Reference; 77 using pointer = void*; // Must be present, but should not be used. 78 using iterator_category = std::random_access_iterator_tag; 79 AtomicSlot()80 AtomicSlot() : SlotBase(kNullAddress) {} AtomicSlot(Address address)81 explicit AtomicSlot(Address address) : SlotBase(address) {} AtomicSlot(ObjectSlot slot)82 explicit AtomicSlot(ObjectSlot slot) : SlotBase(slot.address()) {} AtomicSlot(MaybeObjectSlot slot)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 swap(Reference lhs,Reference rhs)92 friend void swap(Reference lhs, Reference rhs) { lhs.swap(rhs); } 93 94 friend difference_type operator-(AtomicSlot a, AtomicSlot b) { 95 return static_cast<int>(a.address() - b.address()) / kTaggedSize; 96 } 97 }; 98 99 } // namespace internal 100 } // namespace v8 101 102 #endif // V8_OBJECTS_SLOTS_ATOMIC_INL_H_ 103