heap-page.h 7.74 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2020 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_HEAP_CPPGC_HEAP_PAGE_H_
#define V8_HEAP_CPPGC_HEAP_PAGE_H_

8
#include "src/base/iterator.h"
9
#include "src/base/macros.h"
10
#include "src/heap/cppgc/globals.h"
11
#include "src/heap/cppgc/heap-object-header.h"
12
#include "src/heap/cppgc/object-start-bitmap.h"
13 14 15 16

namespace cppgc {
namespace internal {

17 18 19
class BaseSpace;
class NormalPageSpace;
class LargePageSpace;
20
class HeapBase;
21 22
class PageBackend;

23 24
class V8_EXPORT_PRIVATE BasePage {
 public:
25 26
  static inline BasePage* FromPayload(void*);
  static inline const BasePage* FromPayload(const void*);
27

28 29
  static BasePage* FromInnerAddress(const HeapBase*, void*);
  static const BasePage* FromInnerAddress(const HeapBase*, const void*);
30

31 32
  static void Destroy(BasePage*);

33 34 35
  BasePage(const BasePage&) = delete;
  BasePage& operator=(const BasePage&) = delete;

36 37
  HeapBase* heap() { return heap_; }
  const HeapBase* heap() const { return heap_; }
38 39 40 41 42 43

  BaseSpace* space() { return space_; }
  const BaseSpace* space() const { return space_; }
  void set_space(BaseSpace* space) { space_ = space; }

  bool is_large() const { return type_ == PageType::kLarge; }
44

45 46 47 48 49
  Address PayloadStart();
  ConstAddress PayloadStart() const;
  Address PayloadEnd();
  ConstAddress PayloadEnd() const;

50
  // |address| must refer to real object.
51 52
  template <
      HeapObjectHeader::AccessMode = HeapObjectHeader::AccessMode::kNonAtomic>
53
  HeapObjectHeader& ObjectHeaderFromInnerAddress(void* address) const;
54 55
  template <
      HeapObjectHeader::AccessMode = HeapObjectHeader::AccessMode::kNonAtomic>
56 57 58 59 60 61 62 63 64
  const HeapObjectHeader& ObjectHeaderFromInnerAddress(
      const void* address) const;

  // |address| is guaranteed to point into the page but not payload. Returns
  // nullptr when pointing into free list entries and the valid header
  // otherwise.
  HeapObjectHeader* TryObjectHeaderFromInnerAddress(void* address) const;
  const HeapObjectHeader* TryObjectHeaderFromInnerAddress(
      const void* address) const;
65

66
 protected:
67
  enum class PageType { kNormal, kLarge };
68
  BasePage(HeapBase*, BaseSpace*, PageType);
69

70
 private:
71
  HeapBase* heap_;
72 73
  BaseSpace* space_;
  PageType type_;
74 75 76
};

class V8_EXPORT_PRIVATE NormalPage final : public BasePage {
77 78 79
  template <typename T>
  class IteratorImpl : v8::base::iterator<std::forward_iterator_tag, T> {
   public:
80 81 82 83 84 85 86 87 88
    explicit IteratorImpl(T* p, ConstAddress lab_start = nullptr,
                          size_t lab_size = 0)
        : p_(p), lab_start_(lab_start), lab_size_(lab_size) {
      DCHECK(p);
      DCHECK_EQ(0, (lab_size & (sizeof(T) - 1)));
      if (reinterpret_cast<ConstAddress>(p_) == lab_start_) {
        p_ += (lab_size_ / sizeof(T));
      }
    }
89 90 91 92 93 94 95 96

    T& operator*() { return *p_; }
    const T& operator*() const { return *p_; }

    bool operator==(IteratorImpl other) const { return p_ == other.p_; }
    bool operator!=(IteratorImpl other) const { return !(*this == other); }

    IteratorImpl& operator++() {
97 98 99 100 101 102
      const size_t size = p_->GetSize();
      DCHECK_EQ(0, (size & (sizeof(T) - 1)));
      p_ += (size / sizeof(T));
      if (reinterpret_cast<ConstAddress>(p_) == lab_start_) {
        p_ += (lab_size_ / sizeof(T));
      }
103 104 105 106
      return *this;
    }
    IteratorImpl operator++(int) {
      IteratorImpl temp(*this);
107
      ++(*this);
108 109 110
      return temp;
    }

111
    T* base() const { return p_; }
112 113 114

   private:
    T* p_;
115 116
    ConstAddress lab_start_;
    size_t lab_size_;
117 118
  };

119
 public:
120 121 122
  using iterator = IteratorImpl<HeapObjectHeader>;
  using const_iterator = IteratorImpl<const HeapObjectHeader>;

123 124
  // Allocates a new page in the detached state.
  static NormalPage* Create(PageBackend*, NormalPageSpace*);
125 126
  // Destroys and frees the page. The page must be detached from the
  // corresponding space (i.e. be swept when called).
127 128
  static void Destroy(NormalPage*);

129 130 131
  static NormalPage* From(BasePage* page) {
    DCHECK(!page->is_large());
    return static_cast<NormalPage*>(page);
132
  }
133 134
  static const NormalPage* From(const BasePage* page) {
    return From(const_cast<BasePage*>(page));
135
  }
136 137 138 139

  iterator begin();
  const_iterator begin() const;

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
  iterator end() {
    return iterator(reinterpret_cast<HeapObjectHeader*>(PayloadEnd()));
  }
  const_iterator end() const {
    return const_iterator(
        reinterpret_cast<const HeapObjectHeader*>(PayloadEnd()));
  }

  Address PayloadStart();
  ConstAddress PayloadStart() const;
  Address PayloadEnd();
  ConstAddress PayloadEnd() const;

  static size_t PayloadSize();

155 156 157 158
  bool PayloadContains(ConstAddress address) const {
    return (PayloadStart() <= address) && (address < PayloadEnd());
  }

159 160 161 162
  PlatformAwareObjectStartBitmap& object_start_bitmap() {
    return object_start_bitmap_;
  }
  const PlatformAwareObjectStartBitmap& object_start_bitmap() const {
163 164 165
    return object_start_bitmap_;
  }

166
 private:
167
  NormalPage(HeapBase* heap, BaseSpace* space);
168
  ~NormalPage();
169

170
  PlatformAwareObjectStartBitmap object_start_bitmap_;
171 172 173 174
};

class V8_EXPORT_PRIVATE LargePage final : public BasePage {
 public:
175 176
  // Allocates a new page in the detached state.
  static LargePage* Create(PageBackend*, LargePageSpace*, size_t);
177 178 179 180
  // Destroys and frees the page. The page must be detached from the
  // corresponding space (i.e. be swept when called).
  static void Destroy(LargePage*);

181 182 183 184 185 186 187 188
  static LargePage* From(BasePage* page) {
    DCHECK(page->is_large());
    return static_cast<LargePage*>(page);
  }
  static const LargePage* From(const BasePage* page) {
    return From(const_cast<BasePage*>(page));
  }

189 190 191 192 193 194 195 196 197
  HeapObjectHeader* ObjectHeader();
  const HeapObjectHeader* ObjectHeader() const;

  Address PayloadStart();
  ConstAddress PayloadStart() const;
  Address PayloadEnd();
  ConstAddress PayloadEnd() const;

  size_t PayloadSize() const { return payload_size_; }
198

199 200 201 202
  bool PayloadContains(ConstAddress address) const {
    return (PayloadStart() <= address) && (address < PayloadEnd());
  }

203
 private:
204
  LargePage(HeapBase* heap, BaseSpace* space, size_t);
205
  ~LargePage();
206

207
  size_t payload_size_;
208 209
};

210 211 212 213 214 215 216 217 218 219 220 221 222 223
// static
BasePage* BasePage::FromPayload(void* payload) {
  return reinterpret_cast<BasePage*>(
      (reinterpret_cast<uintptr_t>(payload) & kPageBaseMask) + kGuardPageSize);
}

// static
const BasePage* BasePage::FromPayload(const void* payload) {
  return reinterpret_cast<const BasePage*>(
      (reinterpret_cast<uintptr_t>(const_cast<void*>(payload)) &
       kPageBaseMask) +
      kGuardPageSize);
}

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
template <HeapObjectHeader::AccessMode mode =
              HeapObjectHeader::AccessMode::kNonAtomic>
const HeapObjectHeader* ObjectHeaderFromInnerAddressImpl(const BasePage* page,
                                                         const void* address) {
  if (page->is_large()) {
    return LargePage::From(page)->ObjectHeader();
  }
  const PlatformAwareObjectStartBitmap& bitmap =
      NormalPage::From(page)->object_start_bitmap();
  const HeapObjectHeader* header =
      bitmap.FindHeader<mode>(static_cast<ConstAddress>(address));
  DCHECK_LT(address,
            reinterpret_cast<ConstAddress>(header) +
                header->GetSize<HeapObjectHeader::AccessMode::kAtomic>());
  return header;
}

template <HeapObjectHeader::AccessMode mode>
HeapObjectHeader& BasePage::ObjectHeaderFromInnerAddress(void* address) const {
  return const_cast<HeapObjectHeader&>(
      ObjectHeaderFromInnerAddress<mode>(const_cast<const void*>(address)));
}

template <HeapObjectHeader::AccessMode mode>
const HeapObjectHeader& BasePage::ObjectHeaderFromInnerAddress(
    const void* address) const {
  const HeapObjectHeader* header =
      ObjectHeaderFromInnerAddressImpl<mode>(this, address);
  DCHECK_NE(kFreeListGCInfoIndex, header->GetGCInfoIndex());
  return *header;
}

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

#endif  // V8_HEAP_CPPGC_HEAP_PAGE_H_