// 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" #include "src/objects/compressed-slots.h" #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, // [](Tagged_t a, Tagged_t b) { // // Decompress a and b if necessary. // return my_comparison(a, b); // }); // Note how the comparator operates on Tagged_t values, representing the raw // data found at the given heap location, so you probably want to construct // an Object from it. class AtomicSlot : public SlotBase { public: // This class is a stand-in for "Address&" that uses custom atomic // read/write operations for the actual memory accesses. class Reference { public: explicit Reference(Tagged_t* address) : address_(address) {} Reference(const Reference&) V8_NOEXCEPT = default; Reference& operator=(const Reference& other) V8_NOEXCEPT { AsAtomicTagged::Relaxed_Store( address_, AsAtomicTagged::Relaxed_Load(other.address_)); return *this; } Reference& operator=(Tagged_t value) { AsAtomicTagged::Relaxed_Store(address_, value); return *this; } // Values of type AtomicSlot::reference must be implicitly convertible // to AtomicSlot::value_type. operator Tagged_t() const { return AsAtomicTagged::Relaxed_Load(address_); } void swap(Reference& other) { Tagged_t tmp = value(); AsAtomicTagged::Relaxed_Store(address_, other.value()); AsAtomicTagged::Relaxed_Store(other.address_, tmp); } bool operator<(const Reference& other) const { return value() < other.value(); } bool operator==(const Reference& other) const { return value() == other.value(); } private: Tagged_t value() const { return AsAtomicTagged::Relaxed_Load(address_); } Tagged_t* address_; }; // The rest of this class follows C++'s "RandomAccessIterator" requirements. // Most of the heavy lifting is inherited from SlotBase. 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; AtomicSlot() : SlotBase(kNullAddress) {} explicit AtomicSlot(Address address) : SlotBase(address) {} explicit AtomicSlot(ObjectSlot slot) : SlotBase(slot.address()) {} explicit AtomicSlot(MaybeObjectSlot slot) : SlotBase(slot.address()) {} Reference operator*() const { return Reference(reinterpret_cast(address())); } Reference operator[](difference_type i) const { return Reference(reinterpret_cast(address() + i * kTaggedSize)); } friend void swap(Reference lhs, Reference rhs) { lhs.swap(rhs); } friend difference_type operator-(AtomicSlot a, AtomicSlot b) { return static_cast(a.address() - b.address()) / kTaggedSize; } }; } // namespace internal } // namespace v8 #endif // V8_OBJECTS_SLOTS_ATOMIC_INL_H_