Line data Source code
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/globals.h"
9 : #include "src/v8memory.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 399619004 : Subclass& operator++() { // Prefix increment.
26 9755662632 : ptr_ += kSlotDataSize;
27 399619004 : return *static_cast<Subclass*>(this);
28 : }
29 : Subclass operator++(int) { // Postfix increment.
30 : Subclass result = *static_cast<Subclass*>(this);
31 2309910 : ptr_ += kSlotDataSize;
32 : return result;
33 : }
34 : Subclass& operator--() { // Prefix decrement.
35 318116808 : 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 4581826351 : bool operator<(const SlotBase& other) const { return ptr_ < other.ptr_; }
45 13468208 : 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 7282168 : bool operator==(const SlotBase& other) const { return ptr_ == other.ptr_; }
49 522268 : 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 22815363 : return static_cast<size_t>((ptr_ - other.ptr_) / kSlotDataSize);
53 : }
54 : Subclass operator-(int i) const { return Subclass(ptr_ - i * kSlotDataSize); }
55 3378032836 : 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 489524615 : ptr_ += i * kSlotDataSize;
61 : return *static_cast<Subclass*>(this);
62 : }
63 1400848 : 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 :
69 495333487 : void* ToVoidPtr() const { return reinterpret_cast<void*>(address()); }
70 :
71 2149703936 : Address address() const { return ptr_; }
72 : // For symmetry with Handle.
73 66238413463 : TData* location() const { return reinterpret_cast<TData*>(ptr_); }
74 :
75 : protected:
76 5477029928 : explicit SlotBase(Address ptr) : ptr_(ptr) {
77 : DCHECK(IsAligned(ptr, kSlotDataAlignment));
78 1155115 : }
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 :
99 : FullObjectSlot() : SlotBase(kNullAddress) {}
100 347353372 : explicit FullObjectSlot(Address ptr) : SlotBase(ptr) {}
101 : explicit FullObjectSlot(const Address* ptr)
102 68594020 : : SlotBase(reinterpret_cast<Address>(ptr)) {}
103 : inline explicit FullObjectSlot(Object* object);
104 : template <typename T>
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 :
112 : inline const Object operator*() const;
113 : inline void store(Object value) const;
114 :
115 : inline Object Acquire_Load() const;
116 : inline Object Relaxed_Load() const;
117 : inline void Relaxed_Store(Object value) const;
118 : inline void Release_Store(Object value) const;
119 : inline Object Release_CompareAndSwap(Object old, Object target) const;
120 : };
121 :
122 : // A FullMaybeObjectSlot instance describes a kSystemPointerSize-sized field
123 : // ("slot") holding a possibly-weak tagged pointer (think: MaybeObject).
124 : // Its address() is the address of the slot.
125 : // The slot's contents can be read and written using operator* and store().
126 : class FullMaybeObjectSlot
127 : : public SlotBase<FullMaybeObjectSlot, Address, kSystemPointerSize> {
128 : public:
129 : using TObject = MaybeObject;
130 : using THeapObjectSlot = FullHeapObjectSlot;
131 :
132 : // Tagged value stored in this slot can be a weak pointer.
133 : static constexpr bool kCanBeWeak = true;
134 :
135 : FullMaybeObjectSlot() : SlotBase(kNullAddress) {}
136 : explicit FullMaybeObjectSlot(Address ptr) : SlotBase(ptr) {}
137 : explicit FullMaybeObjectSlot(Object* ptr)
138 389672 : : SlotBase(reinterpret_cast<Address>(ptr)) {}
139 : explicit FullMaybeObjectSlot(MaybeObject* ptr)
140 175945290 : : SlotBase(reinterpret_cast<Address>(ptr)) {}
141 : template <typename T>
142 : explicit FullMaybeObjectSlot(SlotBase<T, TData, kSlotDataAlignment> slot)
143 : : SlotBase(slot.address()) {}
144 :
145 : inline const MaybeObject operator*() const;
146 : inline void store(MaybeObject value) const;
147 :
148 : inline MaybeObject Relaxed_Load() const;
149 : inline void Relaxed_Store(MaybeObject value) const;
150 : inline void Release_CompareAndSwap(MaybeObject old, MaybeObject target) const;
151 : };
152 :
153 : // A FullHeapObjectSlot instance describes a kSystemPointerSize-sized field
154 : // ("slot") holding a weak or strong pointer to a heap object (think:
155 : // HeapObjectReference).
156 : // Its address() is the address of the slot.
157 : // The slot's contents can be read and written using operator* and store().
158 : // In case it is known that that slot contains a strong heap object pointer,
159 : // ToHeapObject() can be used to retrieve that heap object.
160 : class FullHeapObjectSlot : public SlotBase<FullHeapObjectSlot, Address> {
161 : public:
162 : FullHeapObjectSlot() : SlotBase(kNullAddress) {}
163 : explicit FullHeapObjectSlot(Address ptr) : SlotBase(ptr) {}
164 0 : explicit FullHeapObjectSlot(Object* ptr)
165 0 : : SlotBase(reinterpret_cast<Address>(ptr)) {}
166 : template <typename T>
167 5701012 : explicit FullHeapObjectSlot(SlotBase<T, TData, kSlotDataAlignment> slot)
168 5701012 : : SlotBase(slot.address()) {}
169 :
170 : inline const HeapObjectReference operator*() const;
171 : inline void store(HeapObjectReference value) const;
172 :
173 : inline HeapObject ToHeapObject() const;
174 :
175 : inline void StoreHeapObject(HeapObject value) const;
176 : };
177 :
178 : // TODO(ishell, v8:8875): When pointer compression is enabled the [u]intptr_t
179 : // and double fields are only kTaggedSize aligned so in order to avoid undefined
180 : // behavior in C++ code we use this iterator adaptor when using STL algorithms
181 : // with unaligned pointers.
182 : // It will be removed once all v8:8875 is fixed and all the full pointer and
183 : // double values in compressed V8 heap are properly aligned.
184 : template <typename T>
185 : class UnalignedSlot : public SlotBase<UnalignedSlot<T>, T, 1> {
186 : public:
187 : // This class is a stand-in for "T&" that uses custom read/write operations
188 : // for the actual memory accesses.
189 : class Reference {
190 : public:
191 : explicit Reference(Address address) : address_(address) {}
192 : Reference(const Reference&) V8_NOEXCEPT = default;
193 :
194 : Reference& operator=(const Reference& other) V8_NOEXCEPT {
195 : WriteUnalignedValue<T>(address_, other.value());
196 : return *this;
197 : }
198 : Reference& operator=(T value) {
199 : WriteUnalignedValue<T>(address_, value);
200 : return *this;
201 : }
202 :
203 : // Values of type UnalignedSlot::reference must be implicitly convertible
204 : // to UnalignedSlot::value_type.
205 : operator T() const { return value(); }
206 :
207 : void swap(Reference& other) {
208 : T tmp = value();
209 : WriteUnalignedValue<T>(address_, other.value());
210 : WriteUnalignedValue<T>(other.address_, tmp);
211 : }
212 :
213 : bool operator<(const Reference& other) const {
214 : return value() < other.value();
215 : }
216 :
217 : bool operator==(const Reference& other) const {
218 : return value() == other.value();
219 : }
220 :
221 : private:
222 : T value() const { return ReadUnalignedValue<T>(address_); }
223 :
224 : Address address_;
225 : };
226 :
227 : // The rest of this class follows C++'s "RandomAccessIterator" requirements.
228 : // Most of the heavy lifting is inherited from SlotBase.
229 : using difference_type = int;
230 : using value_type = T;
231 : using reference = Reference;
232 : using pointer = T*;
233 : using iterator_category = std::random_access_iterator_tag;
234 :
235 : UnalignedSlot() : SlotBase<UnalignedSlot<T>, T, 1>(kNullAddress) {}
236 : explicit UnalignedSlot(Address address)
237 : : SlotBase<UnalignedSlot<T>, T, 1>(address) {}
238 : explicit UnalignedSlot(T* address)
239 : : SlotBase<UnalignedSlot<T>, T, 1>(reinterpret_cast<Address>(address)) {}
240 :
241 : Reference operator*() const {
242 : return Reference(SlotBase<UnalignedSlot<T>, T, 1>::address());
243 : }
244 : Reference operator[](difference_type i) const {
245 : return Reference(SlotBase<UnalignedSlot<T>, T, 1>::address() +
246 : i * sizeof(T));
247 : }
248 :
249 : friend void swap(Reference lhs, Reference rhs) { lhs.swap(rhs); }
250 :
251 : friend difference_type operator-(UnalignedSlot a, UnalignedSlot b) {
252 : return static_cast<int>(a.address() - b.address()) / sizeof(T);
253 : }
254 : };
255 :
256 : } // namespace internal
257 : } // namespace v8
258 :
259 : #endif // V8_OBJECTS_SLOTS_H_
|