kern: devirtualize several KAutoObject functions

This commit is contained in:
Michael Scire 2021-10-23 21:13:26 -07:00
parent 2490bbf4f9
commit 436613401a
30 changed files with 84 additions and 81 deletions

View file

@ -139,7 +139,9 @@ namespace ams::kern {
virtual void Destroy() { MESOSPHERE_ASSERT_THIS(); } virtual void Destroy() { MESOSPHERE_ASSERT_THIS(); }
/* Finalize is responsible for cleaning up resource, but does not destroy the object. */ /* Finalize is responsible for cleaning up resource, but does not destroy the object. */
virtual void Finalize() { MESOSPHERE_ASSERT_THIS(); } /* NOTE: This is a virtual function in official kernel, but because everything which uses it */
/* is already using CRTP for slab heap, we have devirtualized it for performance gain. */
/* virtual void Finalize() { MESOSPHERE_ASSERT_THIS(); } */
virtual KProcess *GetOwner() const { return nullptr; } virtual KProcess *GetOwner() const { return nullptr; }

View file

@ -36,7 +36,6 @@ namespace ams::kern {
} }
virtual void Destroy() override; virtual void Destroy() override;
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
constexpr KSession *GetParent() const { return m_parent; } constexpr KSession *GetParent() const { return m_parent; }

View file

@ -36,14 +36,14 @@ namespace ams::kern {
} }
Result Initialize(KProcessAddress address, size_t size); Result Initialize(KProcessAddress address, size_t size);
virtual void Finalize() override; void Finalize();
Result Map(KProcessAddress address, size_t size); Result Map(KProcessAddress address, size_t size);
Result Unmap(KProcessAddress address, size_t size); Result Unmap(KProcessAddress address, size_t size);
Result MapToOwner(KProcessAddress address, size_t size, ams::svc::MemoryPermission perm); Result MapToOwner(KProcessAddress address, size_t size, ams::svc::MemoryPermission perm);
Result UnmapFromOwner(KProcessAddress address, size_t size); Result UnmapFromOwner(KProcessAddress address, size_t size);
virtual bool IsInitialized() const override { return m_is_initialized; } bool IsInitialized() const { return m_is_initialized; }
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
KProcess *GetOwner() const { return m_owner; } KProcess *GetOwner() const { return m_owner; }

View file

@ -33,9 +33,9 @@ namespace ams::kern {
explicit KDeviceAddressSpace() : m_is_initialized(false) { /* ... */ } explicit KDeviceAddressSpace() : m_is_initialized(false) { /* ... */ }
Result Initialize(u64 address, u64 size); Result Initialize(u64 address, u64 size);
virtual void Finalize() override; void Finalize();
virtual bool IsInitialized() const override { return m_is_initialized; } bool IsInitialized() const { return m_is_initialized; }
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
Result Attach(ams::svc::DeviceName device_name); Result Attach(ams::svc::DeviceName device_name);

View file

@ -39,10 +39,10 @@ namespace ams::kern {
explicit KEvent() : m_readable_event(), m_owner(), m_initialized(), m_readable_event_destroyed() { /* ... */ } explicit KEvent() : m_readable_event(), m_owner(), m_initialized(), m_readable_event_destroyed() { /* ... */ }
void Initialize(); void Initialize();
virtual void Finalize() override; void Finalize();
virtual bool IsInitialized() const override { return m_initialized; } bool IsInitialized() const { return m_initialized; }
virtual uintptr_t GetPostDestroyArgument() const override { return reinterpret_cast<uintptr_t>(m_owner); } uintptr_t GetPostDestroyArgument() const { return reinterpret_cast<uintptr_t>(m_owner); }
static void PostDestroy(uintptr_t arg); static void PostDestroy(uintptr_t arg);

View file

@ -36,11 +36,11 @@ namespace ams::kern {
explicit KInterruptEvent() : m_interrupt_id(-1), m_is_initialized(false) { /* ... */ } explicit KInterruptEvent() : m_interrupt_id(-1), m_is_initialized(false) { /* ... */ }
Result Initialize(int32_t interrupt_name, ams::svc::InterruptType type); Result Initialize(int32_t interrupt_name, ams::svc::InterruptType type);
virtual void Finalize() override; void Finalize();
virtual Result Reset() override; virtual Result Reset() override;
virtual bool IsInitialized() const override { return m_is_initialized; } bool IsInitialized() const { return m_is_initialized; }
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }

View file

@ -38,9 +38,9 @@ namespace ams::kern {
} }
Result Initialize(ams::svc::IoPoolType pool_type); Result Initialize(ams::svc::IoPoolType pool_type);
virtual void Finalize() override; void Finalize();
virtual bool IsInitialized() const override { return m_is_initialized; } bool IsInitialized() const { return m_is_initialized; }
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
Result AddIoRegion(KIoRegion *region); Result AddIoRegion(KIoRegion *region);

View file

@ -43,9 +43,9 @@ namespace ams::kern {
explicit KIoRegion() : m_pool(nullptr), m_is_initialized(false) { /* ... */ } explicit KIoRegion() : m_pool(nullptr), m_is_initialized(false) { /* ... */ }
Result Initialize(KIoPool *pool, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm); Result Initialize(KIoPool *pool, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm);
virtual void Finalize() override; void Finalize();
virtual bool IsInitialized() const override { return m_is_initialized; } bool IsInitialized() const { return m_is_initialized; }
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
Result Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm); Result Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm);

View file

@ -34,7 +34,6 @@ namespace ams::kern {
} }
virtual void Destroy() override; virtual void Destroy() override;
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
constexpr const KLightSession *GetParent() const { return m_parent; } constexpr const KLightSession *GetParent() const { return m_parent; }

View file

@ -40,7 +40,6 @@ namespace ams::kern {
} }
virtual void Destroy() override; virtual void Destroy() override;
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
constexpr const KLightSession *GetParent() const { return m_parent; } constexpr const KLightSession *GetParent() const { return m_parent; }

View file

@ -49,10 +49,10 @@ namespace ams::kern {
explicit KLightSession() : m_state(State::Invalid), m_process(), m_initialized() { /* ... */ } explicit KLightSession() : m_state(State::Invalid), m_process(), m_initialized() { /* ... */ }
void Initialize(KClientPort *client_port, uintptr_t name); void Initialize(KClientPort *client_port, uintptr_t name);
virtual void Finalize() override; void Finalize();
virtual bool IsInitialized() const override { return m_initialized; } bool IsInitialized() const { return m_initialized; }
virtual uintptr_t GetPostDestroyArgument() const override { return reinterpret_cast<uintptr_t>(m_process); } uintptr_t GetPostDestroyArgument() const { return reinterpret_cast<uintptr_t>(m_process); }
static void PostDestroy(uintptr_t arg); static void PostDestroy(uintptr_t arg);

View file

@ -46,6 +46,8 @@ namespace ams::kern {
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
void Initialize(s32 max_sessions, bool is_light, uintptr_t name); void Initialize(s32 max_sessions, bool is_light, uintptr_t name);
void Finalize() { /* ... */ }
void OnClientClosed(); void OnClientClosed();
void OnServerClosed(); void OnServerClosed();

View file

@ -384,11 +384,11 @@ namespace ams::kern {
} }
public: public:
/* Overridden parent functions. */ /* Overridden parent functions. */
virtual bool IsInitialized() const override { return m_is_initialized; } bool IsInitialized() const { return m_is_initialized; }
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
virtual void Finalize() override; void Finalize();
virtual u64 GetId() const override final { return this->GetProcessId(); } virtual u64 GetId() const override final { return this->GetProcessId(); }

View file

@ -46,7 +46,7 @@ namespace ams::kern {
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
void Initialize(); void Initialize();
virtual void Finalize() override; void Finalize();
s64 GetLimitValue(ams::svc::LimitableResource which) const; s64 GetLimitValue(ams::svc::LimitableResource which) const;
s64 GetCurrentValue(ams::svc::LimitableResource which) const; s64 GetCurrentValue(ams::svc::LimitableResource which) const;

View file

@ -62,10 +62,10 @@ namespace ams::kern {
explicit KSession() : m_atomic_state(util::ToUnderlying(State::Invalid)), m_initialized(false), m_process(nullptr) { /* ... */ } explicit KSession() : m_atomic_state(util::ToUnderlying(State::Invalid)), m_initialized(false), m_process(nullptr) { /* ... */ }
void Initialize(KClientPort *client_port, uintptr_t name); void Initialize(KClientPort *client_port, uintptr_t name);
virtual void Finalize() override; void Finalize();
virtual bool IsInitialized() const override { return m_initialized; } bool IsInitialized() const { return m_initialized; }
virtual uintptr_t GetPostDestroyArgument() const override { return reinterpret_cast<uintptr_t>(m_process); } uintptr_t GetPostDestroyArgument() const { return reinterpret_cast<uintptr_t>(m_process); }
static void PostDestroy(uintptr_t arg); static void PostDestroy(uintptr_t arg);

View file

@ -169,20 +169,6 @@ namespace ams::kern {
} }
} }
virtual void Finalize() override {
m_mappings.Finalize();
if (m_thread) {
m_thread->Close();
}
if (m_event) {
m_event->Close();
}
if (m_server) {
m_server->Close();
}
}
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
constexpr ALWAYS_INLINE KThread *GetThread() const { return m_thread; } constexpr ALWAYS_INLINE KThread *GetThread() const { return m_thread; }
@ -229,6 +215,21 @@ namespace ams::kern {
constexpr ALWAYS_INLINE KProcessAddress GetExchangeServerAddress(size_t i) const { return m_mappings.GetExchangeServerAddress(i); } constexpr ALWAYS_INLINE KProcessAddress GetExchangeServerAddress(size_t i) const { return m_mappings.GetExchangeServerAddress(i); }
constexpr ALWAYS_INLINE size_t GetExchangeSize(size_t i) const { return m_mappings.GetExchangeSize(i); } constexpr ALWAYS_INLINE size_t GetExchangeSize(size_t i) const { return m_mappings.GetExchangeSize(i); }
constexpr ALWAYS_INLINE KMemoryState GetExchangeMemoryState(size_t i) const { return m_mappings.GetExchangeMemoryState(i); } constexpr ALWAYS_INLINE KMemoryState GetExchangeMemoryState(size_t i) const { return m_mappings.GetExchangeMemoryState(i); }
private:
/* NOTE: This is public and virtual in Nintendo's kernel. */
void Finalize() {
m_mappings.Finalize();
if (m_thread) {
m_thread->Close();
}
if (m_event) {
m_event->Close();
}
if (m_server) {
m_server->Close();
}
}
}; };
} }

View file

@ -42,9 +42,9 @@ namespace ams::kern {
} }
Result Initialize(KProcess *owner, size_t size, ams::svc::MemoryPermission own_perm, ams::svc::MemoryPermission rem_perm); Result Initialize(KProcess *owner, size_t size, ams::svc::MemoryPermission own_perm, ams::svc::MemoryPermission rem_perm);
virtual void Finalize() override; void Finalize();
virtual bool IsInitialized() const override { return m_is_initialized; } bool IsInitialized() const { return m_is_initialized; }
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
Result Map(KProcessPageTable *table, KProcessAddress address, size_t size, KProcess *process, ams::svc::MemoryPermission map_perm); Result Map(KProcessPageTable *table, KProcessAddress address, size_t size, KProcess *process, ams::svc::MemoryPermission map_perm);

View file

@ -44,7 +44,7 @@ namespace ams::kern {
public: public:
static Result Wait(s32 *out_index, KSynchronizationObject **objects, const s32 num_objects, s64 timeout); static Result Wait(s32 *out_index, KSynchronizationObject **objects, const s32 num_objects, s64 timeout);
public: public:
virtual void Finalize() override; void Finalize();
virtual bool IsSignaled() const { AMS_INFINITE_LOOP(); } virtual bool IsSignaled() const { AMS_INFINITE_LOOP(); }
void DumpWaiters(); void DumpWaiters();

View file

@ -612,12 +612,13 @@ namespace ams::kern {
/* Overridden parent functions. */ /* Overridden parent functions. */
virtual u64 GetId() const override final { return this->GetThreadId(); } virtual u64 GetId() const override final { return this->GetThreadId(); }
virtual bool IsInitialized() const override { return m_initialized; } bool IsInitialized() const { return m_initialized; }
virtual uintptr_t GetPostDestroyArgument() const override { return reinterpret_cast<uintptr_t>(m_parent) | (m_resource_limit_release_hint ? 1 : 0); } uintptr_t GetPostDestroyArgument() const { return reinterpret_cast<uintptr_t>(m_parent) | (m_resource_limit_release_hint ? 1 : 0); }
static void PostDestroy(uintptr_t arg); static void PostDestroy(uintptr_t arg);
virtual void Finalize() override; void Finalize();
virtual bool IsSignaled() const override; virtual bool IsSignaled() const override;
virtual void OnTimer() override; virtual void OnTimer() override;
virtual void DoWorkerTask() override; virtual void DoWorkerTask() override;

View file

@ -36,10 +36,10 @@ namespace ams::kern {
} }
Result Initialize(KProcessAddress addr, size_t size, ams::svc::MemoryPermission own_perm); Result Initialize(KProcessAddress addr, size_t size, ams::svc::MemoryPermission own_perm);
virtual void Finalize() override; void Finalize();
virtual bool IsInitialized() const override { return m_is_initialized; } bool IsInitialized() const { return m_is_initialized; }
virtual uintptr_t GetPostDestroyArgument() const override { return reinterpret_cast<uintptr_t>(m_owner); } uintptr_t GetPostDestroyArgument() const { return reinterpret_cast<uintptr_t>(m_owner); }
static void PostDestroy(uintptr_t arg); static void PostDestroy(uintptr_t arg);
Result Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm); Result Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm);

View file

@ -64,9 +64,8 @@ namespace ams::kern {
static size_t GetNumRemaining() { return s_slab_heap.GetNumRemaining(); } static size_t GetNumRemaining() { return s_slab_heap.GetNumRemaining(); }
}; };
template<typename Derived, typename Base, bool SupportDynamicExpansion = false> template<typename Derived, typename Base, bool SupportDynamicExpansion = false> requires std::derived_from<Base, KAutoObjectWithList>
class KAutoObjectWithSlabHeapAndContainer : public Base { class KAutoObjectWithSlabHeapAndContainer : public Base {
static_assert(std::is_base_of<KAutoObjectWithList, Base>::value);
private: private:
static constinit inline KSlabHeap<Derived, SupportDynamicExpansion> s_slab_heap; static constinit inline KSlabHeap<Derived, SupportDynamicExpansion> s_slab_heap;
static constinit inline KAutoObjectWithListContainer s_container; static constinit inline KAutoObjectWithListContainer s_container;
@ -84,28 +83,44 @@ namespace ams::kern {
ALWAYS_INLINE ListAccessor() : KAutoObjectWithListContainer::ListAccessor(s_container) { /* ... */ } ALWAYS_INLINE ListAccessor() : KAutoObjectWithListContainer::ListAccessor(s_container) { /* ... */ }
ALWAYS_INLINE ~ListAccessor() { /* ... */ } ALWAYS_INLINE ~ListAccessor() { /* ... */ }
}; };
private:
static ALWAYS_INLINE bool IsInitialized(const Derived *obj) {
if constexpr (requires { { obj->IsInitialized() } -> std::same_as<bool>; }) {
return obj->IsInitialized();
} else {
return true;
}
}
static ALWAYS_INLINE uintptr_t GetPostDestroyArgument(const Derived *obj) {
if constexpr (requires { { obj->GetPostDestroyArgument() } -> std::same_as<uintptr_t>; }) {
return obj->GetPostDestroyArgument();
} else {
return 0;
}
}
public: public:
constexpr explicit KAutoObjectWithSlabHeapAndContainer(util::ConstantInitializeTag) : Base(util::ConstantInitialize) { /* ... */ } constexpr explicit KAutoObjectWithSlabHeapAndContainer(util::ConstantInitializeTag) : Base(util::ConstantInitialize) { /* ... */ }
explicit KAutoObjectWithSlabHeapAndContainer() { /* ... */ } explicit KAutoObjectWithSlabHeapAndContainer() { /* ... */ }
virtual void Destroy() override { /* NOTE: IsInitialized() and GetPostDestroyArgument() are virtual functions declared in this class, */
const bool is_initialized = this->IsInitialized(); /* in Nintendo's kernel. We fully devirtualize them, as Destroy() is the only user of them. */
uintptr_t arg = 0; /* We also devirtualize KAutoObject::Finalize(), which is only used by this function in Nintendo's kernel. */
if (is_initialized) { virtual void Destroy() override final {
Derived * const derived = static_cast<Derived *>(this);
if (IsInitialized(derived)) {
s_container.Unregister(this); s_container.Unregister(this);
arg = this->GetPostDestroyArgument(); const uintptr_t arg = GetPostDestroyArgument(derived);
this->Finalize(); derived->Finalize();
} Free(derived);
Free(static_cast<Derived *>(this));
if (is_initialized) {
Derived::PostDestroy(arg); Derived::PostDestroy(arg);
} else {
Free(derived);
} }
} }
virtual bool IsInitialized() const { return true; }
virtual uintptr_t GetPostDestroyArgument() const { return 0; }
size_t GetSlabIndex() const { size_t GetSlabIndex() const {
return s_slab_heap.GetObjectIndex(static_cast<const Derived *>(this)); return s_slab_heap.GetObjectIndex(static_cast<const Derived *>(this));
} }

View file

@ -67,9 +67,6 @@ namespace ams::kern {
/* Close our reference to our owner. */ /* Close our reference to our owner. */
m_owner->Close(); m_owner->Close();
/* Perform inherited finalization. */
KAutoObjectWithSlabHeapAndContainer<KCodeMemory, KAutoObjectWithList>::Finalize();
} }
Result KCodeMemory::Map(KProcessAddress address, size_t size) { Result KCodeMemory::Map(KProcessAddress address, size_t size) {

View file

@ -43,9 +43,6 @@ namespace ams::kern {
/* Finalize the table. */ /* Finalize the table. */
m_table.Finalize(); m_table.Finalize();
/* Finalize base. */
KAutoObjectWithSlabHeapAndContainer<KDeviceAddressSpace, KAutoObjectWithList>::Finalize();
} }
Result KDeviceAddressSpace::Attach(ams::svc::DeviceName device_name) { Result KDeviceAddressSpace::Attach(ams::svc::DeviceName device_name) {

View file

@ -36,8 +36,6 @@ namespace ams::kern {
void KEvent::Finalize() { void KEvent::Finalize() {
MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT_THIS();
KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObjectWithList, true>::Finalize();
} }
Result KEvent::Signal() { Result KEvent::Signal() {

View file

@ -54,7 +54,7 @@ namespace ams::kern {
g_interrupt_event_task_table[m_interrupt_id]->Unregister(m_interrupt_id, m_core_id); g_interrupt_event_task_table[m_interrupt_id]->Unregister(m_interrupt_id, m_core_id);
/* Perform inherited finalization. */ /* Perform inherited finalization. */
KAutoObjectWithSlabHeapAndContainer<KInterruptEvent, KReadableEvent>::Finalize(); KReadableEvent::Finalize();
} }
Result KInterruptEvent::Reset() { Result KInterruptEvent::Reset() {

View file

@ -183,7 +183,7 @@ namespace ams::kern {
MESOSPHERE_LOG("KProcess::Finalize() pid=%ld name=%-12s\n", m_process_id, m_name); MESOSPHERE_LOG("KProcess::Finalize() pid=%ld name=%-12s\n", m_process_id, m_name);
/* Perform inherited finalization. */ /* Perform inherited finalization. */
KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize(); KSynchronizationObject::Finalize();
} }
Result KProcess::Initialize(const ams::svc::CreateProcessParameter &params) { Result KProcess::Initialize(const ams::svc::CreateProcessParameter &params) {

View file

@ -71,9 +71,6 @@ namespace ams::kern {
/* Release the memory reservation. */ /* Release the memory reservation. */
m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, size); m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, size);
m_resource_limit->Close(); m_resource_limit->Close();
/* Perform inherited finalization. */
KAutoObjectWithSlabHeapAndContainer<KSharedMemory, KAutoObjectWithList>::Finalize();
} }
Result KSharedMemory::Map(KProcessPageTable *table, KProcessAddress address, size_t size, KProcess *process, ams::svc::MemoryPermission map_perm) { Result KSharedMemory::Map(KProcessPageTable *table, KProcessAddress address, size_t size, KProcess *process, ams::svc::MemoryPermission map_perm) {

View file

@ -84,7 +84,6 @@ namespace ams::kern {
#endif #endif
this->OnFinalizeSynchronizationObject(); this->OnFinalizeSynchronizationObject();
KAutoObject::Finalize();
} }
Result KSynchronizationObject::Wait(s32 *out_index, KSynchronizationObject **objects, const s32 num_objects, s64 timeout) { Result KSynchronizationObject::Wait(s32 *out_index, KSynchronizationObject **objects, const s32 num_objects, s64 timeout) {

View file

@ -338,7 +338,7 @@ namespace ams::kern {
} }
/* Perform inherited finalization. */ /* Perform inherited finalization. */
KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>::Finalize(); KSynchronizationObject::Finalize();
} }
bool KThread::IsSignaled() const { bool KThread::IsSignaled() const {

View file

@ -56,9 +56,6 @@ namespace ams::kern {
/* Close the page group. */ /* Close the page group. */
GetReference(m_page_group).Close(); GetReference(m_page_group).Close();
GetReference(m_page_group).Finalize(); GetReference(m_page_group).Finalize();
/* Perform inherited finalization. */
KAutoObjectWithSlabHeapAndContainer<KTransferMemory, KAutoObjectWithList>::Finalize();
} }
void KTransferMemory::PostDestroy(uintptr_t arg) { void KTransferMemory::PostDestroy(uintptr_t arg) {