/*** Copyright (C) 2021-2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuHeapAdapter.cpp File: Heap.hpp Date: 2024-7-17 Author: Reece ***/ #include #include "AuHeap.hpp" #include "AuHeapAdapter.hpp" #include "AuHeapInternal.hpp" #include "AuHeapDeletable.hpp" #include "AuHeapAlignmentInterface.hpp" namespace Aurora::Memory { ImplHeapAdapter::ImplHeapAdapter(const HeapAdapterInterface &heapInterface) { if (!this->Init(heapInterface)) { AU_THROW_CONST_STRING("Invalid heap adapter configuration"); } } ImplHeapAdapter::ImplHeapAdapter() { } ImplHeapAdapter::~ImplHeapAdapter() { if (this->adapter.fHeapDestroy) { this->adapter.fHeapDestroy(&this->adapter.handle); } } bool ImplHeapAdapter::Init(const HeapAdapterInterface &heapInterface) { this->adapter = heapInterface; if (!this->adapter.fFree || !this->adapter.fAllocate) { return false; } if (!this->adapter.fGetBlockSize || !this->adapter.bHasAlignmentAwareness) { if (!MakeHeapInterfaceOfStricterAlignment(&this->adapter)) { return false; } } return true; } HeapStats &ImplHeapAdapter::GetStats() { return this->stats; } Types::size_t ImplHeapAdapter::GetChunkSize(const void *head) { if (!head) { return 0; } return this->adapter.fGetBlockSize(&this->adapter.handle, (void *)head); } AuSPtr ImplHeapAdapter::AllocateDivision(AuUInt32 heap, AuUInt32 alignment) { return AllocateDivisionGlobal(this, heap, alignment); } void *ImplHeapAdapter::_FAlloc(Types::size_t uLength) { return _FAlloc(uLength, alignof(void *)); } void *ImplHeapAdapter::_FAlloc(Types::size_t uLength, Types::size_t uAlign) { if (!uLength) { return nullptr; } auto pRet = this->adapter.fAllocate(&this->adapter.handle, uLength, uAlign); if (!pRet) { return nullptr; } auto uLengthCurrent = this->GetChunkSize(pRet); AuAtomicAdd(&this->stats.uBytesLiveCounter, uLengthCurrent); AuAtomicAdd(&this->stats.uBytesAllocatedLifetime, uLengthCurrent); return pRet; } void *ImplHeapAdapter::_ZAlloc(Types::size_t uLength) { auto ptr = this->_FAlloc(uLength); if (!ptr) { return nullptr; } AuMemset(ptr, 0, uLength); return ptr; } void *ImplHeapAdapter::_ZAlloc(Types::size_t uLength, Types::size_t uAlign) { auto ptr = this->_FAlloc(uLength, uAlign); if (!ptr) { return nullptr; } AuMemset(ptr, 0, uLength); return ptr; } void *ImplHeapAdapter::_ZRealloc(void *pBuffer, Types::size_t uLength) { auto prevLength = this->GetChunkSize(pBuffer); auto alloc = this->_ZAlloc(uLength); if (!alloc) { return nullptr; } AuMemcpy(alloc, pBuffer, AuMin(prevLength, uLength)); this->_Free(pBuffer); return alloc; } void *ImplHeapAdapter::_ZRealloc(void *pBuffer, Types::size_t uLength, Types::size_t uAlign) { auto prevLength = this->GetChunkSize(pBuffer); auto alloc = this->_ZAlloc(uLength, uAlign); if (!alloc) { return nullptr; } AuMemcpy(alloc, pBuffer, AuMin(prevLength, uLength)); this->_Free(pBuffer); return alloc; } void *ImplHeapAdapter::_FRealloc(void *pBuffer, Types::size_t uLength) { auto prevLength = this->GetChunkSize(pBuffer); auto alloc = this->_FAlloc(uLength); if (!alloc) { return nullptr; } AuMemcpy(alloc, pBuffer, AuMin(prevLength, uLength)); this->_Free(pBuffer); return alloc; } void *ImplHeapAdapter::_FRealloc(void *pBuffer, Types::size_t uLength, Types::size_t uAlign) { auto prevLength = this->GetChunkSize(pBuffer); auto alloc = this->_FAlloc(uLength, uAlign); if (!alloc) { return nullptr; } AuMemcpy(alloc, pBuffer, AuMin(prevLength, uLength)); this->_Free(pBuffer); return alloc; } void ImplHeapAdapter::_Free(void *pBuffer) { if (pBuffer == nullptr) { return; } auto uLengthCurrent = this->GetChunkSize(pBuffer); this->adapter.fFree(&this->adapter.handle, pBuffer); AuAtomicAdd(&this->stats.uBytesFreeLifetime, uLengthCurrent); AuAtomicSub(&this->stats.uBytesLiveCounter, uLengthCurrent); TryRelease(); } void ImplHeapAdapter::TryRelease() { if (!this->bIsDangling_) { return; } if (AuAtomicLoad(&this->stats.uBytesLiveCounter) == 0) { delete this; } } void ImplHeapAdapter::RequestTermination() { if (AuAtomicLoad(&this->stats.uBytesLiveCounter)) { SysPushErrorMemory("Heap life was less than its allocations, waiting for final free"); SysPushErrorMemory("Reporting using mayday!"); // Write a crash dump for later review, and do not panic. // We just have a leak with no sign of corruption Telemetry::Mayday(); this->bIsDangling_ = true; } else { delete this; } } void ImplHeapAdapter::WalkHeap(bool(*fCallback)(void *, void *), void *pSecondArg) { } AuSPtr ImplHeapAdapter::GetSelfReference() { try { return AuSharedFromThis(); } catch (...) { return {}; } } Heap *ImplHeapAdapter::GetSelfReferenceRaw() { return this; } AUKN_SYM Heap *HeapAdapterNew(const HeapAdapterInterface &adapterInterface) { auto pHeap = _new ImplHeapAdapter(); if (!pHeap) { return nullptr; } if (!pHeap->Init(adapterInterface)) { delete pHeap; return nullptr; } return pHeap; } AUKN_SYM void HeapAdapterRelease(Heap *pHeap) { static_cast(pHeap)->RequestTermination(); } AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, HeapAdapter, ImplHeapAdapter, (const HeapAdapterInterface &, adapterInterface)) }