slots.h 9.25 KB
Newer Older
1 2 3 4 5 6 7 8
// 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_

#include "src/globals.h"
9
#include "src/v8memory.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 111
  // Compares memory representation of a value stored in the slot with given
  // raw value.
  inline bool contains_value(Address raw_value) const;

112
  inline const Object operator*() const;
113
  inline void store(Object value) const;
114

115 116 117 118 119
  inline Object Acquire_Load() const;
  inline Object Relaxed_Load() const;
  inline void Relaxed_Store(Object value) const;
  inline void Release_Store(Object value) const;
  inline Object Release_CompareAndSwap(Object old, Object target) const;
120 121
};

122 123
// A FullMaybeObjectSlot instance describes a kSystemPointerSize-sized field
// ("slot") holding a possibly-weak tagged pointer (think: MaybeObject).
124 125
// Its address() is the address of the slot.
// The slot's contents can be read and written using operator* and store().
126 127
class FullMaybeObjectSlot
    : 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 136
  FullMaybeObjectSlot() : SlotBase(kNullAddress) {}
  explicit FullMaybeObjectSlot(Address ptr) : SlotBase(ptr) {}
137
  explicit FullMaybeObjectSlot(Object* ptr)
138
      : SlotBase(reinterpret_cast<Address>(ptr)) {}
139 140
  explicit FullMaybeObjectSlot(MaybeObject* ptr)
      : 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 154
// A FullHeapObjectSlot instance describes a kSystemPointerSize-sized field
// ("slot") holding a weak or strong pointer to a heap object (think:
155
// HeapObjectReference).
156 157 158 159
// 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.
160
class FullHeapObjectSlot : public SlotBase<FullHeapObjectSlot, Address> {
161
 public:
162 163
  FullHeapObjectSlot() : SlotBase(kNullAddress) {}
  explicit FullHeapObjectSlot(Address ptr) : SlotBase(ptr) {}
164
  explicit FullHeapObjectSlot(Object* ptr)
165
      : SlotBase(reinterpret_cast<Address>(ptr)) {}
166
  template <typename T>
167
  explicit FullHeapObjectSlot(SlotBase<T, TData, kSlotDataAlignment> slot)
168
      : 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 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
// 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 {
      WriteUnalignedValue<T>(address_, other.value());
      return *this;
    }
    Reference& operator=(T value) {
      WriteUnalignedValue<T>(address_, value);
      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();
      WriteUnalignedValue<T>(address_, other.value());
      WriteUnalignedValue<T>(other.address_, tmp);
    }

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

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

   private:
    T value() const { return ReadUnalignedValue<T>(address_); }

    Address address_;
  };

  // The rest of this class follows C++'s "RandomAccessIterator" requirements.
  // Most of the heavy lifting is inherited from SlotBase.
229 230 231 232 233
  using difference_type = int;
  using value_type = T;
  using reference = Reference;
  using pointer = T*;
  using iterator_category = std::random_access_iterator_tag;
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255

  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);
  }
};

256 257 258 259
}  // namespace internal
}  // namespace v8

#endif  // V8_OBJECTS_SLOTS_H_