// 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_ #include "src/base/iterator.h" #include "src/base/macros.h" #include "src/heap/cppgc/globals.h" #include "src/heap/cppgc/heap-object-header.h" #include "src/heap/cppgc/object-start-bitmap.h" namespace cppgc { namespace internal { class BaseSpace; class NormalPageSpace; class LargePageSpace; class HeapBase; class PageBackend; class V8_EXPORT_PRIVATE BasePage { public: static inline BasePage* FromPayload(void*); static inline const BasePage* FromPayload(const void*); static BasePage* FromInnerAddress(const HeapBase*, void*); static const BasePage* FromInnerAddress(const HeapBase*, const void*); static void Destroy(BasePage*); BasePage(const BasePage&) = delete; BasePage& operator=(const BasePage&) = delete; HeapBase* heap() { return heap_; } const HeapBase* heap() const { return heap_; } 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; } Address PayloadStart(); ConstAddress PayloadStart() const; Address PayloadEnd(); ConstAddress PayloadEnd() const; // |address| must refer to real object. HeapObjectHeader& ObjectHeaderFromInnerAddress(void* address) const; 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; protected: enum class PageType { kNormal, kLarge }; BasePage(HeapBase*, BaseSpace*, PageType); private: HeapBase* heap_; BaseSpace* space_; PageType type_; }; class V8_EXPORT_PRIVATE NormalPage final : public BasePage { template class IteratorImpl : v8::base::iterator { public: 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(p_) == lab_start_) { p_ += (lab_size_ / sizeof(T)); } } 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++() { const size_t size = p_->GetSize(); DCHECK_EQ(0, (size & (sizeof(T) - 1))); p_ += (size / sizeof(T)); if (reinterpret_cast(p_) == lab_start_) { p_ += (lab_size_ / sizeof(T)); } return *this; } IteratorImpl operator++(int) { IteratorImpl temp(*this); ++(*this); return temp; } T* base() const { return p_; } private: T* p_; ConstAddress lab_start_; size_t lab_size_; }; public: using iterator = IteratorImpl; using const_iterator = IteratorImpl; // Allocates a new page in the detached state. static NormalPage* Create(PageBackend*, NormalPageSpace*); // Destroys and frees the page. The page must be detached from the // corresponding space (i.e. be swept when called). static void Destroy(NormalPage*); static NormalPage* From(BasePage* page) { DCHECK(!page->is_large()); return static_cast(page); } static const NormalPage* From(const BasePage* page) { return From(const_cast(page)); } iterator begin(); const_iterator begin() const; iterator end() { return iterator(reinterpret_cast(PayloadEnd())); } const_iterator end() const { return const_iterator( reinterpret_cast(PayloadEnd())); } Address PayloadStart(); ConstAddress PayloadStart() const; Address PayloadEnd(); ConstAddress PayloadEnd() const; static size_t PayloadSize(); bool PayloadContains(ConstAddress address) const { return (PayloadStart() <= address) && (address < PayloadEnd()); } ObjectStartBitmap& object_start_bitmap() { return object_start_bitmap_; } const ObjectStartBitmap& object_start_bitmap() const { return object_start_bitmap_; } private: NormalPage(HeapBase* heap, BaseSpace* space); ~NormalPage(); ObjectStartBitmap object_start_bitmap_; }; class V8_EXPORT_PRIVATE LargePage final : public BasePage { public: // Allocates a new page in the detached state. static LargePage* Create(PageBackend*, LargePageSpace*, size_t); // Destroys and frees the page. The page must be detached from the // corresponding space (i.e. be swept when called). static void Destroy(LargePage*); static LargePage* From(BasePage* page) { DCHECK(page->is_large()); return static_cast(page); } static const LargePage* From(const BasePage* page) { return From(const_cast(page)); } HeapObjectHeader* ObjectHeader(); const HeapObjectHeader* ObjectHeader() const; Address PayloadStart(); ConstAddress PayloadStart() const; Address PayloadEnd(); ConstAddress PayloadEnd() const; size_t PayloadSize() const { return payload_size_; } bool PayloadContains(ConstAddress address) const { return (PayloadStart() <= address) && (address < PayloadEnd()); } private: LargePage(HeapBase* heap, BaseSpace* space, size_t); ~LargePage(); size_t payload_size_; }; } // namespace internal } // namespace cppgc #endif // V8_HEAP_CPPGC_HEAP_PAGE_H_