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_H_ 6 #define V8_OBJECTS_SLOTS_H_ 7 8 #include "src/base/memory.h" 9 #include "src/common/globals.h" 10 11 namespace v8 { 12 namespace internal { 13 14 class Object; 15 16 template <typename Subclass, typename Data, 17 size_t SlotDataAlignment = sizeof(Data)> 18 class SlotBase { 19 public: 20 using TData = Data; 21 22 static constexpr size_t kSlotDataSize = sizeof(Data); 23 static constexpr size_t kSlotDataAlignment = SlotDataAlignment; 24 25 Subclass& operator++() { // Prefix increment. 26 ptr_ += kSlotDataSize; 27 return *static_cast<Subclass*>(this); 28 } 29 Subclass operator++(int) { // Postfix increment. 30 Subclass result = *static_cast<Subclass*>(this); 31 ptr_ += kSlotDataSize; 32 return result; 33 } 34 Subclass& operator--() { // Prefix decrement. 35 ptr_ -= kSlotDataSize; 36 return *static_cast<Subclass*>(this); 37 } 38 Subclass operator--(int) { // Postfix decrement. 39 Subclass result = *static_cast<Subclass*>(this); 40 ptr_ -= kSlotDataSize; 41 return result; 42 } 43 44 bool operator<(const SlotBase& other) const { return ptr_ < other.ptr_; } 45 bool operator<=(const SlotBase& other) const { return ptr_ <= other.ptr_; } 46 bool operator>(const SlotBase& other) const { return ptr_ > other.ptr_; } 47 bool operator>=(const SlotBase& other) const { return ptr_ >= other.ptr_; } 48 bool operator==(const SlotBase& other) const { return ptr_ == other.ptr_; } 49 bool operator!=(const SlotBase& other) const { return ptr_ != other.ptr_; } 50 size_t operator-(const SlotBase& other) const { 51 DCHECK_GE(ptr_, other.ptr_); 52 return static_cast<size_t>((ptr_ - other.ptr_) / kSlotDataSize); 53 } 54 Subclass operator-(int i) const { return Subclass(ptr_ - i * kSlotDataSize); } 55 Subclass operator+(int i) const { return Subclass(ptr_ + i * kSlotDataSize); } 56 friend Subclass operator+(int i, const Subclass& slot) { 57 return Subclass(slot.ptr_ + i * kSlotDataSize); 58 } 59 Subclass& operator+=(int i) { 60 ptr_ += i * kSlotDataSize; 61 return *static_cast<Subclass*>(this); 62 } 63 Subclass operator-(int i) { return Subclass(ptr_ - i * kSlotDataSize); } 64 Subclass& operator-=(int i) { 65 ptr_ -= i * kSlotDataSize; 66 return *static_cast<Subclass*>(this); 67 } 68 ToVoidPtr()69 void* ToVoidPtr() const { return reinterpret_cast<void*>(address()); } 70 address()71 Address address() const { return ptr_; } 72 // For symmetry with Handle. location()73 TData* location() const { return reinterpret_cast<TData*>(ptr_); } 74 75 protected: SlotBase(Address ptr)76 explicit SlotBase(Address ptr) : ptr_(ptr) { 77 DCHECK(IsAligned(ptr, kSlotDataAlignment)); 78 } 79 80 private: 81 // This field usually describes an on-heap address (a slot within an object), 82 // so its type should not be a pointer to another C++ wrapper class. 83 // Type safety is provided by well-defined conversion operations. 84 Address ptr_; 85 }; 86 87 // An FullObjectSlot instance describes a kSystemPointerSize-sized field 88 // ("slot") holding a tagged pointer (smi or strong heap object). 89 // Its address() is the address of the slot. 90 // The slot's contents can be read and written using operator* and store(). 91 class FullObjectSlot : public SlotBase<FullObjectSlot, Address> { 92 public: 93 using TObject = Object; 94 using THeapObjectSlot = FullHeapObjectSlot; 95 96 // Tagged value stored in this slot is guaranteed to never be a weak pointer. 97 static constexpr bool kCanBeWeak = false; 98 FullObjectSlot()99 FullObjectSlot() : SlotBase(kNullAddress) {} FullObjectSlot(Address ptr)100 explicit FullObjectSlot(Address ptr) : SlotBase(ptr) {} FullObjectSlot(const Address * ptr)101 explicit FullObjectSlot(const Address* ptr) 102 : SlotBase(reinterpret_cast<Address>(ptr)) {} 103 inline explicit FullObjectSlot(Object* object); 104 template <typename T> FullObjectSlot(SlotBase<T,TData,kSlotDataAlignment> slot)105 explicit FullObjectSlot(SlotBase<T, TData, kSlotDataAlignment> slot) 106 : SlotBase(slot.address()) {} 107 108 // Compares memory representation of a value stored in the slot with given 109 // raw value. 110 inline bool contains_value(Address raw_value) const; 111 inline bool contains_map_value(Address raw_value) const; 112 113 inline Object operator*() const; 114 inline Object load(PtrComprCageBase cage_base) const; 115 inline void store(Object value) const; 116 inline void store_map(Map map) const; 117 118 inline Map load_map() const; 119 120 inline Object Acquire_Load() const; 121 inline Object Acquire_Load(PtrComprCageBase cage_base) const; 122 inline Object Relaxed_Load() const; 123 inline Object Relaxed_Load(PtrComprCageBase cage_base) const; 124 inline void Relaxed_Store(Object value) const; 125 inline void Release_Store(Object value) const; 126 inline Object Relaxed_CompareAndSwap(Object old, Object target) const; 127 inline Object Release_CompareAndSwap(Object old, Object target) const; 128 }; 129 130 // A FullMaybeObjectSlot instance describes a kSystemPointerSize-sized field 131 // ("slot") holding a possibly-weak tagged pointer (think: MaybeObject). 132 // Its address() is the address of the slot. 133 // The slot's contents can be read and written using operator* and store(). 134 class FullMaybeObjectSlot 135 : public SlotBase<FullMaybeObjectSlot, Address, kSystemPointerSize> { 136 public: 137 using TObject = MaybeObject; 138 using THeapObjectSlot = FullHeapObjectSlot; 139 140 // Tagged value stored in this slot can be a weak pointer. 141 static constexpr bool kCanBeWeak = true; 142 FullMaybeObjectSlot()143 FullMaybeObjectSlot() : SlotBase(kNullAddress) {} FullMaybeObjectSlot(Address ptr)144 explicit FullMaybeObjectSlot(Address ptr) : SlotBase(ptr) {} FullMaybeObjectSlot(Object * ptr)145 explicit FullMaybeObjectSlot(Object* ptr) 146 : SlotBase(reinterpret_cast<Address>(ptr)) {} FullMaybeObjectSlot(MaybeObject * ptr)147 explicit FullMaybeObjectSlot(MaybeObject* ptr) 148 : SlotBase(reinterpret_cast<Address>(ptr)) {} 149 template <typename T> FullMaybeObjectSlot(SlotBase<T,TData,kSlotDataAlignment> slot)150 explicit FullMaybeObjectSlot(SlotBase<T, TData, kSlotDataAlignment> slot) 151 : SlotBase(slot.address()) {} 152 153 inline MaybeObject operator*() const; 154 inline MaybeObject load(PtrComprCageBase cage_base) const; 155 inline void store(MaybeObject value) const; 156 157 inline MaybeObject Relaxed_Load() const; 158 inline MaybeObject Relaxed_Load(PtrComprCageBase cage_base) const; 159 inline void Relaxed_Store(MaybeObject value) const; 160 inline void Release_CompareAndSwap(MaybeObject old, MaybeObject target) const; 161 }; 162 163 // A FullHeapObjectSlot instance describes a kSystemPointerSize-sized field 164 // ("slot") holding a weak or strong pointer to a heap object (think: 165 // HeapObjectReference). 166 // Its address() is the address of the slot. 167 // The slot's contents can be read and written using operator* and store(). 168 // In case it is known that that slot contains a strong heap object pointer, 169 // ToHeapObject() can be used to retrieve that heap object. 170 class FullHeapObjectSlot : public SlotBase<FullHeapObjectSlot, Address> { 171 public: FullHeapObjectSlot()172 FullHeapObjectSlot() : SlotBase(kNullAddress) {} FullHeapObjectSlot(Address ptr)173 explicit FullHeapObjectSlot(Address ptr) : SlotBase(ptr) {} FullHeapObjectSlot(Object * ptr)174 explicit FullHeapObjectSlot(Object* ptr) 175 : SlotBase(reinterpret_cast<Address>(ptr)) {} 176 template <typename T> FullHeapObjectSlot(SlotBase<T,TData,kSlotDataAlignment> slot)177 explicit FullHeapObjectSlot(SlotBase<T, TData, kSlotDataAlignment> slot) 178 : SlotBase(slot.address()) {} 179 180 inline HeapObjectReference operator*() const; 181 inline HeapObjectReference load(PtrComprCageBase cage_base) const; 182 inline void store(HeapObjectReference value) const; 183 184 inline HeapObject ToHeapObject() const; 185 186 inline void StoreHeapObject(HeapObject value) const; 187 }; 188 189 // TODO(ishell, v8:8875): When pointer compression is enabled the [u]intptr_t 190 // and double fields are only kTaggedSize aligned so in order to avoid undefined 191 // behavior in C++ code we use this iterator adaptor when using STL algorithms 192 // with unaligned pointers. 193 // It will be removed once all v8:8875 is fixed and all the full pointer and 194 // double values in compressed V8 heap are properly aligned. 195 template <typename T> 196 class UnalignedSlot : public SlotBase<UnalignedSlot<T>, T, 1> { 197 public: 198 // This class is a stand-in for "T&" that uses custom read/write operations 199 // for the actual memory accesses. 200 class Reference { 201 public: Reference(Address address)202 explicit Reference(Address address) : address_(address) {} 203 Reference(const Reference&) V8_NOEXCEPT = default; 204 205 Reference& operator=(const Reference& other) V8_NOEXCEPT { 206 base::WriteUnalignedValue<T>(address_, other.value()); 207 return *this; 208 } 209 Reference& operator=(T value) { 210 base::WriteUnalignedValue<T>(address_, value); 211 return *this; 212 } 213 214 // Values of type UnalignedSlot::reference must be implicitly convertible 215 // to UnalignedSlot::value_type. T()216 operator T() const { return value(); } 217 swap(Reference & other)218 void swap(Reference& other) { 219 T tmp = value(); 220 base::WriteUnalignedValue<T>(address_, other.value()); 221 base::WriteUnalignedValue<T>(other.address_, tmp); 222 } 223 224 bool operator<(const Reference& other) const { 225 return value() < other.value(); 226 } 227 228 bool operator==(const Reference& other) const { 229 return value() == other.value(); 230 } 231 232 private: value()233 T value() const { return base::ReadUnalignedValue<T>(address_); } 234 235 Address address_; 236 }; 237 238 // The rest of this class follows C++'s "RandomAccessIterator" requirements. 239 // Most of the heavy lifting is inherited from SlotBase. 240 using difference_type = int; 241 using value_type = T; 242 using reference = Reference; 243 using pointer = T*; 244 using iterator_category = std::random_access_iterator_tag; 245 UnalignedSlot()246 UnalignedSlot() : SlotBase<UnalignedSlot<T>, T, 1>(kNullAddress) {} UnalignedSlot(Address address)247 explicit UnalignedSlot(Address address) 248 : SlotBase<UnalignedSlot<T>, T, 1>(address) {} UnalignedSlot(T * address)249 explicit UnalignedSlot(T* address) 250 : SlotBase<UnalignedSlot<T>, T, 1>(reinterpret_cast<Address>(address)) {} 251 252 Reference operator*() const { 253 return Reference(SlotBase<UnalignedSlot<T>, T, 1>::address()); 254 } 255 Reference operator[](difference_type i) const { 256 return Reference(SlotBase<UnalignedSlot<T>, T, 1>::address() + 257 i * sizeof(T)); 258 } 259 swap(Reference lhs,Reference rhs)260 friend void swap(Reference lhs, Reference rhs) { lhs.swap(rhs); } 261 262 friend difference_type operator-(UnalignedSlot a, UnalignedSlot b) { 263 return static_cast<int>(a.address() - b.address()) / sizeof(T); 264 } 265 }; 266 267 // An off-heap uncompressed object slot can be the same as an on-heap one, with 268 // a few methods deleted. 269 class OffHeapFullObjectSlot : public FullObjectSlot { 270 public: OffHeapFullObjectSlot()271 OffHeapFullObjectSlot() : FullObjectSlot() {} OffHeapFullObjectSlot(Address ptr)272 explicit OffHeapFullObjectSlot(Address ptr) : FullObjectSlot(ptr) {} OffHeapFullObjectSlot(const Address * ptr)273 explicit OffHeapFullObjectSlot(const Address* ptr) : FullObjectSlot(ptr) {} 274 275 inline Object operator*() const = delete; 276 277 using FullObjectSlot::Relaxed_Load; 278 inline Object Relaxed_Load() const = delete; 279 }; 280 281 } // namespace internal 282 } // namespace v8 283 284 #endif // V8_OBJECTS_SLOTS_H_ 285