2024-03-19 15:47:42 +00:00
|
|
|
/***
|
|
|
|
Copyright (C) 2021-2024 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
|
|
|
|
File: AuHeapInternal.cpp
|
|
|
|
File: AuHeap.cpp
|
|
|
|
Date: 2021-6-12
|
|
|
|
Author: Reece
|
|
|
|
***/
|
|
|
|
#include <Source/RuntimeInternal.hpp>
|
|
|
|
#include "AuHeap.hpp"
|
|
|
|
#include "AuHeapInternal.hpp"
|
|
|
|
#include "AuHeapDeletable.hpp"
|
|
|
|
|
|
|
|
typedef struct FragmentHeader
|
|
|
|
{
|
|
|
|
void * next;
|
|
|
|
void * prev;
|
|
|
|
size_t size;
|
|
|
|
bool used;
|
|
|
|
} FragmentHeader;
|
|
|
|
|
|
|
|
namespace Aurora::Memory
|
|
|
|
{
|
|
|
|
InternalHeap::InternalHeap() :
|
2024-04-15 16:51:22 +00:00
|
|
|
pHeap_(nullptr),
|
|
|
|
uAllocCount_(0)
|
2024-03-19 15:47:42 +00:00
|
|
|
{ }
|
|
|
|
|
|
|
|
InternalHeap::InternalHeap(const MemoryViewWrite &memory)
|
|
|
|
{
|
2024-04-15 16:51:22 +00:00
|
|
|
SysAssert(this->Init(memory));
|
2024-03-19 15:47:42 +00:00
|
|
|
}
|
|
|
|
|
2024-04-23 23:52:22 +00:00
|
|
|
InternalHeap::InternalHeap(const AuSPtr<MemoryViewWrite> &pMemory)
|
|
|
|
{
|
|
|
|
SysAssert(this->Init(pMemory), "Couldn't initialize inline AuHeap! [OOM]");
|
|
|
|
}
|
|
|
|
|
2024-03-19 15:47:42 +00:00
|
|
|
InternalHeap::InternalHeap(AuUInt uLength)
|
|
|
|
{
|
|
|
|
SysAssert(this->Init(uLength), "Couldn't initialize inline AuHeap! [OOM]");
|
|
|
|
}
|
|
|
|
|
|
|
|
InternalHeap::~InternalHeap()
|
|
|
|
{
|
2024-04-15 16:51:22 +00:00
|
|
|
SysAssertDbgExp(this->uAllocCount_ == 0);
|
2024-03-19 15:47:42 +00:00
|
|
|
|
|
|
|
if (this->pBase_)
|
|
|
|
{
|
2024-04-15 16:51:22 +00:00
|
|
|
if (this->pHeap_)
|
2024-03-19 15:47:42 +00:00
|
|
|
{
|
2024-04-15 16:51:22 +00:00
|
|
|
this->pHeap_ = nullptr;
|
2024-03-19 15:47:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (this->bOwnsMemory_)
|
|
|
|
{
|
|
|
|
SysAllocateFree(this->pBase_, this->uLength_);
|
|
|
|
this->pBase_ = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AuUInt InternalHeap::GetHeapSize(const void *ptr)
|
|
|
|
{
|
|
|
|
return reinterpret_cast<const FragmentHeader *>(ptr)[-1].size;
|
|
|
|
}
|
|
|
|
|
2024-04-15 16:51:22 +00:00
|
|
|
bool InternalHeap::Init(const MemoryViewWrite &memory)
|
|
|
|
{
|
|
|
|
if (memory.HasControlBlock())
|
|
|
|
{
|
|
|
|
this->pBloat_ = AuMakeShared<MemoryViewWrite>(memory);
|
|
|
|
}
|
|
|
|
|
|
|
|
return this->Init(memory.length, memory.ptr);
|
|
|
|
}
|
|
|
|
|
2024-04-23 23:52:22 +00:00
|
|
|
bool InternalHeap::Init(const AuSPtr<MemoryViewWrite> &pMemory)
|
|
|
|
{
|
|
|
|
if (!pMemory || !*pMemory)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->pBloat_ = pMemory;
|
|
|
|
return this->Init(pMemory->length, pMemory->ptr);
|
|
|
|
}
|
|
|
|
|
2024-03-19 15:47:42 +00:00
|
|
|
bool InternalHeap::Init(AuUInt uLength, void *ptr)
|
|
|
|
{
|
|
|
|
SysAssert(!this->pBase_, "heap already initialized");
|
|
|
|
SysAssert(uLength, "invalid heap allocation");
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
this->pBase_ = ptr;
|
|
|
|
this->uLength_ = uLength;
|
|
|
|
this->bOwnsMemory_ = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (uLength <= 4096)
|
|
|
|
{
|
|
|
|
uLength = 4096;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(this->pBase_ = SysAllocateLarge(uLength)))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->bOwnsMemory_ = true;
|
|
|
|
this->uLength_ = uLength;
|
|
|
|
}
|
|
|
|
|
2024-04-15 16:51:22 +00:00
|
|
|
if (!(this->pHeap_ = o1heapInit(this->pBase_, uLength)))
|
2024-03-19 15:47:42 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Types::size_t InternalHeap::GetChunkSize(const void *head)
|
|
|
|
{
|
|
|
|
return InternalHeap::GetHeapSize(head);
|
|
|
|
}
|
|
|
|
|
|
|
|
AuSPtr<Heap> InternalHeap::AllocateDivision(AuUInt32 heap, AuUInt32 alignment)
|
|
|
|
{
|
|
|
|
return AllocateDivisionGlobal(this, heap, alignment);
|
|
|
|
}
|
|
|
|
|
|
|
|
AuSPtr<Heap> AllocateDivisionGlobal(Heap *heap, AuUInt32 uLength, AuUInt32 alignment)
|
|
|
|
{
|
|
|
|
auto ptr = heap->ZAlloc<void *>(uLength, alignment);
|
|
|
|
if (!ptr)
|
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
auto ret = AuMakeShared<DeletableHeap>(heap, ptr);
|
|
|
|
if (!ret)
|
|
|
|
{
|
|
|
|
heap->Free(ptr);
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ret->Init(uLength, ptr))
|
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *InternalHeap::_FAlloc(Types::size_t uLength)
|
|
|
|
{
|
2024-04-15 16:51:22 +00:00
|
|
|
if (!this->pHeap_)
|
2024-03-19 15:47:42 +00:00
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2024-04-15 16:51:22 +00:00
|
|
|
auto ret = o1heapAllocate(this->pHeap_, uLength);
|
2024-03-19 15:47:42 +00:00
|
|
|
if (ret)
|
|
|
|
{
|
2024-04-15 16:51:22 +00:00
|
|
|
AuAtomicAdd(&this->uAllocCount_, 1u);
|
2024-03-19 15:47:42 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *InternalHeap::_FAlloc(Types::size_t uLength, Types::size_t uAlign)
|
|
|
|
{
|
|
|
|
SysAssert(uAlign <= O1HEAP_ALIGNMENT, "heap wrapping is unsupported, alignment past the supported 2^x alignment is not possible");
|
|
|
|
return this->_FAlloc(uLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
void *InternalHeap::_ZAlloc(Types::size_t uLength)
|
|
|
|
{
|
2024-04-15 16:51:22 +00:00
|
|
|
if (!this->pHeap_)
|
2024-03-19 15:47:42 +00:00
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto ptr = this->_FAlloc(uLength);
|
|
|
|
if (!ptr)
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
AuMemset(ptr, 0, uLength);
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *InternalHeap::_ZAlloc(Types::size_t uLength, Types::size_t uAlign)
|
|
|
|
{
|
|
|
|
SysAssert(uAlign <= O1HEAP_ALIGNMENT, "heap wrapping is unsupported, alignment past the supported 2^x alignment is not possible");
|
|
|
|
return _ZAlloc(uLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
void *InternalHeap::_ZRealloc(void *pBuffer, Types::size_t uLength)
|
|
|
|
{
|
|
|
|
auto prevLength = GetHeapSize(pBuffer);
|
|
|
|
auto alloc = this->_ZAlloc(uLength);
|
|
|
|
if (!alloc)
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
AuMemcpy(alloc, pBuffer, AuMin(prevLength, uLength));
|
|
|
|
this->_Free(pBuffer);
|
|
|
|
return alloc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *InternalHeap::_ZRealloc(void *pBuffer, Types::size_t uLength, Types::size_t uAlign)
|
|
|
|
{
|
|
|
|
SysAssert(uAlign <= O1HEAP_ALIGNMENT, "heap wrapping is unsupported, alignment past the supported 2^x alignment is not possible");
|
|
|
|
return this->_ZRealloc(pBuffer, uLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
void *InternalHeap::_FRealloc(void *pBuffer, Types::size_t uLength)
|
|
|
|
{
|
|
|
|
auto prevLength = GetHeapSize(pBuffer);
|
|
|
|
auto alloc = this->_FAlloc(uLength);
|
|
|
|
if (!alloc)
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
AuMemcpy(alloc, pBuffer, AuMin(prevLength, uLength));
|
|
|
|
this->_Free(pBuffer);
|
|
|
|
return alloc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *InternalHeap::_FRealloc(void *pBuffer, Types::size_t uLength, Types::size_t uAlign)
|
|
|
|
{
|
|
|
|
SysAssert(uAlign <= O1HEAP_ALIGNMENT, "heap wrapping is unsupported, alignment past the supported 2^x alignment is not possible");
|
|
|
|
return this->_FRealloc(pBuffer, uLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InternalHeap::_Free(void *pBuffer)
|
|
|
|
{
|
|
|
|
if (pBuffer == nullptr)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-04-15 16:51:22 +00:00
|
|
|
o1heapFree(this->pHeap_, pBuffer);
|
2024-03-19 15:47:42 +00:00
|
|
|
DecrementUsers();
|
|
|
|
}
|
|
|
|
|
|
|
|
void InternalHeap::DecrementUsers()
|
|
|
|
{
|
2024-04-15 16:51:22 +00:00
|
|
|
if (AuAtomicSub(&this->uAllocCount_, 1u) == 0)
|
2024-03-19 15:47:42 +00:00
|
|
|
{
|
|
|
|
TryRelease();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InternalHeap::TryRelease()
|
|
|
|
{
|
|
|
|
if (!this->bIsDangling_)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-04-15 16:51:22 +00:00
|
|
|
if (AuAtomicLoad(&uAllocCount_) == 0)
|
2024-03-19 15:47:42 +00:00
|
|
|
{
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InternalHeap::RequestTermination()
|
|
|
|
{
|
2024-04-15 16:51:22 +00:00
|
|
|
if (AuAtomicLoad(&this->uAllocCount_))
|
2024-03-19 15:47:42 +00:00
|
|
|
{
|
|
|
|
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 InternalHeap::UpdateStats()
|
|
|
|
{
|
2024-04-15 16:51:22 +00:00
|
|
|
auto pDiag = o1heapGetDiagnostics(this->pHeap_);
|
2024-03-19 15:47:42 +00:00
|
|
|
|
|
|
|
this->stats.uBytesLiveCounter = pDiag.allocated;
|
|
|
|
this->stats.uBytesCapacity = pDiag.capacity;
|
|
|
|
this->stats.uBytesPeakCounter = pDiag.peak_allocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InternalHeap::WalkHeap(bool(*fCallback)(void *, void *), void *pSecondArg)
|
|
|
|
{
|
2024-04-15 16:51:22 +00:00
|
|
|
o1heapTraverseHeap(this->pHeap_, fCallback, pSecondArg);
|
2024-03-19 15:47:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AuSPtr<Heap> InternalHeap::GetSelfReference()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
return AuSharedFromThis();
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Heap *InternalHeap::GetSelfReferenceRaw()
|
|
|
|
{
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
AUKN_SYM Heap *AllocHeapNew(AuUInt uSize)
|
|
|
|
{
|
|
|
|
auto pHeap = _new InternalHeap();
|
|
|
|
if (!pHeap)
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pHeap->Init(uSize, nullptr))
|
|
|
|
{
|
|
|
|
delete pHeap;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pHeap;
|
|
|
|
}
|
|
|
|
|
|
|
|
AUKN_SYM void AllocHeapRelease(Heap *pHeap)
|
|
|
|
{
|
|
|
|
static_cast<InternalHeap *>(pHeap)->RequestTermination();
|
|
|
|
}
|
|
|
|
|
|
|
|
AUKN_SYM Heap *RequestHeapOfRegionNew(const MemoryViewWrite &memory)
|
|
|
|
{
|
|
|
|
if (!memory)
|
|
|
|
{
|
|
|
|
SysPushErrorArg();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto pHeap = _new InternalHeap();
|
|
|
|
if (!pHeap)
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2024-04-15 16:51:22 +00:00
|
|
|
if (!pHeap->Init(memory))
|
2024-03-19 15:47:42 +00:00
|
|
|
{
|
|
|
|
delete pHeap;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pHeap;
|
|
|
|
}
|
|
|
|
|
|
|
|
AUKN_SYM void RequestHeapOfRegionRelease(Heap *pHeap)
|
|
|
|
{
|
|
|
|
static_cast<InternalHeap *>(pHeap)->RequestTermination();
|
|
|
|
}
|
|
|
|
|
2024-04-23 23:52:22 +00:00
|
|
|
AUKN_SYM Heap *RequestHeapOfSharedRegionNew(const AuSPtr<MemoryViewWrite> &pMemory)
|
|
|
|
{
|
|
|
|
if (!pMemory)
|
|
|
|
{
|
|
|
|
SysPushErrorArg();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto pHeap = _new InternalHeap();
|
|
|
|
if (!pHeap)
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pHeap->Init(pMemory))
|
|
|
|
{
|
|
|
|
delete pHeap;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pHeap;
|
|
|
|
}
|
|
|
|
|
|
|
|
AUKN_SYM void RequestHeapOfSharedRegionRelease(Heap *pHeap)
|
|
|
|
{
|
|
|
|
static_cast<InternalHeap *>(pHeap)->RequestTermination();
|
|
|
|
}
|
|
|
|
|
2024-03-19 15:47:42 +00:00
|
|
|
AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, RequestHeapOfRegion, InternalHeap, (const MemoryViewWrite &, memory))
|
2024-04-23 23:52:22 +00:00
|
|
|
AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, RequestHeapOfSharedRegion, InternalHeap, (const AuSPtr<MemoryViewWrite> &, memory))
|
2024-03-19 15:47:42 +00:00
|
|
|
AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, AllocHeap, InternalHeap, (AuUInt, uLength))
|
|
|
|
}
|