slots.h 10.3 KB
Newer Older
1 2 3 4 5 6 7
// 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_H_
#define V8_OBJECTS_SLOTS_H_

8
#include "src/base/memory.h"
9
#include "src/common/globals.h"
10 11 12 13

namespace v8 {
namespace internal {

14
class Object;
15

16 17
template <typename Subclass, typename Data,
          size_t SlotDataAlignment = sizeof(Data)>
18 19
class SlotBase {
 public:
20
  using TData = Data;
21

22 23
  static constexpr size_t kSlotDataSize = sizeof(Data);
  static constexpr size_t kSlotDataAlignment = SlotDataAlignment;
24

25
  Subclass& operator++() {  // Prefix increment.
26
    ptr_ += kSlotDataSize;
27 28
    return *static_cast<Subclass*>(this);
  }
29 30
  Subclass operator++(int) {  // Postfix increment.
    Subclass result = *static_cast<Subclass*>(this);
31
    ptr_ += kSlotDataSize;
32 33 34
    return result;
  }
  Subclass& operator--() {  // Prefix decrement.
35
    ptr_ -= kSlotDataSize;
36 37 38 39
    return *static_cast<Subclass*>(this);
  }
  Subclass operator--(int) {  // Postfix decrement.
    Subclass result = *static_cast<Subclass*>(this);
40
    ptr_ -= kSlotDataSize;
41 42
    return result;
  }
43

44 45
  bool operator<(const SlotBase& other) const { return ptr_ < other.ptr_; }
  bool operator<=(const SlotBase& other) const { return ptr_ <= other.ptr_; }
46 47
  bool operator>(const SlotBase& other) const { return ptr_ > other.ptr_; }
  bool operator>=(const SlotBase& other) const { return ptr_ >= other.ptr_; }
48 49 50
  bool operator==(const SlotBase& other) const { return ptr_ == other.ptr_; }
  bool operator!=(const SlotBase& other) const { return ptr_ != other.ptr_; }
  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 55
  Subclass operator-(int i) const { return Subclass(ptr_ - i * kSlotDataSize); }
  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 62
    return *static_cast<Subclass*>(this);
  }
63
  Subclass operator-(int i) { return Subclass(ptr_ - i * kSlotDataSize); }
64
  Subclass& operator-=(int i) {
65
    ptr_ -= i * kSlotDataSize;
66 67
    return *static_cast<Subclass*>(this);
  }
68

69 70
  void* ToVoidPtr() const { return reinterpret_cast<void*>(address()); }

71
  Address address() const { return ptr_; }
72
  // For symmetry with Handle.
73
  TData* location() const { return reinterpret_cast<TData*>(ptr_); }
74 75 76

 protected:
  explicit SlotBase(Address ptr) : ptr_(ptr) {
77
    DCHECK(IsAligned(ptr, kSlotDataAlignment));
78 79 80 81 82 83 84 85 86
  }

 private:
  // This field usually describes an on-heap address (a slot within an object),
  // so its type should not be a pointer to another C++ wrapper class.
  // Type safety is provided by well-defined conversion operations.
  Address ptr_;
};

87 88
// An FullObjectSlot instance describes a kSystemPointerSize-sized field
// ("slot") holding a tagged pointer (smi or strong heap object).
89 90
// Its address() is the address of the slot.
// 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 100
  FullObjectSlot() : SlotBase(kNullAddress) {}
  explicit FullObjectSlot(Address ptr) : SlotBase(ptr) {}
101
  explicit FullObjectSlot(const Address* ptr)
102
      : 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 109 110
  // Compares memory representation of a value stored in the slot with given
  // raw value.
  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 117 118
  inline void store_map(Map map) const;

  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 125
  inline void Relaxed_Store(Object value) const;
  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 131
// A FullMaybeObjectSlot instance describes a kSystemPointerSize-sized field
// ("slot") holding a possibly-weak tagged pointer (think: MaybeObject).
132 133
// Its address() is the address of the slot.
// The slot's contents can be read and written using operator* and store().
134 135
class FullMaybeObjectSlot
    : 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

143 144
  FullMaybeObjectSlot() : SlotBase(kNullAddress) {}
  explicit FullMaybeObjectSlot(Address ptr) : SlotBase(ptr) {}
145
  explicit FullMaybeObjectSlot(Object* ptr)
146
      : SlotBase(reinterpret_cast<Address>(ptr)) {}
147 148
  explicit FullMaybeObjectSlot(MaybeObject* ptr)
      : SlotBase(reinterpret_cast<Address>(ptr)) {}
149
  template <typename T>
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 164
// A FullHeapObjectSlot instance describes a kSystemPointerSize-sized field
// ("slot") holding a weak or strong pointer to a heap object (think:
165
// HeapObjectReference).
166 167 168 169
// Its address() is the address of the slot.
// The slot's contents can be read and written using operator* and store().
// In case it is known that that slot contains a strong heap object pointer,
// ToHeapObject() can be used to retrieve that heap object.
170
class FullHeapObjectSlot : public SlotBase<FullHeapObjectSlot, Address> {
171
 public:
172 173
  FullHeapObjectSlot() : SlotBase(kNullAddress) {}
  explicit FullHeapObjectSlot(Address ptr) : SlotBase(ptr) {}
174
  explicit FullHeapObjectSlot(Object* ptr)
175
      : SlotBase(reinterpret_cast<Address>(ptr)) {}
176
  template <typename T>
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 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
// TODO(ishell, v8:8875): When pointer compression is enabled the [u]intptr_t
// and double fields are only kTaggedSize aligned so in order to avoid undefined
// behavior in C++ code we use this iterator adaptor when using STL algorithms
// with unaligned pointers.
// It will be removed once all v8:8875 is fixed and all the full pointer and
// double values in compressed V8 heap are properly aligned.
template <typename T>
class UnalignedSlot : public SlotBase<UnalignedSlot<T>, T, 1> {
 public:
  // This class is a stand-in for "T&" that uses custom read/write operations
  // for the actual memory accesses.
  class Reference {
   public:
    explicit Reference(Address address) : address_(address) {}
    Reference(const Reference&) V8_NOEXCEPT = default;

    Reference& operator=(const Reference& other) V8_NOEXCEPT {
206
      base::WriteUnalignedValue<T>(address_, other.value());
207 208 209
      return *this;
    }
    Reference& operator=(T value) {
210
      base::WriteUnalignedValue<T>(address_, value);
211 212 213 214 215 216 217 218 219
      return *this;
    }

    // Values of type UnalignedSlot::reference must be implicitly convertible
    // to UnalignedSlot::value_type.
    operator T() const { return value(); }

    void swap(Reference& other) {
      T tmp = value();
220 221
      base::WriteUnalignedValue<T>(address_, other.value());
      base::WriteUnalignedValue<T>(other.address_, tmp);
222 223 224 225 226 227 228 229 230 231 232
    }

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

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

   private:
233
    T value() const { return base::ReadUnalignedValue<T>(address_); }
234 235 236 237 238 239

    Address address_;
  };

  // The rest of this class follows C++'s "RandomAccessIterator" requirements.
  // Most of the heavy lifting is inherited from SlotBase.
240 241 242 243 244
  using difference_type = int;
  using value_type = T;
  using reference = Reference;
  using pointer = T*;
  using iterator_category = std::random_access_iterator_tag;
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266

  UnalignedSlot() : SlotBase<UnalignedSlot<T>, T, 1>(kNullAddress) {}
  explicit UnalignedSlot(Address address)
      : SlotBase<UnalignedSlot<T>, T, 1>(address) {}
  explicit UnalignedSlot(T* address)
      : SlotBase<UnalignedSlot<T>, T, 1>(reinterpret_cast<Address>(address)) {}

  Reference operator*() const {
    return Reference(SlotBase<UnalignedSlot<T>, T, 1>::address());
  }
  Reference operator[](difference_type i) const {
    return Reference(SlotBase<UnalignedSlot<T>, T, 1>::address() +
                     i * sizeof(T));
  }

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

  friend difference_type operator-(UnalignedSlot a, UnalignedSlot b) {
    return static_cast<int>(a.address() - b.address()) / sizeof(T);
  }
};

267 268 269 270 271
// An off-heap uncompressed object slot can be the same as an on-heap one, with
// a few methods deleted.
class OffHeapFullObjectSlot : public FullObjectSlot {
 public:
  OffHeapFullObjectSlot() : FullObjectSlot() {}
272
  explicit OffHeapFullObjectSlot(Address ptr) : FullObjectSlot(ptr) {}
273 274 275 276 277 278 279 280
  explicit OffHeapFullObjectSlot(const Address* ptr) : FullObjectSlot(ptr) {}

  inline Object operator*() const = delete;

  using FullObjectSlot::Relaxed_Load;
  inline Object Relaxed_Load() const = delete;
};

281 282 283 284
}  // namespace internal
}  // namespace v8

#endif  // V8_OBJECTS_SLOTS_H_