[*] Polish AuMemory
This commit is contained in:
parent
0b60cb8099
commit
bd1283e146
@ -10,6 +10,8 @@
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
struct ProxyHeap;
|
||||
static const AuUInt8 kHeapSize = 128;
|
||||
static const AuUInt8 kHeap2Size = 255;
|
||||
|
||||
struct Heap
|
||||
{
|
||||
@ -18,73 +20,110 @@ namespace Aurora::Memory
|
||||
virtual HeapStats &GetStats() = 0;
|
||||
virtual void WalkHeap(bool(*fCallback)(void *, void *), void *pSecondArg) = 0;
|
||||
|
||||
// Potentially slower, zero allocate
|
||||
template<typename T = void *>
|
||||
T ZAlloc(Types::size_t length)
|
||||
T ZAlloc(Types::size_t uLength)
|
||||
{
|
||||
return reinterpret_cast<T>(_ZAlloc(length));
|
||||
if constexpr (AuIsVoid_v<AuRemovePointer_t<T>>)
|
||||
{
|
||||
return reinterpret_cast<T>(_ZAlloc(uLength));
|
||||
}
|
||||
else
|
||||
{
|
||||
return reinterpret_cast<T>(_ZAlloc(uLength, alignof(AuRemovePointer_t<T>)));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T = void *>
|
||||
T ZAlloc(Types::size_t length, Types::size_t align)
|
||||
T ZAlloc(Types::size_t uLength, Types::size_t uAlignment)
|
||||
{
|
||||
return reinterpret_cast<T>(_ZAlloc(length, align));
|
||||
return reinterpret_cast<T>(_ZAlloc(uLength, uAlignment));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *ZAlloc()
|
||||
{
|
||||
return reinterpret_cast<T *>(_ZAlloc(sizeof(T)));
|
||||
return reinterpret_cast<T *>(_ZAlloc(sizeof(T), alignof(T)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *NewArray(Types::size_t count)
|
||||
T *NewArray(Types::size_t uLength)
|
||||
{
|
||||
return ZAlloc<T *>(count * sizeof(T));
|
||||
return ZAlloc<T *>(uLength * sizeof(T), alignof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *NewArray(Types::size_t count, Types::size_t align)
|
||||
T *NewArray(Types::size_t uLength, Types::size_t uAlignment)
|
||||
{
|
||||
return ZAlloc<T *>(count * sizeof(T), align);
|
||||
return ZAlloc<T *>(uLength * sizeof(T), uAlignment);
|
||||
}
|
||||
|
||||
/// Fast, unsafe alloc
|
||||
template<typename T = void *>
|
||||
T FAlloc(Types::size_t length)
|
||||
T FAlloc(Types::size_t uLength)
|
||||
{
|
||||
return reinterpret_cast<T>(_FAlloc(length));
|
||||
if constexpr (AuIsVoid_v<AuRemovePointer_t<T>>)
|
||||
{
|
||||
return reinterpret_cast<T>(_FAlloc(uLength));
|
||||
}
|
||||
else
|
||||
{
|
||||
return reinterpret_cast<T>(_FAlloc(uLength, alignof(AuRemovePointer_t<T>)));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T = void *>
|
||||
T FAlloc(Types::size_t length, Types::size_t align)
|
||||
T FAlloc(Types::size_t uLength, Types::size_t uAlignment)
|
||||
{
|
||||
return reinterpret_cast<T>(_FAlloc(length, align));
|
||||
return reinterpret_cast<T>(_FAlloc(uLength, uAlignment));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T ZRealloc(T pHead, Types::size_t length)
|
||||
T *FAlloc()
|
||||
{
|
||||
return reinterpret_cast<T>(_ZRealloc(reinterpret_cast<void *>(pHead), length));
|
||||
return reinterpret_cast<T *>(_FAlloc(sizeof(T), alignof(T)));
|
||||
}
|
||||
|
||||
// Reallocs
|
||||
template<typename T>
|
||||
T ZRealloc(T pHead, Types::size_t uLength)
|
||||
{
|
||||
if constexpr (AuIsVoid_v<AuRemovePointer_t<T>>)
|
||||
{
|
||||
return reinterpret_cast<T>(_ZRealloc(reinterpret_cast<void *>(pHead), uLength));
|
||||
}
|
||||
else
|
||||
{
|
||||
return reinterpret_cast<T>(_ZRealloc(reinterpret_cast<void *>(pHead), uLength, alignof(AuRemovePointer_t<T>)));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T ZRealloc(T pHead, Types::size_t length, Types::size_t alloc)
|
||||
T ZRealloc(T pHead, Types::size_t uLength, Types::size_t uAlignment)
|
||||
{
|
||||
return reinterpret_cast<T>(_ZRealloc(reinterpret_cast<void *>(pHead), length), alloc);
|
||||
return reinterpret_cast<T>(_ZRealloc(reinterpret_cast<void *>(pHead), uLength, uAlignment));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T FRealloc(T pHead, Types::size_t length)
|
||||
T FRealloc(T pHead, Types::size_t uLength)
|
||||
{
|
||||
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(pHead), length));
|
||||
if constexpr (AuIsVoid_v<AuRemovePointer_t<T>>)
|
||||
{
|
||||
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(pHead), uLength));
|
||||
}
|
||||
else
|
||||
{
|
||||
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(pHead), uLength, alignof(AuRemovePointer_t<T>)));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T FRealloc(T pHead, Types::size_t length, Types::size_t alloc)
|
||||
T FRealloc(T pHead, Types::size_t uLength, Types::size_t uAlignment)
|
||||
{
|
||||
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(pHead), length), alloc);
|
||||
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(pHead), uLength, uAlignment));
|
||||
}
|
||||
|
||||
// Free
|
||||
template<typename T>
|
||||
void Free(T pHead)
|
||||
{
|
||||
@ -115,12 +154,12 @@ namespace Aurora::Memory
|
||||
|
||||
auto pVoids = (void **)(((char *)pThat) - kAlignment);
|
||||
auto pHeap = (Heap *)pVoids[0];
|
||||
auto uCount = (AuUInt)pVoids[1];
|
||||
auto uLength = (AuUInt)pVoids[1];
|
||||
|
||||
if constexpr (AuIsClass_v<T> &&
|
||||
!AuIsTriviallyDestructible_v<T>)
|
||||
{
|
||||
for (AU_ITERATE_N(i, uCount))
|
||||
for (AU_ITERATE_N(i, uLength))
|
||||
{
|
||||
auto &refElement = pThat[i];
|
||||
refElement.~T();
|
||||
@ -187,10 +226,20 @@ namespace Aurora::Memory
|
||||
}
|
||||
|
||||
*(void **)pPtr = pThat;
|
||||
return AuSPtr<T>((T *)(pPtr + kAlignment), &Heap::DeleteThat<T>);
|
||||
|
||||
auto pTThat = (T *)(pPtr + kAlignment);
|
||||
AUROXTL_COMMODITY_TRY
|
||||
{
|
||||
return AuSPtr<T>(pTThat, &Heap::DeleteThat<T>);
|
||||
}
|
||||
AUROXTL_COMMODITY_CATCH
|
||||
{
|
||||
Heap::DeleteThat<T>(pTThat);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// note: callers can use AuHUPOf_t<T> pUniquePointer = AuNullHeapPointer<T>()
|
||||
// note: callers can use AuHUPOf_t<Z> pUniquePointer = AuNullHeapPointer<Z>()
|
||||
|
||||
template <class T, class Z = T, class ...Args>
|
||||
AuUPtr<Z, decltype(&Heap::DeleteThat<Z>)> NewClassUnique(Args &&...args)
|
||||
@ -288,7 +337,16 @@ namespace Aurora::Memory
|
||||
pVoids[0] = pThat;
|
||||
pVoids[1] = (void *)uElements;
|
||||
|
||||
return AuSPtr<T>((T *)(pPtr + kAlignment), &Heap::DeleteThatArray<T>);
|
||||
auto pTThat = (T *)(pPtr + kAlignment);
|
||||
AUROXTL_COMMODITY_TRY
|
||||
{
|
||||
return AuSPtr<T>(pTThat, &Heap::DeleteThatArray<T>);
|
||||
}
|
||||
AUROXTL_COMMODITY_CATCH
|
||||
{
|
||||
Heap::DeleteThatArray<T>(pTThat);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// note: callers can use AuHUPOf_t<T> pUniquePointer = AuNullHeapPointer<T>()
|
||||
@ -372,31 +430,6 @@ namespace Aurora::Memory
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static AuSPtr<T> ToSmartPointer(AuSPtr<Heap> heap,
|
||||
T *pHead,
|
||||
bool bPinHeap = true)
|
||||
{
|
||||
auto handle = bPinHeap ?
|
||||
heap :
|
||||
AuSPtr<Heap> {};
|
||||
auto pHeap = heap.get();
|
||||
return AuSPtr<T>(pHead,
|
||||
[handle, pHeap](T *pDeleteMe)
|
||||
{
|
||||
if constexpr (AuIsClass_v<T>
|
||||
#if !defined(AURT_HEAP_NO_STL)
|
||||
&& !std::is_trivially_destructible_v<T>
|
||||
#endif
|
||||
)
|
||||
{
|
||||
pDeleteMe->~T();
|
||||
}
|
||||
|
||||
pHeap->Free(pDeleteMe);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
using HUPOf_t = AuUPtr<T, decltype(&Heap::DeleteThat<T>)>;
|
||||
|
||||
@ -408,9 +441,9 @@ namespace Aurora::Memory
|
||||
virtual Heap *GetSelfReferenceRaw() = 0;
|
||||
|
||||
virtual AU_ALLOC void *_ZAlloc(Types::size_t uLength) = 0;
|
||||
virtual AU_ALLOC void *_ZAlloc(Types::size_t uLength, Types::size_t align) = 0;
|
||||
virtual AU_ALLOC void *_ZAlloc(Types::size_t uLength, Types::size_t uAlignment) = 0;
|
||||
virtual AU_ALLOC void *_FAlloc(Types::size_t uLength) = 0;
|
||||
virtual AU_ALLOC void *_FAlloc(Types::size_t uLength, Types::size_t align) = 0;
|
||||
virtual AU_ALLOC void *_FAlloc(Types::size_t uLength, Types::size_t uAlignment) = 0;
|
||||
virtual AU_ALLOC void *_ZRealloc(void *pBase, Types::size_t uLength, Types::size_t uAlign) = 0;
|
||||
virtual AU_ALLOC void *_ZRealloc(void *pBase, Types::size_t uLength) = 0;
|
||||
virtual AU_ALLOC void *_FRealloc(void *pBase, Types::size_t uLength, Types::size_t uAlign) = 0;
|
||||
@ -432,8 +465,8 @@ namespace Aurora::Memory
|
||||
};
|
||||
|
||||
/**
|
||||
Returns a heap interface backed by the default allocator
|
||||
*/
|
||||
* Returns a heap interface backed by the default allocator
|
||||
*/
|
||||
AUKN_SHARED_API(DefaultDiscontiguousHeap, Heap);
|
||||
|
||||
inline Heap *GetDefaultDiscontiguousHeap()
|
||||
@ -448,27 +481,28 @@ namespace Aurora::Memory
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates uLength amount of contiguous virtual memory
|
||||
* Allocates uLength amount of contiguous virtual memory
|
||||
* @return a heap backed by uLength bytes of virtual memory
|
||||
* @warning the SOO variant cannot guarantee release-on-last-free and will panic if uLength cannot be allocated. Use AllocHeap[Shared/Unique/New](uLength) instead.
|
||||
*/
|
||||
AUKN_SHARED_SOO2_NCM(AllocHeap, Heap, kHeapSize, ((AuUInt, uLength)), AuUInt uLength);
|
||||
|
||||
@warning Heaps are guaranteed to outlive their allocations; heaps are the one object that effectively own a single reference count on themselves.
|
||||
Requesting termination before all of its' memory has been free will result, pHead at worst, a warning.
|
||||
Expect to leak unless all allocs have been paired by a free.
|
||||
/**
|
||||
* @warning the SOO variant cannot guarantee release-on-last-free.
|
||||
*/
|
||||
AUKN_SHARED_SOO2_NCM(RequestHeapOfRegion, Heap, kHeapSize, ((const MemoryViewWrite &, memory)), const MemoryViewWrite &memory);
|
||||
|
||||
I do not expect to implement force frees simply because all our primary use cases keep track of dtors to forcefully release leaked objects.
|
||||
Use RequestHeapOfRegion to be backed by caller owned memory.
|
||||
/**
|
||||
* Proxies an existing heap with encapsulated statistics.
|
||||
* This is intended for debugging purposes when accurate heap stats of a heap-subset are desired.
|
||||
* @warning this heap cannot guarantee release-on-last-free
|
||||
*/
|
||||
AUKN_SHARED_SOO2_NCM(HeapProxy, Heap, kHeap2Size, ((const AuSPtr<Heap> &, pHead)), const AuSPtr<Heap> &pHead);
|
||||
|
||||
@return a heap backed by uLength bytes of virtual memory
|
||||
/**
|
||||
* Proxies an existing heap with encapsulated statistics and leak detector
|
||||
* This is intended for debugging purposes when accurate heap stats of a heap-subset are desired.
|
||||
* @warning this heap cannot guarantee release-on-last-free
|
||||
*/
|
||||
AUKN_SHARED_API(AllocHeap, Heap, AuUInt uLength);
|
||||
|
||||
AUKN_SHARED_API(RequestHeapOfRegion, Heap, const MemoryViewWrite &memory);
|
||||
|
||||
// AllocHeap but use mimalloc (or the default allocator) instead
|
||||
AUKN_SHARED_API(AllocHeapMimalloc, Heap, AuUInt uLength);
|
||||
|
||||
// Proxies an existing heap with encapsulated statistics
|
||||
AUKN_SHARED_API(HeapProxy, Heap, const AuSPtr<Heap> &pHead);
|
||||
|
||||
// Proxies an existing heap with encapsulated statistics and leak detector
|
||||
AUKN_SHARED_API(HeapProxyEx, Heap, const AuSPtr<Heap> &pHead, LeakFinderAlloc_f pfAlloc, LeakFinderFree_f pfFree);
|
||||
AUKN_SHARED_SOO2_NCM(HeapProxyEx, Heap, kHeap2Size, ((const AuSPtr<Heap> &,pHead), (LeakFinderAlloc_f, pfAlloc), (LeakFinderFree_f, pfFree)), const AuSPtr<Heap> &pHead, LeakFinderAlloc_f pfAlloc, LeakFinderFree_f pfFree);
|
||||
}
|
@ -32,26 +32,26 @@ namespace Aurora::Memory
|
||||
LeakFinderFree_f pFree);
|
||||
|
||||
// thread-local
|
||||
AUKN_SYM void SetMemoryLowNotification(MemoryLowNotification_f pFunc);
|
||||
AUKN_SYM void SetMemoryLowNotification(MemoryLowNotification_f pFunc);
|
||||
|
||||
AUKN_SYM void ReserveHeapMemory(AuUInt uHeapSize, bool bCommit = true);
|
||||
|
||||
AUKN_SYM AU_ALLOC void *_ZAlloc(Types::size_t length);
|
||||
AUKN_SYM AU_ALLOC void *_ZAlloc(Types::size_t length, Types::size_t align);
|
||||
AUKN_SYM AU_ALLOC void *_FAlloc(Types::size_t length);
|
||||
AUKN_SYM AU_ALLOC void *_FAlloc(Types::size_t length, Types::size_t align);
|
||||
AUKN_SYM AU_ALLOC void *_ZRealloc(void *buffer, Types::size_t length, Types::size_t align);
|
||||
AUKN_SYM AU_ALLOC void *_ZRealloc(void *buffer, Types::size_t length);
|
||||
AUKN_SYM AU_ALLOC void *_FRealloc(void *buffer, Types::size_t length, Types::size_t align);
|
||||
AUKN_SYM AU_ALLOC void *_FRealloc(void *buffer, Types::size_t length);
|
||||
AUKN_SYM AU_ALLOC void *_ZAlloc(Types::size_t uLength);
|
||||
AUKN_SYM AU_ALLOC void *_ZAlloc(Types::size_t uLength, Types::size_t uAlignment);
|
||||
AUKN_SYM AU_ALLOC void *_FAlloc(Types::size_t uLength);
|
||||
AUKN_SYM AU_ALLOC void *_FAlloc(Types::size_t uLength, Types::size_t uAlignment);
|
||||
AUKN_SYM AU_ALLOC void *_ZRealloc(void *buffer, Types::size_t uLength, Types::size_t uAlignment);
|
||||
AUKN_SYM AU_ALLOC void *_ZRealloc(void *buffer, Types::size_t uLength);
|
||||
AUKN_SYM AU_ALLOC void *_FRealloc(void *buffer, Types::size_t uLength, Types::size_t uAlignment);
|
||||
AUKN_SYM AU_ALLOC void *_FRealloc(void *buffer, Types::size_t uLength);
|
||||
AUKN_SYM void _Free(void *buffer);
|
||||
|
||||
AUKN_SYM AuUInt GetChunkSize(const void *head);
|
||||
AUKN_SYM AuUInt GetPageSize();
|
||||
|
||||
static void *__FAlloc(Types::size_t length, Types::size_t align)
|
||||
static void *__FAlloc(Types::size_t uLength, Types::size_t uAlignment)
|
||||
{
|
||||
return _FAlloc(length, align);
|
||||
return _FAlloc(uLength, uAlignment);
|
||||
}
|
||||
|
||||
static void __Free(void *buffer)
|
||||
@ -59,89 +59,126 @@ namespace Aurora::Memory
|
||||
_Free(buffer);
|
||||
}
|
||||
|
||||
|
||||
// These memory management APIs do not support class types, and will likely *never* support them
|
||||
// QST already handles dynamic allocation of structs in a given heap properly (afaik)
|
||||
// _new, new, et al are backed by operator overloads directed towards these functions
|
||||
// -> do not double init
|
||||
// TODO: ensure typeof(T) is not a pointer of a class
|
||||
|
||||
#if !defined(_CPPSHARP)
|
||||
|
||||
template<typename T>
|
||||
T ZAlloc(Types::size_t length)
|
||||
template<typename T = void *>
|
||||
T ZAlloc(Types::size_t uLength)
|
||||
{
|
||||
static_assert(!AuIsClass_v<AuRemovePointer_t<T>>, "Do not use heap/kmem apis with classes");
|
||||
return reinterpret_cast<T>(_ZAlloc(length));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T ZAlloc(Types::size_t length, Types::size_t align)
|
||||
{
|
||||
static_assert(!AuIsClass_v<AuRemovePointer_t<T>>, "Do not use heap/kmem apis with classes");
|
||||
return reinterpret_cast<T>(_ZAlloc(length, align));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *NewArray(Types::size_t count)
|
||||
{
|
||||
static_assert(!AuIsClass_v<T>, "Do not use heap/kmem apis with classes");
|
||||
return reinterpret_cast<T *>(_FAlloc(count * sizeof(T)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *NewArray(Types::size_t count, Types::size_t align)
|
||||
{
|
||||
static_assert(!AuIsClass_v<T>, "Do not use heap/kmem apis with classes");
|
||||
return reinterpret_cast<T *>(_FAlloc(count * sizeof(T)), align);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
AuSPtr<T> AllocateFastArray(Types::size_t length, Types::size_t align = sizeof(T))
|
||||
{
|
||||
static_assert(!AuIsClass_v<AuRemovePointer_t<T>>, "Do not use heap/kmem apis with classes");
|
||||
return AuSPtr<T>(reinterpret_cast<T *>(_FAlloc(length)), [](T *ptr)
|
||||
static_assert((!AuIsClass_v<AuRemovePointer_t<T>> || (AuIsTriviallyConstructible_v<AuRemovePointer_t<T>> && AuIsTriviallyDestructible_v<AuRemovePointer_t<T>>)),
|
||||
"Do not use heap/kmem apis with classes. Use AuNewClass[Unique]");
|
||||
if constexpr (AuIsVoid_v<AuRemovePointer_t<T>>)
|
||||
{
|
||||
_Free(ptr);
|
||||
});
|
||||
return reinterpret_cast<T>(_ZAlloc(uLength));
|
||||
}
|
||||
else
|
||||
{
|
||||
return reinterpret_cast<T>(_ZAlloc(uLength, alignof(AuRemovePointer_t<T>)));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T = void *>
|
||||
T ZAlloc(Types::size_t uLength, Types::size_t uAlignment)
|
||||
{
|
||||
static_assert((!AuIsClass_v<T> || (AuIsTriviallyConstructible_v<T> && AuIsTriviallyDestructible_v<T>)),
|
||||
"Do not use heap/kmem apis with classes. Use AuNewClass[Unique] instead");
|
||||
return reinterpret_cast<T>(_ZAlloc(uLength, uAlignment));
|
||||
}
|
||||
|
||||
template<typename T = void *>
|
||||
T FAlloc(Types::size_t uLength)
|
||||
{
|
||||
static_assert((!AuIsClass_v<AuRemovePointer_t<T>> || (AuIsTriviallyConstructible_v<AuRemovePointer_t<T>> && AuIsTriviallyDestructible_v<AuRemovePointer_t<T>>)),
|
||||
"Do not use heap/kmem apis with classes. Use AuNewClass[Unique]");
|
||||
if constexpr (AuIsVoid_v<AuRemovePointer_t<T>>)
|
||||
{
|
||||
return reinterpret_cast<T>(_FAlloc(uLength));
|
||||
}
|
||||
else
|
||||
{
|
||||
return reinterpret_cast<T>(_FAlloc(uLength, alignof(AuRemovePointer_t<T>)));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T = void *>
|
||||
T FAlloc(Types::size_t uLength, Types::size_t uAlignment)
|
||||
{
|
||||
static_assert((!AuIsClass_v<T> || (AuIsTriviallyConstructible_v<T> && AuIsTriviallyDestructible_v<T>)),
|
||||
"Do not use heap/kmem apis with classes. Use AuNewClass[Unique] instead");
|
||||
return reinterpret_cast<T>(_FAlloc(uLength, uAlignment));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T FAlloc(Types::size_t length)
|
||||
T *ZAlloc()
|
||||
{
|
||||
static_assert(!AuIsClass_v<AuRemovePointer_t<T>>, "Do not use heap/kmem apis with classes");
|
||||
return reinterpret_cast<T>(_FAlloc(length));
|
||||
return ZAlloc<T *>(sizeof(T), alignof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T FAlloc(Types::size_t length, Types::size_t align)
|
||||
T *FAlloc()
|
||||
{
|
||||
static_assert(!AuIsClass_v<AuRemovePointer_t<T>>, "Do not use heap/kmem apis with classes");
|
||||
return reinterpret_cast<T>(_FAlloc(length, align));
|
||||
return FAlloc<T *>(sizeof(T), alignof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T ZRealloc(T in, Types::size_t length)
|
||||
T *NewArray(Types::size_t uCount)
|
||||
{
|
||||
return reinterpret_cast<T>(_ZRealloc(reinterpret_cast<void *>(in), length));
|
||||
static_assert((!AuIsClass_v<T> || (AuIsTriviallyConstructible_v<T> && AuIsTriviallyDestructible_v<T>)),
|
||||
"Do not use heap/kmem apis with classes. Use AuNewClassArray[Unique] instead");
|
||||
return reinterpret_cast<T *>(_FAlloc(uCount * sizeof(T), alignof(T)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T ZRealloc(T in, Types::size_t length, Types::size_t alloc)
|
||||
T *NewArray(Types::size_t uCount, Types::size_t uAlignment)
|
||||
{
|
||||
return reinterpret_cast<T>(_ZRealloc(reinterpret_cast<void *>(in), length), alloc);
|
||||
static_assert((!AuIsClass_v<T> || (AuIsTriviallyConstructible_v<T> && AuIsTriviallyDestructible_v<T>)),
|
||||
"Do not use heap/kmem apis with classes. Use AuNewClassArray[Unique] instead");
|
||||
return reinterpret_cast<T *>(_FAlloc(uCount * sizeof(T), uAlignment));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T FRealloc(T in, Types::size_t length)
|
||||
AuSPtr<T> AllocateFastArray(Types::size_t uLength, Types::size_t uAlignment = alignof(T))
|
||||
{
|
||||
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(in), length));
|
||||
static_assert((!AuIsClass_v<T> || (AuIsTriviallyConstructible_v<T> && AuIsTriviallyDestructible_v<T>)),
|
||||
"Do not use heap/kmem apis with classes. Use AuNewClassArray instead");
|
||||
return AuSPtr<T>(reinterpret_cast<T *>(_FAlloc(uLength, uAlignment)), &_Free);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T FRealloc(T in, Types::size_t length, Types::size_t alloc)
|
||||
T FRealloc(T in, Types::size_t uLength)
|
||||
{
|
||||
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(in), length), alloc);
|
||||
if constexpr (AuIsVoid_v<AuRemovePointer_t<T>>)
|
||||
{
|
||||
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(in), uLength));
|
||||
}
|
||||
else
|
||||
{
|
||||
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(in), uLength, alignof(AuRemovePointer_t<T>)));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T ZRealloc(T in, Types::size_t uLength)
|
||||
{
|
||||
if constexpr (AuIsVoid_v<AuRemovePointer_t<T>>)
|
||||
{
|
||||
return reinterpret_cast<T>(_ZRealloc(reinterpret_cast<void *>(in), uLength));
|
||||
}
|
||||
else
|
||||
{
|
||||
return reinterpret_cast<T>(_ZRealloc(reinterpret_cast<void *>(in), uLength, alignof(AuRemovePointer_t<T>)));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T ZRealloc(T in, Types::size_t uLength, Types::size_t uAlignment)
|
||||
{
|
||||
return reinterpret_cast<T>(_ZRealloc(reinterpret_cast<void *>(in), uLength, uAlignment));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T FRealloc(T in, Types::size_t uLength, Types::size_t uAlignment)
|
||||
{
|
||||
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(in), uLength, uAlignment));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -26,6 +26,11 @@ extern "C"
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
AuUInt32 RoundPageUp(AuUInt32 value);
|
||||
}
|
||||
|
||||
namespace Aurora
|
||||
{
|
||||
static bool gShouldResPathDoNothing {};
|
||||
@ -778,4 +783,15 @@ namespace Aurora
|
||||
|
||||
return length.QuadPart;
|
||||
}
|
||||
|
||||
void *SysAllocateLarge(AuUInt uLength)
|
||||
{
|
||||
uLength = AuMemory::RoundPageUp(uLength);
|
||||
return VirtualAlloc(nullptr, uLength, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
void SysAllocateFree(void *pBuffer, AuUInt uLength)
|
||||
{
|
||||
VirtualFree(pBuffer, 0, MEM_RELEASE);
|
||||
}
|
||||
}
|
@ -8,12 +8,18 @@
|
||||
#include "RuntimeInternal.hpp"
|
||||
#include "AuProcAddresses.UNIX.hpp"
|
||||
#include <Source/Debug/ExceptionWatcher.Unix.hpp>
|
||||
#include <sys/mman.h>
|
||||
|
||||
namespace Aurora::Process
|
||||
{
|
||||
void PosixForkResetLocks();
|
||||
}
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
AuUInt32 RoundPageUp(AuUInt32 value);
|
||||
}
|
||||
|
||||
namespace Aurora
|
||||
{
|
||||
int PosixOpen(const char *pathname, int flags, mode_t mode)
|
||||
@ -159,4 +165,16 @@ namespace Aurora
|
||||
{
|
||||
return PosixGetLength(uOSHandle);
|
||||
}
|
||||
|
||||
void *SysAllocateLarge(AuUInt uLength)
|
||||
{
|
||||
uLength = AuMemory::RoundPageUp(uLength);
|
||||
return ::mmap(0, uLength, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
|
||||
void SysAllocateFree(void *pBuffer, AuUInt uLength)
|
||||
{
|
||||
uLength = AuMemory::RoundPageUp(uLength);
|
||||
::munmap(pBuffer, uLength);
|
||||
}
|
||||
}
|
@ -6,10 +6,8 @@
|
||||
Author: Reece
|
||||
***/
|
||||
#include <RuntimeInternal.hpp>
|
||||
#include "AuProcAddresses.hpp"
|
||||
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
#include "AuProcAddresses.NT.hpp"
|
||||
#endif
|
||||
|
||||
namespace Aurora
|
||||
{
|
||||
@ -29,4 +27,18 @@ namespace Aurora
|
||||
InitLinuxAddresses();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(AURORA_HAS_SYS_ALLOC_LARGE)
|
||||
|
||||
void *SysAllocateLarge(AuUInt uLength)
|
||||
{
|
||||
return AuMemory::FAlloc<void *>(uLength, 32);
|
||||
}
|
||||
|
||||
void SysAllocateFree(void *pBuffer, AuUInt uLength)
|
||||
{
|
||||
AuMemory::Free(pBuffer);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
@ -47,4 +47,14 @@ namespace Aurora
|
||||
void SysWakeAllOnAddress(const void *pAddress);
|
||||
|
||||
AuUInt64 SysGetFileLength(AuUInt uOSHandle);
|
||||
}
|
||||
|
||||
void *SysAllocateLarge(AuUInt uLength);
|
||||
|
||||
void SysAllocateFree(void *pBuffer, AuUInt uLength);
|
||||
}
|
||||
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED) || defined(AURORA_IS_POSIX_DERIVED)
|
||||
#if !defined(AURORA_HAS_SYS_ALLOC_LARGE)
|
||||
#define AURORA_HAS_SYS_ALLOC_LARGE
|
||||
#endif
|
||||
#endif
|
@ -38,7 +38,7 @@
|
||||
#include "CmdLine/AuCmdLine.hpp"
|
||||
#include "Grug/AuGrug.hpp"
|
||||
#include "Threading/AuSleep.hpp"
|
||||
#include "Memory/Cache.hpp"
|
||||
#include "Memory/AuMemoryCache.hpp"
|
||||
#include "Threading/Primitives/SMTYield.hpp"
|
||||
#include <mimalloc.h>
|
||||
#include "Process/AuProcessStartTime.hpp"
|
||||
|
@ -8,27 +8,29 @@
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "Debug.hpp"
|
||||
#include "ErrorStack.hpp"
|
||||
#include <Source/Memory/Heap.hpp>
|
||||
#include <Source/Memory/AuHeap.hpp>
|
||||
#include <Source/Memory/AuBaseHeap.hpp>
|
||||
|
||||
namespace Aurora::Debug
|
||||
{
|
||||
static thread_local AuSInt tlsMemoryCrunchCounter;
|
||||
static auto const kAutoReservePool = 3 * 1024 * 1024;
|
||||
static auto const kDefaultReservePool = 3 * 1024 * 1024;
|
||||
|
||||
AuUInt8 *gReservePoolStart {};
|
||||
AuUInt8 *gReservePoolEnd {};
|
||||
// Extern defintions
|
||||
AuUInt8 *gReservePoolStart {};
|
||||
AuUInt8 *gReservePoolEnd {};
|
||||
AuSPtr<AuMemory::Heap> gReserveHeap {};
|
||||
|
||||
void InitMemoryCrunch()
|
||||
{
|
||||
gReserveHeap = AuMemory::AllocHeapShared(gRuntimeConfig.debug.uDebugMemoryReserveSize ?
|
||||
gRuntimeConfig.debug.uDebugMemoryReserveSize :
|
||||
kAutoReservePool);
|
||||
kDefaultReservePool);
|
||||
SysAssert(gReserveHeap);
|
||||
|
||||
auto pHeap = AuStaticCast<AuMemory::BaseHeap>(gReserveHeap);
|
||||
gReservePoolStart = AuReinterpretCast<AuUInt8 *>(pHeap->base_);
|
||||
gReservePoolEnd = AuReinterpretCast<AuUInt8 *>(pHeap->base_) + pHeap->length_;
|
||||
gReservePoolStart = AuReinterpretCast<AuUInt8 *>(pHeap->GetHeapBase());
|
||||
gReservePoolEnd = AuReinterpretCast<AuUInt8 *>(gReservePoolStart) + pHeap->GetHeapLength();
|
||||
}
|
||||
|
||||
bool IsPointerReserveRange(void *ptr)
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
namespace Aurora::HWInfo
|
||||
{
|
||||
inline AuUInt32 gPageSize;
|
||||
inline AuUInt32 gPageSize { 4096 }; // harden: specify default value in case of early access
|
||||
|
||||
template<typename T>
|
||||
AuOptional<T> QueryBsdHwStat(int id);
|
||||
|
28
Source/Memory/AuBaseHeap.cpp
Normal file
28
Source/Memory/AuBaseHeap.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
/***
|
||||
Copyright (C) 2021-2024 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: AuBaseHeap.cpp
|
||||
Date: 2021-6-12
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "AuBaseHeap.hpp"
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
HeapStats &BaseHeap::GetStats()
|
||||
{
|
||||
UpdateStats();
|
||||
return stats;
|
||||
}
|
||||
|
||||
void *BaseHeap::GetHeapBase()
|
||||
{
|
||||
return this->pBase_;
|
||||
}
|
||||
|
||||
AuUInt BaseHeap::GetHeapLength()
|
||||
{
|
||||
return this->uLength_;
|
||||
}
|
||||
}
|
28
Source/Memory/AuBaseHeap.hpp
Normal file
28
Source/Memory/AuBaseHeap.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
/***
|
||||
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: AuBaseHeap.hpp
|
||||
Date: 2021-6-12
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
struct BaseHeap : Heap
|
||||
{
|
||||
virtual void UpdateStats() = 0;
|
||||
|
||||
HeapStats &GetStats() override;
|
||||
|
||||
void *GetHeapBase();
|
||||
AuUInt GetHeapLength();
|
||||
|
||||
protected:
|
||||
HeapStats stats;
|
||||
|
||||
protected:
|
||||
void *pBase_ {};
|
||||
AuUInt uLength_ {};
|
||||
};
|
||||
}
|
144
Source/Memory/AuDefaultHeap.cpp
Normal file
144
Source/Memory/AuDefaultHeap.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
/***
|
||||
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: AuDefaultHeap.cpp
|
||||
Date: 2021-6-13
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "AuDefaultHeap.hpp"
|
||||
#include "AuHeap.hpp"
|
||||
#include <Source/Debug/MemoryCrunch.hpp>
|
||||
#include <mimalloc.h>
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
AuSPtr<Heap> DefaultHeap::AllocateDivision(AuUInt32 heap, AuUInt32 alignment)
|
||||
{
|
||||
return AllocateDivisionGlobal(this, heap, alignment);
|
||||
}
|
||||
|
||||
void *DefaultHeap::_ZAlloc(Types::size_t length)
|
||||
{
|
||||
return AuMemory::_ZAlloc(length);
|
||||
}
|
||||
|
||||
void *DefaultHeap::_ZAlloc(Types::size_t length, Types::size_t align)
|
||||
{
|
||||
return AuMemory::_ZAlloc(length, align);
|
||||
}
|
||||
|
||||
Types::size_t DefaultHeap::GetChunkSize(const void *head)
|
||||
{
|
||||
return AuMemory::GetChunkSize(head);
|
||||
}
|
||||
|
||||
void *DefaultHeap::_FAlloc(Types::size_t length)
|
||||
{
|
||||
return AuMemory::_FAlloc(length);
|
||||
}
|
||||
|
||||
void *DefaultHeap::_FAlloc(Types::size_t length, Types::size_t align)
|
||||
{
|
||||
return AuMemory::_FAlloc(length, align);
|
||||
}
|
||||
|
||||
void *DefaultHeap::_ZRealloc(void *buffer, Types::size_t length, Types::size_t align)
|
||||
{
|
||||
return AuMemory::_ZRealloc(buffer, length, align);
|
||||
}
|
||||
|
||||
void *DefaultHeap::_ZRealloc(void *buffer, Types::size_t length)
|
||||
{
|
||||
return AuMemory::_ZRealloc(buffer, length);
|
||||
}
|
||||
|
||||
void *DefaultHeap::_FRealloc(void *buffer, Types::size_t length, Types::size_t align)
|
||||
{
|
||||
return AuMemory::_FRealloc(buffer, length, align);
|
||||
}
|
||||
|
||||
void *DefaultHeap::_FRealloc(void *buffer, Types::size_t length)
|
||||
{
|
||||
return AuMemory::_FRealloc(buffer, length);
|
||||
}
|
||||
|
||||
void DefaultHeap::_Free(void *buffer)
|
||||
{
|
||||
return AuMemory::_Free(buffer);
|
||||
}
|
||||
|
||||
AuSPtr<Heap> DefaultHeap::GetSelfReference()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
Heap *DefaultHeap::GetSelfReferenceRaw()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
struct WalkInstance
|
||||
{
|
||||
bool(*fCallback)(void *, void *);
|
||||
void *pSecondArg;
|
||||
};
|
||||
|
||||
static bool mi_block_visit_funHandler(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *arg)
|
||||
{
|
||||
auto pWalkInstance = (WalkInstance *)arg;
|
||||
if (!block)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!area->used)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
for (AU_ITERATE_N(i, area->used))
|
||||
{
|
||||
if (!pWalkInstance->fCallback(((AuUInt *)block) + (i * area->block_size), pWalkInstance->pSecondArg))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
return pWalkInstance->fCallback(block, pWalkInstance->pSecondArg);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void DefaultHeap::WalkHeap(bool(*fCallback)(void *, void*), void *pSecondArg)
|
||||
{
|
||||
WalkInstance inst;
|
||||
inst.fCallback = fCallback;
|
||||
inst.pSecondArg = pSecondArg;
|
||||
mi_heap_visit_blocks(mi_heap_get_default(), true , &mi_block_visit_funHandler, &inst);
|
||||
}
|
||||
|
||||
void DefaultHeap::UpdateStats()
|
||||
{
|
||||
auto other = AuDebug::gReserveHeap->GetStats();
|
||||
|
||||
this->stats.bIsSharedWithOtherHeaps = true;
|
||||
this->stats.uBytesLiveCounter = gBytesCounterAllocated + other.uBytesLiveCounter;
|
||||
this->stats.uBytesPeakCounter = AuMax(gBytesCounterPeak, other.uBytesPeakCounter);
|
||||
|
||||
if (!this->stats.uBytesCapacity)
|
||||
{
|
||||
this->stats.uBytesCapacity = Aurora::HWInfo::GetMemStatSystem /*should be process, but process is this with extra steps.*/().value_or(AuHwInfo::RamStat { }).qwAvailable;
|
||||
}
|
||||
}
|
||||
|
||||
static DefaultHeap gDefaultAllocation;
|
||||
|
||||
AUKN_SYM Heap *DefaultDiscontiguousHeapNew()
|
||||
{
|
||||
return &gDefaultAllocation;
|
||||
}
|
||||
|
||||
AUKN_SYM void DefaultDiscontiguousHeapRelease(Heap * heap) {}
|
||||
}
|
34
Source/Memory/AuDefaultHeap.hpp
Normal file
34
Source/Memory/AuDefaultHeap.hpp
Normal file
@ -0,0 +1,34 @@
|
||||
/***
|
||||
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: AuDefaultHeap.hpp
|
||||
Date: 2021-6-13
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
#include "AuBaseHeap.hpp"
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
struct DefaultHeap : BaseHeap
|
||||
{
|
||||
AuSPtr<Heap> AllocateDivision(AuUInt32 heap, AuUInt32 alignment) override;
|
||||
void *_ZAlloc(Types::size_t length) override;
|
||||
void *_ZAlloc(Types::size_t length, Types::size_t align) override;
|
||||
Types::size_t GetChunkSize(const void *head) override;
|
||||
void *_FAlloc(Types::size_t length) override;
|
||||
void *_FAlloc(Types::size_t length, Types::size_t align) override;
|
||||
void *_ZRealloc(void *buffer, Types::size_t length, Types::size_t align) override;
|
||||
void *_ZRealloc(void *buffer, Types::size_t length) override;
|
||||
void *_FRealloc(void *buffer, Types::size_t length, Types::size_t align) override;
|
||||
void *_FRealloc(void *buffer, Types::size_t length) override;
|
||||
void _Free(void *buffer) override;
|
||||
|
||||
AuSPtr<Heap> GetSelfReference() override;
|
||||
Heap *GetSelfReferenceRaw() override;
|
||||
|
||||
void WalkHeap(bool(*fCallback)(void *, void *), void *pSecondArg) override;
|
||||
void UpdateStats() override;
|
||||
};
|
||||
}
|
17
Source/Memory/AuHeap.cpp
Normal file
17
Source/Memory/AuHeap.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
/***
|
||||
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: AuHeap.cpp
|
||||
Date: 2021-6-12
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "AuHeap.hpp"
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
AuUInt32 RoundPageUp(AuUInt32 uLength)
|
||||
{
|
||||
return AuPageRoundUp(uLength, HWInfo::GetPageSize());
|
||||
}
|
||||
}
|
18
Source/Memory/AuHeap.hpp
Normal file
18
Source/Memory/AuHeap.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
/***
|
||||
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: AuHeap.hpp
|
||||
Date: 2021-6-12
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
#include "AuMemory.hpp"
|
||||
#include "AuBaseHeap.hpp"
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
AuUInt32 RoundPageUp(AuUInt32 value);
|
||||
|
||||
AuSPtr<Heap> AllocateDivisionGlobal(Heap *heap, AuUInt32 length, AuUInt32 alignment);
|
||||
}
|
28
Source/Memory/AuHeapDeletable.cpp
Normal file
28
Source/Memory/AuHeapDeletable.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
/***
|
||||
Copyright (C) 2021-2024 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: AuHeapDeletable.cpp
|
||||
File: AuHeap.cpp
|
||||
Date: 2021-6-12
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "AuHeapDeletable.hpp"
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
DeletableHeap::DeletableHeap(Heap *parent, void *ptr) :
|
||||
pParent(pParent),
|
||||
ptr2_(ptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DeletableHeap::~DeletableHeap()
|
||||
{
|
||||
if (this->ptr2_)
|
||||
{
|
||||
pParent->Free(this->ptr2_);
|
||||
}
|
||||
}
|
||||
}
|
23
Source/Memory/AuHeapDeletable.hpp
Normal file
23
Source/Memory/AuHeapDeletable.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
/***
|
||||
Copyright (C) 2021-2024 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: AuHeapDeletable.hpp
|
||||
File: Heap.hpp
|
||||
Date: 2021-6-12
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
#include "AuHeapInternal.hpp"
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
struct DeletableHeap : InternalHeap
|
||||
{
|
||||
Heap *pParent {};
|
||||
void *ptr2_ {};
|
||||
|
||||
DeletableHeap(Heap *pParent, void *ptr);
|
||||
~DeletableHeap();
|
||||
};
|
||||
}
|
349
Source/Memory/AuHeapInternal.cpp
Normal file
349
Source/Memory/AuHeapInternal.cpp
Normal file
@ -0,0 +1,349 @@
|
||||
/***
|
||||
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() :
|
||||
heap_(nullptr),
|
||||
count_(0)
|
||||
{ }
|
||||
|
||||
InternalHeap::InternalHeap(const MemoryViewWrite &memory)
|
||||
{
|
||||
SysAssert(this->Init(memory.length, memory.ptr));
|
||||
}
|
||||
|
||||
InternalHeap::InternalHeap(AuUInt uLength)
|
||||
{
|
||||
SysAssert(this->Init(uLength), "Couldn't initialize inline AuHeap! [OOM]");
|
||||
}
|
||||
|
||||
InternalHeap::~InternalHeap()
|
||||
{
|
||||
SysAssertDbgExp(this->count_ == 0);
|
||||
|
||||
if (this->pBase_)
|
||||
{
|
||||
if (this->heap_)
|
||||
{
|
||||
this->heap_ = nullptr;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!(this->heap_ = o1heapInit(this->pBase_, uLength)))
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (!this->heap_)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto ret = o1heapAllocate(this->heap_, uLength);
|
||||
if (ret)
|
||||
{
|
||||
AuAtomicAdd(&this->count_, 1);
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (!this->heap_)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
o1heapFree(this->heap_, pBuffer);
|
||||
DecrementUsers();
|
||||
}
|
||||
|
||||
void InternalHeap::DecrementUsers()
|
||||
{
|
||||
if (AuAtomicSub(&this->count_, 1) == 0)
|
||||
{
|
||||
TryRelease();
|
||||
}
|
||||
}
|
||||
|
||||
void InternalHeap::TryRelease()
|
||||
{
|
||||
if (!this->bIsDangling_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (count_ == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
void InternalHeap::RequestTermination()
|
||||
{
|
||||
if (AuAtomicLoad(&this->count_))
|
||||
{
|
||||
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()
|
||||
{
|
||||
auto pDiag = o1heapGetDiagnostics(this->heap_);
|
||||
|
||||
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)
|
||||
{
|
||||
o1heapTraverseHeap(this->heap_, fCallback, pSecondArg);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!pHeap->Init(memory.length, memory.ptr))
|
||||
{
|
||||
delete pHeap;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return pHeap;
|
||||
}
|
||||
|
||||
AUKN_SYM void RequestHeapOfRegionRelease(Heap *pHeap)
|
||||
{
|
||||
static_cast<InternalHeap *>(pHeap)->RequestTermination();
|
||||
}
|
||||
|
||||
AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, RequestHeapOfRegion, InternalHeap, (const MemoryViewWrite &, memory))
|
||||
AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, AllocHeap, InternalHeap, (AuUInt, uLength))
|
||||
}
|
64
Source/Memory/AuHeapInternal.hpp
Normal file
64
Source/Memory/AuHeapInternal.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
/***
|
||||
Copyright (C) 2021-2024 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: AuHeapInternal.hpp
|
||||
File: Heap.hpp
|
||||
Date: 2021-6-12
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
#include "AuMemory.hpp"
|
||||
#include "AuBaseHeap.hpp"
|
||||
|
||||
#include "o1heap.hpp"
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
struct InternalHeap :
|
||||
BaseHeap,
|
||||
AuEnableSharedFromThis<InternalHeap>
|
||||
{
|
||||
virtual AuSPtr<Heap> AllocateDivision(AuUInt32 heap, AuUInt32 alignment) override;
|
||||
|
||||
InternalHeap();
|
||||
InternalHeap(const MemoryViewWrite &memory);
|
||||
InternalHeap(AuUInt uLength);
|
||||
virtual ~InternalHeap();
|
||||
|
||||
bool Init(AuUInt uLength, void *ptr = nullptr);
|
||||
|
||||
static AuUInt GetHeapSize(const void *ptr);
|
||||
|
||||
Types::size_t GetChunkSize(const void *head) override;
|
||||
|
||||
void *_FAlloc(Types::size_t uLength) override;
|
||||
void *_FAlloc(Types::size_t uLength, Types::size_t uAlign) override;
|
||||
void *_ZAlloc(Types::size_t uLength) override;
|
||||
void *_ZAlloc(Types::size_t uLength, Types::size_t uAlign) override;
|
||||
void *_ZRealloc(void *pBuffer, Types::size_t uLength) override;
|
||||
void *_ZRealloc(void *pBuffer, Types::size_t uLength, Types::size_t uAlign) override;
|
||||
void *_FRealloc(void *pBuffer, Types::size_t uLength) override;
|
||||
void *_FRealloc(void *pBuffer, Types::size_t uLength, Types::size_t uAlign) override;
|
||||
void _Free(void *pBuffer) override;
|
||||
AuSPtr<Heap> GetSelfReference() override;
|
||||
Heap *GetSelfReferenceRaw() override;
|
||||
|
||||
void TryRelease();
|
||||
void DecrementUsers();
|
||||
void RequestTermination();
|
||||
|
||||
void UpdateStats() override;
|
||||
|
||||
void WalkHeap(bool(*fCallback)(void *, void *), void *pSecondArg) override;
|
||||
|
||||
private:
|
||||
O1HeapInstance *heap_ {};
|
||||
int count_ {};
|
||||
bool bIsDangling_ {};
|
||||
|
||||
protected:
|
||||
bool bOwnsMemory_ {};
|
||||
|
||||
};
|
||||
}
|
@ -1,14 +1,13 @@
|
||||
/***
|
||||
Copyright (C) 2024 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: HeapProxy.cpp
|
||||
File: AuHeapProxy.cpp
|
||||
Date: 2024-1-16
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "Memory.hpp"
|
||||
#include "Heap.hpp"
|
||||
#include "HeapProxy.hpp"
|
||||
#include "AuHeap.hpp"
|
||||
#include "AuHeapProxy.hpp"
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
@ -58,9 +57,9 @@ namespace Aurora::Memory
|
||||
}
|
||||
}
|
||||
|
||||
void *ProxyHeap::_ZAlloc(Types::size_t uLength, Types::size_t align)
|
||||
void *ProxyHeap::_ZAlloc(Types::size_t uLength, Types::size_t uAlign)
|
||||
{
|
||||
if (auto pThat = this->pHeap->ZAlloc(uLength, align))
|
||||
if (auto pThat = this->pHeap->ZAlloc(uLength, uAlign))
|
||||
{
|
||||
auto uLengthCurrent = this->GetChunkSize(pThat);
|
||||
AuAtomicAdd(&this->uBytesLifetime, uLengthCurrent);
|
||||
@ -103,9 +102,9 @@ namespace Aurora::Memory
|
||||
}
|
||||
}
|
||||
|
||||
void *ProxyHeap::_FAlloc(Types::size_t uLength, Types::size_t align)
|
||||
void *ProxyHeap::_FAlloc(Types::size_t uLength, Types::size_t uAlign)
|
||||
{
|
||||
if (auto pThat = this->pHeap->_FAlloc(uLength, align))
|
||||
if (auto pThat = this->pHeap->_FAlloc(uLength, uAlign))
|
||||
{
|
||||
auto uLengthCurrent = this->GetChunkSize(pThat);
|
||||
AuAtomicAdd(&this->uBytesLifetime, uLengthCurrent);
|
||||
@ -123,13 +122,13 @@ namespace Aurora::Memory
|
||||
}
|
||||
}
|
||||
|
||||
void *ProxyHeap::_ZRealloc(void *pHead, Types::size_t uLength, Types::size_t align)
|
||||
void *ProxyHeap::_ZRealloc(void *pHead, Types::size_t uLength, Types::size_t uAlign)
|
||||
{
|
||||
if (pHead)
|
||||
{
|
||||
auto uLengthCurrent = this->GetChunkSize(pHead);
|
||||
|
||||
if (auto pThat = this->pHeap->_ZRealloc(pHead, uLength, align))
|
||||
if (auto pThat = this->pHeap->_ZRealloc(pHead, uLength, uAlign))
|
||||
{
|
||||
auto uLengthNext = this->GetChunkSize(pThat);
|
||||
AuAtomicAdd(&this->uBytesFree, uLengthCurrent);
|
||||
@ -185,13 +184,13 @@ namespace Aurora::Memory
|
||||
}
|
||||
}
|
||||
|
||||
void *ProxyHeap::_FRealloc(void *pHead, Types::size_t uLength, Types::size_t align)
|
||||
void *ProxyHeap::_FRealloc(void *pHead, Types::size_t uLength, Types::size_t uAlign)
|
||||
{
|
||||
if (pHead)
|
||||
{
|
||||
auto uLengthCurrent = this->GetChunkSize(pHead);
|
||||
|
||||
if (auto pThat = this->pHeap->_FRealloc(pHead, uLength, align))
|
||||
if (auto pThat = this->pHeap->_FRealloc(pHead, uLength, uAlign))
|
||||
{
|
||||
auto uLengthNext = this->GetChunkSize(pThat);
|
||||
AuAtomicAdd(&this->uBytesFree, uLengthCurrent);
|
||||
@ -329,4 +328,8 @@ namespace Aurora::Memory
|
||||
{
|
||||
AuSafeDelete<ProxyHeap *>(heap);
|
||||
}
|
||||
|
||||
AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, HeapProxy, ProxyHeap, (const AuSPtr<Heap> &, pHead))
|
||||
|
||||
AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, HeapProxyEx, ProxyHeap, (const AuSPtr<Heap> &, pHead), (LeakFinderAlloc_f, pfAlloc), (LeakFinderFree_f, pfFree))
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/***
|
||||
Copyright (C) 2024 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: HeapProxy.hpp
|
||||
File: AuHeapProxy.hpp
|
||||
Date: 2024-1-16
|
||||
Author: Reece
|
||||
***/
|
@ -1,19 +1,14 @@
|
||||
/***
|
||||
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Memory.cpp
|
||||
File: AuMemory.cpp
|
||||
Date: 2021-6-12
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "Memory.hpp"
|
||||
#include "AuMemory.hpp"
|
||||
#include <mimalloc.h>
|
||||
#include <Source/HWInfo/AuHWInfo.hpp>
|
||||
|
||||
#if defined(AURORA_IS_LINUX_DERIVED)
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include <Source/Debug/MemoryCrunch.hpp>
|
||||
#include <Source/Debug/ErrorStack.hpp>
|
||||
|
||||
@ -23,10 +18,10 @@ namespace Aurora::Memory
|
||||
AuUInt gBytesCounterPeak {};
|
||||
|
||||
thread_local AuInt64 tlsLastOutOfMemory {};
|
||||
thread_local MemoryLowNotification_f tlsMemoryLowNotification;
|
||||
|
||||
static LeakFinderAlloc_f gLeakFinderAlloc;
|
||||
static LeakFinderFree_f gLeakFinderFree;
|
||||
thread_local MemoryLowNotification_f tlsMemoryLowNotification;
|
||||
static LeakFinderFree_f gLeakFinderFree;
|
||||
|
||||
static void AddBytesToCounter(AuUInt uBytes)
|
||||
{
|
||||
@ -148,8 +143,7 @@ namespace Aurora::Memory
|
||||
|
||||
AUKN_SYM void *_ZRealloc(void *buffer, Types::size_t length, Types::size_t align)
|
||||
{
|
||||
SysAssertDbg(length);
|
||||
void *pRet;
|
||||
void *pRet = nullptr;
|
||||
|
||||
if (AuDebug::IsPointerReserveRange(buffer))
|
||||
{
|
||||
@ -159,9 +153,15 @@ namespace Aurora::Memory
|
||||
{
|
||||
auto oldLen = ::mi_malloc_size(buffer);
|
||||
|
||||
pRet = ::mi_rezalloc_aligned(buffer, length, align);
|
||||
|
||||
if (pRet)
|
||||
if (buffer && !length)
|
||||
{
|
||||
::mi_free(buffer);
|
||||
}
|
||||
else if (!buffer && length)
|
||||
{
|
||||
return _ZAlloc(length, align);
|
||||
}
|
||||
else if ((pRet = ::mi_rezalloc_aligned(buffer, length, align)))
|
||||
{
|
||||
auto uNewSize = ::mi_malloc_size(pRet);
|
||||
|
||||
@ -178,14 +178,12 @@ namespace Aurora::Memory
|
||||
gLeakFinderAlloc(pRet, uNewSize);
|
||||
}
|
||||
}
|
||||
else if (buffer && length)
|
||||
{
|
||||
OnOOM(length);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pRet)
|
||||
if (!pRet && buffer && length)
|
||||
{
|
||||
OnOOM(length);
|
||||
|
||||
if (gRuntimeConfig.debug.bIsMemoryErrorFatal)
|
||||
{
|
||||
SysPanic("ZAllocEx out of memory");
|
||||
@ -197,8 +195,7 @@ namespace Aurora::Memory
|
||||
|
||||
AUKN_SYM void *_ZRealloc(void *buffer, Types::size_t length)
|
||||
{
|
||||
SysAssertDbg(length);
|
||||
void *pRet;
|
||||
void *pRet = nullptr;
|
||||
|
||||
if (AuDebug::IsPointerReserveRange(buffer))
|
||||
{
|
||||
@ -208,9 +205,15 @@ namespace Aurora::Memory
|
||||
{
|
||||
auto oldLen = ::mi_malloc_size(buffer);
|
||||
|
||||
pRet = ::mi_rezalloc(buffer, length);
|
||||
|
||||
if (pRet)
|
||||
if (buffer && !length)
|
||||
{
|
||||
::mi_free(buffer);
|
||||
}
|
||||
else if (!buffer && length)
|
||||
{
|
||||
return _ZAlloc(length);
|
||||
}
|
||||
else if ((pRet = ::mi_rezalloc(buffer, length)))
|
||||
{
|
||||
auto uNewSize = ::mi_malloc_size(pRet);
|
||||
|
||||
@ -227,14 +230,12 @@ namespace Aurora::Memory
|
||||
gLeakFinderAlloc(pRet, uNewSize);
|
||||
}
|
||||
}
|
||||
else if (buffer && length)
|
||||
{
|
||||
OnOOM(length);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pRet)
|
||||
if (!pRet && buffer && length)
|
||||
{
|
||||
OnOOM(length);
|
||||
|
||||
if (gRuntimeConfig.debug.bIsMemoryErrorFatal)
|
||||
{
|
||||
SysPanic("ZAlloc out of memory");
|
||||
@ -246,8 +247,7 @@ namespace Aurora::Memory
|
||||
|
||||
AUKN_SYM void *_FRealloc(void *buffer, Types::size_t length, Types::size_t align)
|
||||
{
|
||||
SysAssertDbg(length);
|
||||
void *pRet;
|
||||
void *pRet = nullptr;
|
||||
|
||||
if (AuDebug::IsPointerReserveRange(buffer))
|
||||
{
|
||||
@ -257,9 +257,15 @@ namespace Aurora::Memory
|
||||
{
|
||||
auto oldLen = ::mi_malloc_size(buffer);
|
||||
|
||||
pRet = ::mi_realloc_aligned(buffer, length, align);
|
||||
|
||||
if (pRet)
|
||||
if (buffer && !length)
|
||||
{
|
||||
::mi_free(buffer);
|
||||
}
|
||||
else if (!buffer && length)
|
||||
{
|
||||
return _FAlloc(length, align);
|
||||
}
|
||||
else if ((pRet = ::mi_realloc_aligned(buffer, length, align)))
|
||||
{
|
||||
auto uNewSize = ::mi_malloc_size(pRet);
|
||||
|
||||
@ -276,14 +282,12 @@ namespace Aurora::Memory
|
||||
gLeakFinderAlloc(pRet, uNewSize);
|
||||
}
|
||||
}
|
||||
else if (buffer && length)
|
||||
{
|
||||
OnOOM(length);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pRet)
|
||||
if (!pRet && buffer && length)
|
||||
{
|
||||
OnOOM(length);
|
||||
|
||||
if (gRuntimeConfig.debug.bIsMemoryErrorFatal)
|
||||
{
|
||||
SysPanic("FReallocEx out of memory");
|
||||
@ -295,8 +299,7 @@ namespace Aurora::Memory
|
||||
|
||||
AUKN_SYM void *_FRealloc(void *buffer, Types::size_t length)
|
||||
{
|
||||
SysAssertDbg(length);
|
||||
void *pRet;
|
||||
void *pRet = nullptr;
|
||||
|
||||
if (AuDebug::IsPointerReserveRange(buffer))
|
||||
{
|
||||
@ -306,9 +309,15 @@ namespace Aurora::Memory
|
||||
{
|
||||
auto oldLen = ::mi_malloc_size(buffer);
|
||||
|
||||
pRet = ::mi_realloc(buffer, length);
|
||||
|
||||
if (pRet)
|
||||
if (buffer && !length)
|
||||
{
|
||||
::mi_free(buffer);
|
||||
}
|
||||
else if (!buffer && length)
|
||||
{
|
||||
return _FAlloc(length);
|
||||
}
|
||||
else if ((pRet = ::mi_realloc(buffer, length)))
|
||||
{
|
||||
auto uNewSize = ::mi_malloc_size(pRet);
|
||||
|
||||
@ -325,14 +334,12 @@ namespace Aurora::Memory
|
||||
gLeakFinderAlloc(pRet, uNewSize);
|
||||
}
|
||||
}
|
||||
else if (buffer && length)
|
||||
{
|
||||
OnOOM(length);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pRet)
|
||||
if (!pRet && buffer && length)
|
||||
{
|
||||
OnOOM(length);
|
||||
|
||||
if (gRuntimeConfig.debug.bIsMemoryErrorFatal)
|
||||
{
|
||||
SysPanic("FRealloc out of memory");
|
||||
@ -360,7 +367,6 @@ namespace Aurora::Memory
|
||||
RemoveBytesFromCounter(uCount);
|
||||
::mi_free(pHead);
|
||||
|
||||
|
||||
if (gLeakFinderFree)
|
||||
{
|
||||
gLeakFinderFree(pHead, uCount);
|
@ -1,12 +1,14 @@
|
||||
/***
|
||||
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Memory.hpp
|
||||
File: AuMemory.hpp
|
||||
Date: 2021-6-12
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
#include "AuMemory.hpp"
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
extern AuUInt gBytesCounterAllocated;
|
@ -1,13 +1,13 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Cache.cpp
|
||||
File: AuMemoryCache.cpp
|
||||
Date: 2022-3-21
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "Memory.hpp"
|
||||
#include "Cache.hpp"
|
||||
#include "AuMemory.hpp"
|
||||
#include "AuMemoryCache.hpp"
|
||||
#include <Source/HWInfo/AuHWInfo.hpp>
|
||||
|
||||
#define LINUX_SUPPORTS_CACHE_CTL 0
|
@ -1,7 +1,7 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Cache.hpp
|
||||
File: AuMemoryCache.hpp
|
||||
Date: 2022-3-21
|
||||
Author: Reece
|
||||
***/
|
@ -1,13 +1,13 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: SwapLock.cpp
|
||||
File: AuMemorySwapLock.cpp
|
||||
Date: 2022-3-21
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "Memory.hpp"
|
||||
#include "SwapLock.hpp"
|
||||
#include "AuMemory.hpp"
|
||||
#include "AuMemorySwapLock.hpp"
|
||||
#include <Source/HWInfo/AuHWInfo.hpp>
|
||||
|
||||
#if defined(AURORA_IS_LINUX_DERIVED)
|
@ -1,7 +1,7 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: SwapLock.hpp
|
||||
File: AuMemorySwapLock.hpp
|
||||
Date: 2022-3-21
|
||||
Author: Reece
|
||||
***/
|
@ -1,148 +0,0 @@
|
||||
/***
|
||||
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: DefaultHeap.cpp
|
||||
Date: 2021-6-13
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "Memory.hpp"
|
||||
#include "DefaultHeap.hpp"
|
||||
#include "Heap.hpp"
|
||||
#include <Source/Debug/MemoryCrunch.hpp>
|
||||
#include <mimalloc.h>
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
struct DefaultHeap : BaseHeap
|
||||
{
|
||||
AuSPtr<Heap> AllocateDivision(AuUInt32 heap, AuUInt32 alignment) override
|
||||
{
|
||||
return AllocateDivisionGlobal(this, heap, alignment);
|
||||
}
|
||||
|
||||
void *_ZAlloc(Types::size_t length) override
|
||||
{
|
||||
return Aurora::Memory::_ZAlloc(length);
|
||||
}
|
||||
|
||||
void *_ZAlloc(Types::size_t length, Types::size_t align) override
|
||||
{
|
||||
return Aurora::Memory::_ZAlloc(length, align);
|
||||
}
|
||||
|
||||
Types::size_t GetChunkSize(const void *head) override
|
||||
{
|
||||
return Aurora::Memory::GetChunkSize(head);
|
||||
}
|
||||
|
||||
void *_FAlloc(Types::size_t length) override
|
||||
{
|
||||
return Aurora::Memory::_FAlloc(length);
|
||||
}
|
||||
|
||||
void *_FAlloc(Types::size_t length, Types::size_t align) override
|
||||
{
|
||||
return Aurora::Memory::_FAlloc(length, align);
|
||||
}
|
||||
|
||||
void *_ZRealloc(void *buffer, Types::size_t length, Types::size_t align) override
|
||||
{
|
||||
return Aurora::Memory::_ZRealloc(buffer, length, align);
|
||||
}
|
||||
|
||||
void *_ZRealloc(void *buffer, Types::size_t length) override
|
||||
{
|
||||
return Aurora::Memory::_ZRealloc(buffer, length);
|
||||
}
|
||||
|
||||
void *_FRealloc(void *buffer, Types::size_t length, Types::size_t align) override
|
||||
{
|
||||
return Aurora::Memory::_FRealloc(buffer, length, align);
|
||||
}
|
||||
|
||||
void *_FRealloc(void *buffer, Types::size_t length) override
|
||||
{
|
||||
return Aurora::Memory::_FRealloc(buffer, length);
|
||||
}
|
||||
|
||||
void _Free(void *buffer) override
|
||||
{
|
||||
return Aurora::Memory::_Free(buffer);
|
||||
}
|
||||
|
||||
AuSPtr<Heap> GetSelfReference() override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
Heap *GetSelfReferenceRaw() override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
struct WalkInstance
|
||||
{
|
||||
bool(*fCallback)(void *, void *);
|
||||
void *pSecondArg;
|
||||
};
|
||||
|
||||
static bool mi_block_visit_funHandler(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *arg)
|
||||
{
|
||||
auto pWalkInstance = (WalkInstance *)arg;
|
||||
if (!block)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!area->used)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
for (AU_ITERATE_N(i, area->used))
|
||||
{
|
||||
if (!pWalkInstance->fCallback(((AuUInt *)block) + (i * area->block_size), pWalkInstance->pSecondArg))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
return pWalkInstance->fCallback(block, pWalkInstance->pSecondArg);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void WalkHeap(bool(*fCallback)(void *, void*), void *pSecondArg) override
|
||||
{
|
||||
WalkInstance inst;
|
||||
inst.fCallback = fCallback;
|
||||
inst.pSecondArg = pSecondArg;
|
||||
mi_heap_visit_blocks(mi_heap_get_default(), true , &mi_block_visit_funHandler, &inst);
|
||||
}
|
||||
|
||||
void UpdateStats() override
|
||||
{
|
||||
auto other = AuDebug::gReserveHeap->GetStats();
|
||||
|
||||
this->stats.bIsSharedWithOtherHeaps = true;
|
||||
this->stats.uBytesLiveCounter = gBytesCounterAllocated + other.uBytesLiveCounter;
|
||||
this->stats.uBytesPeakCounter = AuMax(gBytesCounterPeak, other.uBytesPeakCounter);
|
||||
|
||||
if (!this->stats.uBytesCapacity)
|
||||
{
|
||||
this->stats.uBytesCapacity = Aurora::HWInfo::GetMemStatSystem /*should be process, but process is this with extra steps.*/().value_or(AuHwInfo::RamStat { }).qwAvailable;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static DefaultHeap gDefaultAllocation;
|
||||
|
||||
AUKN_SYM Heap *DefaultDiscontiguousHeapNew()
|
||||
{
|
||||
return &gDefaultAllocation;
|
||||
}
|
||||
|
||||
AUKN_SYM void DefaultDiscontiguousHeapRelease(Heap * heap) {}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
/***
|
||||
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: DefaultHeap.hpp
|
||||
Date: 2021-6-13
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
}
|
@ -1,432 +0,0 @@
|
||||
/***
|
||||
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Heap.cpp
|
||||
Date: 2021-6-12
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "Memory.hpp"
|
||||
#include "Heap.hpp"
|
||||
|
||||
#include "mimalloc.h"
|
||||
#include "o1heap.hpp"
|
||||
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
static AuUInt32 RoundPageUp(AuUInt32 value)
|
||||
{
|
||||
return AuPageRoundUp(value, HWInfo::GetPageSize());
|
||||
}
|
||||
|
||||
static void *HeapLargeAllocate(AuUInt length)
|
||||
{
|
||||
length = RoundPageUp(length);
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
return VirtualAlloc(nullptr, length, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
#elif defined(AURORA_IS_POSIX_DERIVED)
|
||||
return mmap(0, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
#else
|
||||
// ideally we should page align.
|
||||
// i think mimalloc has fast paths with warnings for overly large passthrough allocations. unsure.
|
||||
// 32 alignment in the fastest way mimalloc can provide us memory seems adequate
|
||||
// it's very easy for mimalloc to seethe at larger allocations, but it does have slowpaths to handle them
|
||||
return AuMemory::FAlloc<void *>(length, 32);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void HeapLargeFree(void *buffer, AuUInt length)
|
||||
{
|
||||
length = RoundPageUp(length);
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
VirtualFree(buffer, 0, MEM_RELEASE);
|
||||
#elif defined(AURORA_IS_POSIX_DERIVED)
|
||||
munmap(buffer, length);
|
||||
#else
|
||||
AuMemory::Free(buffer);
|
||||
mi_collect(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct InternalHeap : BaseHeap, AuEnableSharedFromThis<InternalHeap>
|
||||
{
|
||||
virtual AuSPtr<Heap> AllocateDivision(AuUInt32 heap, AuUInt32 alignment) override;
|
||||
|
||||
InternalHeap() : heap_(nullptr), count_(0)
|
||||
{ }
|
||||
|
||||
virtual ~InternalHeap();
|
||||
|
||||
bool ownsMemory_ {};
|
||||
bool Init(AuUInt length, void *ptr = nullptr);
|
||||
|
||||
typedef struct FragmentHeader
|
||||
{
|
||||
void *next;
|
||||
void *prev;
|
||||
size_t size;
|
||||
bool used;
|
||||
} FragmentHeader;
|
||||
|
||||
static AuUInt GetHeapSize(const void *ptr)
|
||||
{
|
||||
return reinterpret_cast<const FragmentHeader *>(ptr)[-1].size;
|
||||
}
|
||||
|
||||
Types::size_t GetChunkSize(const void *head) override;
|
||||
|
||||
void *_FAlloc(Types::size_t length) override;
|
||||
void *_FAlloc(Types::size_t length, Types::size_t align) override;
|
||||
void *_ZAlloc(Types::size_t length) override;
|
||||
void *_ZAlloc(Types::size_t length, Types::size_t align) override;
|
||||
void *_ZRealloc(void *buffer, Types::size_t length) override;
|
||||
void *_ZRealloc(void *buffer, Types::size_t length, Types::size_t align) override;
|
||||
void *_FRealloc(void *buffer, Types::size_t length) override;
|
||||
void *_FRealloc(void *buffer, Types::size_t length, Types::size_t align) override;
|
||||
void _Free(void *buffer) override;
|
||||
AuSPtr<Heap> GetSelfReference() override;
|
||||
Heap *GetSelfReferenceRaw() override;
|
||||
|
||||
void TryRelease();
|
||||
void DecrementUsers();
|
||||
void RequestTermination();
|
||||
|
||||
void UpdateStats() override;
|
||||
|
||||
void WalkHeap(bool(*fCallback)(void *, void *), void *pSecondArg) override;
|
||||
|
||||
private:
|
||||
O1HeapInstance *heap_ {};
|
||||
int count_ {};
|
||||
bool isDangling_ {};
|
||||
};
|
||||
|
||||
struct DeletableHeap : InternalHeap
|
||||
{
|
||||
Heap *parent {};
|
||||
void *ptr2_ {};
|
||||
|
||||
DeletableHeap(Heap *parent, void *ptr);
|
||||
~DeletableHeap();
|
||||
};
|
||||
|
||||
DeletableHeap::DeletableHeap(Heap *parent, void *ptr) : parent(parent), ptr2_(ptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DeletableHeap::~DeletableHeap()
|
||||
{
|
||||
if (this->ptr2_)
|
||||
{
|
||||
parent->Free(this->ptr2_);
|
||||
}
|
||||
}
|
||||
|
||||
InternalHeap::~InternalHeap()
|
||||
{
|
||||
SysAssertDbgExp(count_ == 0);
|
||||
|
||||
if (this->base_)
|
||||
{
|
||||
if (this->heap_)
|
||||
{
|
||||
this->heap_ = nullptr;
|
||||
}
|
||||
|
||||
if (this->ownsMemory_)
|
||||
{
|
||||
HeapLargeFree(this->base_, this->length_);
|
||||
this->base_ = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool InternalHeap::Init(AuUInt length, void *ptr)
|
||||
{
|
||||
SysAssert(!this->base_, "heap already initialized");
|
||||
SysAssert(length, "invalid heap allocation");
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
this->base_ = ptr;
|
||||
this->length_ = length;
|
||||
this->ownsMemory_ = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (length <= 4096)
|
||||
{
|
||||
length = 4086;
|
||||
}
|
||||
|
||||
if (!(this->base_ = HeapLargeAllocate(length)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this->ownsMemory_ = true;
|
||||
this->length_ = length;
|
||||
}
|
||||
|
||||
if (!(this->heap_ = o1heapInit(this->base_, length)))
|
||||
{
|
||||
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 length, AuUInt32 alignment)
|
||||
{
|
||||
auto ptr = heap->ZAlloc<void *>(length, alignment);
|
||||
if (!ptr)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
auto ret = AuMakeShared<DeletableHeap>(heap, ptr);
|
||||
if (!ret)
|
||||
{
|
||||
heap->Free(ptr);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!ret->Init(length, ptr))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *InternalHeap::_FAlloc(Types::size_t length)
|
||||
{
|
||||
if (!this->heap_)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto ret = o1heapAllocate(this->heap_, length);
|
||||
if (ret)
|
||||
{
|
||||
AuAtomicAdd(&this->count_, 1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *InternalHeap::_FAlloc(Types::size_t length, Types::size_t align)
|
||||
{
|
||||
SysAssert(align <= O1HEAP_ALIGNMENT, "heap wrapping is unsupported, alignment past the supported 2^x alignment is not possible");
|
||||
return this->_FAlloc(length);
|
||||
}
|
||||
|
||||
void *InternalHeap::_ZAlloc(Types::size_t length)
|
||||
{
|
||||
if (!this->heap_)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto ptr = this->_FAlloc(length);
|
||||
if (!ptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AuMemset(ptr, 0, length);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *InternalHeap::_ZAlloc(Types::size_t length, Types::size_t align)
|
||||
{
|
||||
SysAssert(align <= O1HEAP_ALIGNMENT, "heap wrapping is unsupported, alignment past the supported 2^x alignment is not possible");
|
||||
return _ZAlloc(length);
|
||||
}
|
||||
|
||||
void *InternalHeap::_ZRealloc(void *buffer, Types::size_t length)
|
||||
{
|
||||
auto prevLength = GetHeapSize(buffer);
|
||||
auto alloc = this->_ZAlloc(length);
|
||||
if (!alloc)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AuMemcpy(alloc, buffer, AuMin(prevLength, length));
|
||||
this->_Free(buffer);
|
||||
return alloc;
|
||||
}
|
||||
|
||||
void *InternalHeap::_ZRealloc(void *buffer, Types::size_t length, Types::size_t align)
|
||||
{
|
||||
SysAssert(align <= O1HEAP_ALIGNMENT, "heap wrapping is unsupported, alignment past the supported 2^x alignment is not possible");
|
||||
return this->_ZRealloc(buffer, length);
|
||||
}
|
||||
|
||||
void *InternalHeap::_FRealloc(void *buffer, Types::size_t length)
|
||||
{
|
||||
auto prevLength = GetHeapSize(buffer);
|
||||
auto alloc = this->_FAlloc(length);
|
||||
if (!alloc)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AuMemcpy(alloc, buffer, AuMin(prevLength, length));
|
||||
this->_Free(buffer);
|
||||
return alloc;
|
||||
}
|
||||
|
||||
void *InternalHeap::_FRealloc(void *buffer, Types::size_t length, Types::size_t align)
|
||||
{
|
||||
SysAssert(align <= O1HEAP_ALIGNMENT, "heap wrapping is unsupported, alignment past the supported 2^x alignment is not possible");
|
||||
return this->_FRealloc(buffer, length);
|
||||
}
|
||||
|
||||
void InternalHeap::_Free(void *buffer)
|
||||
{
|
||||
if (buffer == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
o1heapFree(this->heap_, buffer);
|
||||
DecrementUsers();
|
||||
}
|
||||
|
||||
void InternalHeap::DecrementUsers()
|
||||
{
|
||||
if (AuAtomicSub(&this->count_, 1) == 0)
|
||||
{
|
||||
TryRelease();
|
||||
}
|
||||
}
|
||||
|
||||
void InternalHeap::TryRelease()
|
||||
{
|
||||
if (!this->isDangling_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (count_ == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
void InternalHeap::RequestTermination()
|
||||
{
|
||||
if (AuAtomicLoad(&this->count_))
|
||||
{
|
||||
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->isDangling_ = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
void InternalHeap::UpdateStats()
|
||||
{
|
||||
auto pDiag = o1heapGetDiagnostics(this->heap_);
|
||||
|
||||
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)
|
||||
{
|
||||
o1heapTraverseHeap(this->heap_, fCallback, pSecondArg);
|
||||
}
|
||||
|
||||
AuSPtr<Heap> InternalHeap::GetSelfReference()
|
||||
{
|
||||
try
|
||||
{
|
||||
return AuSharedFromThis();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Heap *InternalHeap::GetSelfReferenceRaw()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
AUKN_SYM Heap *AllocHeapNew(AuUInt size)
|
||||
{
|
||||
auto heap = _new InternalHeap();
|
||||
if (!heap)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!heap->Init(size, nullptr))
|
||||
{
|
||||
delete heap;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return heap;
|
||||
}
|
||||
|
||||
AUKN_SYM void AllocHeapRelease(Heap *heap)
|
||||
{
|
||||
static_cast<InternalHeap *>(heap)->RequestTermination();
|
||||
}
|
||||
|
||||
AUKN_SYM Heap *RequestHeapOfRegionNew(const MemoryViewWrite &memory)
|
||||
{
|
||||
if (!memory)
|
||||
{
|
||||
SysPushErrorArg();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto heap = _new InternalHeap();
|
||||
if (!heap)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!heap->Init(memory.length, memory.ptr))
|
||||
{
|
||||
delete heap;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return heap;
|
||||
}
|
||||
|
||||
AUKN_SYM void RequestHeapOfRegionRelease(Heap *heap)
|
||||
{
|
||||
static_cast<InternalHeap *>(heap)->RequestTermination();
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
/***
|
||||
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Heap.hpp
|
||||
Date: 2021-6-12
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
namespace Aurora::Memory
|
||||
{
|
||||
struct BaseHeap : Heap
|
||||
{
|
||||
void *base_ {};
|
||||
AuUInt length_ {};
|
||||
HeapStats stats;
|
||||
|
||||
virtual void UpdateStats() = 0;
|
||||
|
||||
inline HeapStats &GetStats() override
|
||||
{
|
||||
UpdateStats();
|
||||
return stats;
|
||||
}
|
||||
};
|
||||
|
||||
AuSPtr<Heap> AllocateDivisionGlobal(Heap *heap, AuUInt32 length, AuUInt32 alignment);
|
||||
}
|
@ -6,9 +6,7 @@
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "Memory.hpp"
|
||||
#include "SwapLock.hpp"
|
||||
#include <Source/HWInfo/AuHWInfo.hpp>
|
||||
#include "AuMemory.hpp"
|
||||
|
||||
namespace Aurora::Memory::Transition
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user