/* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #include #include #include #include namespace ams::kern { template class KSlabAllocated { private: static constinit inline KSlabHeap s_slab_heap; public: constexpr KSlabAllocated() = default; size_t GetSlabIndex() const { return s_slab_heap.GetIndex(static_cast(this)); } public: static void InitializeSlabHeap(void *memory, size_t memory_size) { s_slab_heap.Initialize(memory, memory_size); } static Derived *Allocate() { return s_slab_heap.Allocate(); } static void Free(Derived *obj) { s_slab_heap.Free(obj); } template::type> static Derived *AllocateFromUnusedSlabMemory() { static_assert(Enable == SupportDynamicExpansion); Derived * const obj = GetPointer(AllocateUnusedSlabMemory(sizeof(Derived), alignof(Derived))); if (AMS_LIKELY(obj != nullptr)) { std::construct_at(obj); } return obj; } static size_t GetObjectSize() { return s_slab_heap.GetObjectSize(); } static size_t GetSlabHeapSize() { return s_slab_heap.GetSlabHeapSize(); } static size_t GetPeakIndex() { return s_slab_heap.GetPeakIndex(); } static uintptr_t GetSlabHeapAddress() { return s_slab_heap.GetSlabHeapAddress(); } static size_t GetNumRemaining() { return s_slab_heap.GetNumRemaining(); } }; template requires std::derived_from class KAutoObjectWithSlabHeapBase : public Base { private: template friend class KAutoObjectWithSlabHeap; template friend class KAutoObjectWithSlabHeapAndContainer; private: static constinit inline KSlabHeap s_slab_heap; private: static ALWAYS_INLINE Derived *Allocate() { return s_slab_heap.Allocate(); } static ALWAYS_INLINE void Free(Derived *obj) { s_slab_heap.Free(obj); } private: static ALWAYS_INLINE bool IsInitialized(const Derived *obj) { if constexpr (requires { { obj->IsInitialized() } -> std::same_as; }) { return obj->IsInitialized(); } else { return true; } } static ALWAYS_INLINE uintptr_t GetPostDestroyArgument(const Derived *obj) { if constexpr (requires { { obj->GetPostDestroyArgument() } -> std::same_as; }) { return obj->GetPostDestroyArgument(); } else { return 0; } } public: constexpr explicit KAutoObjectWithSlabHeapBase(util::ConstantInitializeTag) : Base(util::ConstantInitialize) { /* ... */ } explicit KAutoObjectWithSlabHeapBase() { /* ... */ } /* NOTE: IsInitialized() and GetPostDestroyArgument() are virtual functions declared in this class, */ /* in Nintendo's kernel. We fully devirtualize them, as Destroy() is the only user of them. */ /* We also devirtualize KAutoObject::Finalize(), which is only used by this function in Nintendo's kernel. */ virtual void Destroy() override final { Derived * const derived = static_cast(this); if (KAutoObjectWithSlabHeapBase::IsInitialized(derived)) { Derived::PreFinalize(derived); const uintptr_t arg = KAutoObjectWithSlabHeapBase::GetPostDestroyArgument(derived); derived->Finalize(); KAutoObjectWithSlabHeapBase::Free(derived); Derived::PostDestroy(arg); } else { KAutoObjectWithSlabHeapBase::Free(derived); } } size_t GetSlabIndex() const { return s_slab_heap.GetObjectIndex(static_cast(this)); } public: static void InitializeSlabHeap(void *memory, size_t memory_size) { s_slab_heap.Initialize(memory, memory_size); } static Derived *Create() { Derived *obj = Allocate(); if (AMS_LIKELY(obj != nullptr)) { KAutoObject::Create(obj); } return obj; } template::type> static Derived *CreateFromUnusedSlabMemory() { static_assert(Enable == SupportDynamicExpansion); Derived * const obj = GetPointer(AllocateUnusedSlabMemory(sizeof(Derived), alignof(Derived))); if (AMS_LIKELY(obj != nullptr)) { std::construct_at(obj); KAutoObject::Create(obj); } return obj; } static size_t GetObjectSize() { return s_slab_heap.GetObjectSize(); } static size_t GetSlabHeapSize() { return s_slab_heap.GetSlabHeapSize(); } static size_t GetPeakIndex() { return s_slab_heap.GetPeakIndex(); } static uintptr_t GetSlabHeapAddress() { return s_slab_heap.GetSlabHeapAddress(); } static size_t GetNumRemaining() { return s_slab_heap.GetNumRemaining(); } }; template class KAutoObjectWithSlabHeap : public KAutoObjectWithSlabHeapBase { public: constexpr explicit KAutoObjectWithSlabHeap(util::ConstantInitializeTag) : KAutoObjectWithSlabHeapBase(util::ConstantInitialize) { /* ... */ } explicit KAutoObjectWithSlabHeap() { /* ... */ } static ALWAYS_INLINE void PreFinalize(Derived *) { /* ... */ } }; template requires std::derived_from class KAutoObjectWithSlabHeapAndContainer : public KAutoObjectWithSlabHeapBase { private: static constinit inline KAutoObjectWithListContainer s_container; public: class ListAccessor : public KAutoObjectWithListContainer::ListAccessor { public: ALWAYS_INLINE ListAccessor() : KAutoObjectWithListContainer::ListAccessor(s_container) { /* ... */ } ALWAYS_INLINE ~ListAccessor() { /* ... */ } }; public: constexpr explicit KAutoObjectWithSlabHeapAndContainer(util::ConstantInitializeTag) : KAutoObjectWithSlabHeapBase(util::ConstantInitialize) { /* ... */ } explicit KAutoObjectWithSlabHeapAndContainer() { /* ... */ } public: static void InitializeSlabHeap(void *memory, size_t memory_size) { KAutoObjectWithSlabHeapBase::InitializeSlabHeap(memory, memory_size); s_container.Initialize(); } static void Register(Derived *obj) { return s_container.Register(obj); } static ALWAYS_INLINE void PreFinalize(Derived *obj) { s_container.Unregister(obj); } }; }