From d9d79a460b7ce67a599231364d4f10f958556130 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Sat, 15 Jan 2022 22:59:00 -0800 Subject: [PATCH] More Allocator work, fully working CSmallAllocPool --- Runtime/CGameAllocator.cpp | 68 ++++++++++++++++-- Runtime/CGameAllocator.hpp | 124 +++++++++++++++++---------------- Runtime/CMakeLists.txt | 3 + Runtime/CMediumAllocPool.cpp | 32 +++++++++ Runtime/CMediumAllocPool.hpp | 29 ++++++++ Runtime/CSmallAllocPool.cpp | 131 +++++++++++++++++++++++++++++++++++ Runtime/CSmallAllocPool.hpp | 63 +++++++++++++++++ Runtime/IAllocator.cpp | 31 +++++++++ Runtime/IAllocator.hpp | 85 +++++++++++++++++++++++ 9 files changed, 499 insertions(+), 67 deletions(-) create mode 100644 Runtime/CMediumAllocPool.cpp create mode 100644 Runtime/CMediumAllocPool.hpp create mode 100644 Runtime/CSmallAllocPool.cpp create mode 100644 Runtime/CSmallAllocPool.hpp create mode 100644 Runtime/IAllocator.cpp create mode 100644 Runtime/IAllocator.hpp diff --git a/Runtime/CGameAllocator.cpp b/Runtime/CGameAllocator.cpp index 0f7683992..2667a5d25 100644 --- a/Runtime/CGameAllocator.cpp +++ b/Runtime/CGameAllocator.cpp @@ -23,24 +23,80 @@ u32 CGameAllocator::GetFreeBinEntryForSize(size_t len) { } bool CGameAllocator::Initialize() { return true; } - void* CGameAllocator::Alloc() { return nullptr; } -s32 CGameAllocator::Free(void* ptr) { return 0; } +bool CGameAllocator::Free(void* ptr) { return 0; } void CGameAllocator::ReleaseAll() {} void CGameAllocator::AllocSecondary() {} void CGameAllocator::FreeSecondary() {} void CGameAllocator::ReleaseAllSecondary() {} -void CGameAllocator::SetOutOfMemoryCallback() {} -void CGameAllocator::EnumAllocations() {} + +void CGameAllocator::SetOutOfMemoryCallback(IAllocator::FOutOfMemoryCb cb, void* target) { + x58_oomCallBack = cb; + x5c_oomTarget = target; +} + +s32 CGameAllocator::EnumAllocations(IAllocator::FEnumAllocationsCb cb, const void* ptr, bool b) { + s32 ret = 0; + SAllocInfo info; + info.x0_infoPtr = xc_first; + while (true) { + if (info.x0_infoPtr == nullptr) { + return ret; + } + + if (static_cast(info.x0_infoPtr)->x1c_postGuard != 0xeaeaeaea) { + break; + } + if (static_cast(info.x0_infoPtr)->x0_priorGuard != 0xefefefef) { + return -1; + } + + void* next = static_cast(info.x0_infoPtr)->GetNext(); + info.x10_type = static_cast(info.x0_infoPtr)->xc_type; + info.x8_hasPrevious = static_cast(info.x0_infoPtr)->x10_prev != nullptr; + info.xc_fileAndLne = static_cast(info.x0_infoPtr)->x8_fileAndLine; + info.x4_len = static_cast(info.x0_infoPtr)->x4_len; + info.x9_ = false; + (*cb)(info, ptr); + + ++ret; + info.x0_infoPtr = reinterpret_cast(reinterpret_cast(next) & ~sizeof(SGameMemInfo)); + } + + return -1; +} + IAllocator::SAllocInfo CGameAllocator::GetAllocInfo(void* ptr) { SGameMemInfo* info = GetMemInfoFromBlockPtr(ptr); return {.x0_infoPtr = info, .x4_len = info->x4_len, .x8_hasPrevious = info->x10_prev != nullptr, .x9_ = false, - .xc_fileAndLne = info->x8_line, + .xc_fileAndLne = info->x8_fileAndLine, .x10_type = info->xc_type}; } + void CGameAllocator::OffsetFakeStatics(s32 offset) { xb8_fakeStatics += offset; } -void CGameAllocator::GetMetrics() {} +IAllocator::SMetrics CGameAllocator::GetMetrics() { + u32 mediumAllocTotalAllocated = x74_mediumPool == nullptr ? 0 : x74_mediumPool->GetTotalEntries(); + u32 mediumAllocBlocksAvailable = x74_mediumPool == nullptr ? 0 : x74_mediumPool->GetNumBlocksAvailable(); + u32 mediumAllocAllocatedSize = + x74_mediumPool == nullptr ? 0 : x74_mediumPool->GetTotalEntries() - x74_mediumPool->GetNumBlocksAvailable(); + u32 mediumAllocNumAllocs = x74_mediumPool == nullptr ? 0 : x74_mediumPool->GetNumAllocs(); + + u32 smallAllocRemainingSize = 0; + u32 smallAllocAllocatedSize = 0; + u32 smallAllocNumAllocs = 0; + if (x60_smallPool == nullptr) { + + } else { + smallAllocRemainingSize = x60_smallPool->GetNumBlocksAvailable(); + smallAllocAllocatedSize = x60_smallPool->GetTotalEntries(); + smallAllocNumAllocs = x60_smallPool->GetNumAllocs(); + } + + return SMetrics(x8_heapSize, x80_, x84_, x88_, x8c_, x90_heapSize2, x94_, x98_, x9c_, xa0_, xa4_, smallAllocNumAllocs, + smallAllocAllocatedSize, smallAllocRemainingSize, mediumAllocNumAllocs, mediumAllocAllocatedSize, + mediumAllocBlocksAvailable, x80_ - xb0_, xb4_, xbc_, mediumAllocTotalAllocated, xb8_fakeStatics); +} } // namespace metaforce diff --git a/Runtime/CGameAllocator.hpp b/Runtime/CGameAllocator.hpp index 58343bcb8..4e6023407 100644 --- a/Runtime/CGameAllocator.hpp +++ b/Runtime/CGameAllocator.hpp @@ -4,76 +4,75 @@ #include #include +#include "Runtime/IAllocator.hpp" #include "Runtime/RetroTypes.hpp" +#include "Runtime/CSmallAllocPool.hpp" +#include "Runtime/CMediumAllocPool.hpp" namespace metaforce { -class CCallStack { - const char* x0_line; - const char* x4_type; - -public: - CCallStack(int lineNum, const char* lineStr, const char* type) : x0_line(lineStr), x4_type(type) {} -}; - -enum class EHint { - Unk = (1 << 0), - RoundUpLen = (1 << 1), -}; - -ENABLE_BITWISE_ENUM(EHint); - -enum class EScope { - -}; - -enum class EType { - -}; - -class IAllocator { -public: - struct SAllocInfo { - void* x0_infoPtr; - size_t x4_len; - bool x8_hasPrevious; - bool x9_; - const char* xc_fileAndLne; - const char* x10_type; - }; - - virtual bool Initialize() = 0; // const COSContext& ctx) = 0; - - virtual void* Alloc(size_t size) = 0; - virtual bool Free(void* ptr) = 0; - virtual void ReleaseAll() = 0; - virtual void* AllocSecondary(size_t size) = 0; - virtual bool FreeSecondary(void* ptr) = 0; - virtual void ReleaseAllSecondary() = 0; - virtual void SetOutOfMemoryCallback() = 0; - virtual void EnumAllocations() = 0; - virtual SAllocInfo GetAllocInfo(void* ptr) = 0; - virtual void OffsetFakeStatics(s32 offset) = 0; - virtual void GetMetrics() = 0; -}; - class CGameAllocator : public IAllocator { - struct SGameMemInfo { - u32 x0_sentinel = 0xefefefef; +public: +private: + class SGameMemInfo { + public: + u32 x0_priorGuard = 0xefefefef; size_t x4_len = 0; - const char* x8_line; + const char* x8_fileAndLine; const char* xc_type; - SGameMemInfo* x10_prev = nullptr; - void* x14_ = nullptr; + void* x10_prev = nullptr; + void* x14_next = nullptr; void* x18_ = nullptr; - u32 x1c_canary = 0xeaeaeaea; + u32 x1c_postGuard = 0xeaeaeaea; + public: + void* GetPrev() { return x10_prev; } + void SetPrev(void* prev) { x10_prev = prev; } + void* GetNext() { return x14_next; } + void SetNext(void* next) { x14_next = next; } + u32 GetPrevMaskedFlags(); + u32 GetNextMaskedFlags(); + void SetTopOfHeapAllocated(bool topOfHeap); }; + + u8 x4_; + u8 x5_; + u8 x6_; + u8 x7_; + u32 x8_heapSize; + SGameMemInfo* xc_first; + SGameMemInfo* x10_last; + std::array x14_bins; + u32 x54_; + FOutOfMemoryCb x58_oomCallBack; + void* x5c_oomTarget; + std::unique_ptr x60_smallPool; + void* x64_smallAllocBookKeeping; + void* x68_smallAllocMainData; + bool x6c_; + u32 x70_; + std::unique_ptr x74_mediumPool; + void* x78_; + bool x7c_; + u32 x80_; + u32 x84_; + u32 x88_; + u32 x8c_; + u32 x90_heapSize2; + u32 x94_; + u32 x98_; + u32 x9c_; + u32 xa0_; + u32 xa4_; + u32 xa8_; + u32 xac_; + u32 xb0_; + u32 xb4_; + u32 xb8_fakeStatics = 0; + u32 xbc_; + static u32 GetFreeBinEntryForSize(size_t len); SGameMemInfo* GetMemInfoFromBlockPtr(void* ptr) { return reinterpret_cast(reinterpret_cast(intptr_t(ptr) - sizeof(SGameMemInfo))); } - std::array x14_bins; - - s32 xb8_fakeStatics = 0; public: bool Initialize() override; // const COsContext& ctx); @@ -83,10 +82,13 @@ public: void* AllocSecondary(size_t size) override; bool FreeSecondary(void* ptr) override; void ReleaseAllSecondary() override; - void SetOutOfMemoryCallback() override; - void EnumAllocations() override; + void SetOutOfMemoryCallback(FOutOfMemoryCb cb, void* target) override; + s32 EnumAllocations(IAllocator::FEnumAllocationsCb cb, const void* ptr, bool b) override; SAllocInfo GetAllocInfo(void* ptr) override; void OffsetFakeStatics(s32 offset) override; - void GetMetrics() override; + SMetrics GetMetrics() override; + void AllocSecondary(); + void FreeSecondary(); + void* Alloc(); }; } // namespace metaforce diff --git a/Runtime/CMakeLists.txt b/Runtime/CMakeLists.txt index f7df2fb4f..e1dbf0033 100644 --- a/Runtime/CMakeLists.txt +++ b/Runtime/CMakeLists.txt @@ -73,6 +73,9 @@ set(RUNTIME_SOURCES_B ITweak.hpp IMain.hpp CStopwatch.hpp + IAllocator.hpp IAllocator.cpp + CSmallAllocPool.hpp CSmallAllocPool.cpp + CMediumAllocPool.hpp CMediumAllocPool.cpp CGameAllocator.hpp CGameAllocator.cpp CMemoryCardSys.hpp CMemoryCardSys.cpp CScannableObjectInfo.hpp CScannableObjectInfo.cpp diff --git a/Runtime/CMediumAllocPool.cpp b/Runtime/CMediumAllocPool.cpp new file mode 100644 index 000000000..917c831de --- /dev/null +++ b/Runtime/CMediumAllocPool.cpp @@ -0,0 +1,32 @@ +#include "CMediumAllocPool.hpp" + +namespace metaforce { + +//CMediumAllocPool::CMediumAllocPool() +u32 CMediumAllocPool::GetTotalEntries() const { + u32 ret = 0; + for (const auto& puddle : x0_puddles) { + ret += puddle.x1c_numEntries; + } + + return ret; +} + +u32 CMediumAllocPool::GetNumBlocksAvailable() const { + u32 ret = 0; + for (const auto& puddle : x0_puddles) { + ret += puddle.x14_numBlocks; + } + + return ret; +} + +u32 CMediumAllocPool::GetNumAllocs() const { + u32 ret = 0; + for (const auto& puddle : x0_puddles) { + ret += puddle.x18_numAllocs; + } + + return ret; +} +} diff --git a/Runtime/CMediumAllocPool.hpp b/Runtime/CMediumAllocPool.hpp new file mode 100644 index 000000000..631b50d09 --- /dev/null +++ b/Runtime/CMediumAllocPool.hpp @@ -0,0 +1,29 @@ +#pragma once +#include + +#include + +namespace metaforce { +class CMediumAllocPool { + struct SMediumAllocPuddle { + u8 x0_; + void* x4_; + void* x8_; + void* xc_; + u32 x10_; + u32 x14_numBlocks; + u32 x18_numAllocs; + u32 x1c_numEntries; + u8 x20_; + }; + std::list x0_puddles; + std::list::iterator x18_lastAlloc; +public: + //CMediumAllocPool(); + + u32 GetTotalEntries() const; + u32 GetNumBlocksAvailable() const; + u32 GetNumAllocs() const; + +}; +} diff --git a/Runtime/CSmallAllocPool.cpp b/Runtime/CSmallAllocPool.cpp new file mode 100644 index 000000000..9c34794ae --- /dev/null +++ b/Runtime/CSmallAllocPool.cpp @@ -0,0 +1,131 @@ +#include "CSmallAllocPool.hpp" + +#include + +namespace metaforce { +CSmallAllocPool::CSmallAllocPool(u32 len, void* mainData, void* bookKeeping) +: x0_mainData(mainData), x4_bookKeeping(bookKeeping), x8_numBlocks(len), x18_numBlocksAvailable(len) { + memset(x4_bookKeeping, 0, len / 2); +} + +void* CSmallAllocPool::FindFree(u32 len) { + if (xc_cachedBookKeepingOffset == nullptr) { + xc_cachedBookKeepingOffset = x4_bookKeeping; + } + + auto* curKeepingOffset = static_cast(xc_cachedBookKeepingOffset); + auto* bookKeepingPtr = static_cast(x4_bookKeeping); + auto* bookKeepingEndPtr = bookKeepingPtr + (x8_numBlocks >> 1); + auto* curKeepingIter = curKeepingOffset; + while (true) { + u8* tmpIter = nullptr; + if (static_cast(curKeepingIter)[0] == 0 && curKeepingIter != bookKeepingEndPtr) { + tmpIter = curKeepingIter; + do { + ++tmpIter; + if (tmpIter == curKeepingOffset || tmpIter == bookKeepingEndPtr || tmpIter == curKeepingIter + len / 2) { + break; + } + } while (static_cast(tmpIter)[0] == 0); + + if (tmpIter == curKeepingIter + len / 2) { + if (tmpIter == bookKeepingEndPtr) { + xc_cachedBookKeepingOffset = bookKeepingPtr; + } else { + xc_cachedBookKeepingOffset = curKeepingIter; + } + return curKeepingIter; + } + + if (tmpIter == curKeepingOffset) { + return nullptr; + } + if (tmpIter == bookKeepingEndPtr) { + tmpIter = bookKeepingPtr; + } + } else { + tmpIter = bookKeepingPtr; + if (curKeepingIter != bookKeepingEndPtr) { + u32 tmp = static_cast(curKeepingIter)[0]; + tmpIter = curKeepingIter + (tmp >> 5); + } + } + curKeepingIter = tmpIter; + if (tmpIter == curKeepingOffset) { + return nullptr; + } + } +} + +void* CSmallAllocPool::Alloc(uint32_t size) { + uint32_t len = 1; + if (size > 3) { + len = (size + 3) / 4; + } + if ((len & 1) != 0) { + len += 1; + } + + auto* freePtr = static_cast(FindFree(len)); + if (freePtr == nullptr) { + return nullptr; + } + + auto* bookKeepingStart = static_cast(x4_bookKeeping); + uint32_t blockCount = (len - 2) / 2; + auto* bufPtr = static_cast(x0_mainData); + + static_cast(freePtr)[0] = (len << 4) | 0xf; + uint8_t* freePtrIter = freePtr + 1; + if (blockCount != 0) { + uint32_t uVar5 = blockCount >> 3; + if (uVar5 != 0) { + do { + static_cast(freePtrIter)[0] = 0xff; + static_cast(freePtrIter)[1] = 0xff; + static_cast(freePtrIter)[2] = 0xff; + static_cast(freePtrIter)[3] = 0xff; + static_cast(freePtrIter)[4] = 0xff; + static_cast(freePtrIter)[5] = 0xff; + static_cast(freePtrIter)[6] = 0xff; + static_cast(freePtrIter)[7] = 0xff; + freePtrIter += 8; + } while (--uVar5 != 0u); + + blockCount &= 7; + } + + if (blockCount != 0) { + do { + static_cast(freePtrIter)[0] = 0xff; + ++freePtrIter; + } while (--blockCount != 0u); + } + } + + x18_numBlocksAvailable = x18_numBlocksAvailable - len; + ++x1c_numAllocs; + + return bufPtr + ((freePtr - bookKeepingStart) * 8); +} + +bool CSmallAllocPool::Free(void* buf) { + u32 offset = static_cast(buf) - static_cast(x0_mainData); + u32 block = (offset >> 2) + static_cast(static_cast(offset < 0 && ((offset & 3) != 0u)) != 0); + u32 numBlocks = (static_cast(x4_bookKeeping)[0] + (block >> 1)) >> (~-(block & 1) & 4) & 0xf; + x18_numBlocksAvailable += numBlocks; + --x1c_numAllocs; + x14_ = block; + if (block == x10_) { + x10_ = -1; + } + u8* puVar1 = static_cast(x4_bookKeeping) + (block >> 1); + for (; numBlocks != 0; numBlocks -= 2) { + static_cast(puVar1)[0] = 0; + ++puVar1; + } + + return true; +} + +} // namespace metaforce \ No newline at end of file diff --git a/Runtime/CSmallAllocPool.hpp b/Runtime/CSmallAllocPool.hpp new file mode 100644 index 000000000..e6966d4ec --- /dev/null +++ b/Runtime/CSmallAllocPool.hpp @@ -0,0 +1,63 @@ +#pragma once +#include "GCNTypes.hpp" + +namespace metaforce { +class CSmallAllocPool { + void* x0_mainData; + void* x4_bookKeeping; + uint32_t x8_numBlocks; + void* xc_cachedBookKeepingOffset = nullptr; + int32_t x10_ = -1; + uint32_t x14_ = -1; + uint32_t x18_numBlocksAvailable = 0; + uint32_t x1c_numAllocs = 0; + + [[nodiscard]] void* FindFree(uint32_t len); +public: + CSmallAllocPool(uint32_t len, void* mainData, void* bookKeeping); + + [[nodiscard]] void* Alloc(uint32_t size); + [[nodiscard]] bool Free(void* buf); + + [[nodiscard]] uint32_t GetNumUsedBlocks() const { + uint32_t usedBlocks = 0; + for (uint32_t i = 0; i < x8_numBlocks / 2;) { + uint8_t p = static_cast(x4_bookKeeping)[i]; + // Don't check the header directly, make sure we extract the block count, as it's actually possible to allocate a + // 0 block buffer, Retro worked around this in retail by not allowing CGameAllocator to allocate buffers >= 0x39 + // bytes + if (((p >> 4) & 0xf) != 0) { + uint32_t numBlocks = (p >> 4) & 0xf; + usedBlocks += numBlocks; + // skip over blocks used by this allocation + i += numBlocks / 2; + } else { + ++i; + } + } + return usedBlocks; + } + + [[nodiscard]] uint32_t GetNumUnusedBlocks() const { + uint32_t unusedBlocks = 0; + for (uint32_t i = 0; i < x8_numBlocks / 2;) { + uint8_t p = static_cast(x4_bookKeeping)[i]; + // Don't check the header directly, make sure we extract the block count, as it's actually possible to allocate a + // 0 block buffer, Retro worked around this in retail by not allowing CGameAllocator to allocate buffers >= 0x39 + // bytes + if (((p >> 4) & 0xf) != 0) { + // skip over blocks used by this allocation + i += ((p >> 4) & 0xf) / 2; + } else { + ++i; + unusedBlocks += 2; + } + } + return unusedBlocks; + } + + [[nodiscard]] u32 GetNumBlocksAvailable() const { return x18_numBlocksAvailable; } + [[nodiscard]] u32 GetTotalEntries() const { return x8_numBlocks - x18_numBlocksAvailable; } + [[nodiscard]] u32 GetNumAllocs() const { return x1c_numAllocs; } +}; +} // namespace metaforce \ No newline at end of file diff --git a/Runtime/IAllocator.cpp b/Runtime/IAllocator.cpp new file mode 100644 index 000000000..30498c35d --- /dev/null +++ b/Runtime/IAllocator.cpp @@ -0,0 +1,31 @@ +#include "IAllocator.hpp" + +namespace metaforce { +IAllocator::SMetrics::SMetrics(u32 heapSize, u32 unk1, u32 unk2, u32 unk3, u32 unk4, u32 heapSize2, u32 unk5, u32 unk6, + u32 unk7, u32 unk8, u32 unk9, u32 smallAllocNumAllocs, u32 smallAllocAllocatedSize, + u32 smallAllocRemainingSize, u32 mediumAllocNumAllocs, u32 mediumAllocAllocatedSize, + u32 mediumAllocBlocksAvailable, u32 unk10, u32 unk11, u32 unk12, + u32 mediumAllocTotalAllocated, u32 fakeStatics) +: x0_heapSize(heapSize) +, x4_(unk1) +, x8_(unk2) +, xc_(unk3) +, x10_(unk4) +, x14_heapSize2(heapSize2) +, x18_(unk5) +, x1c_(unk6) +, x20_(unk7) +, x24_(unk8) +, x28_(unk9) +, x2c_smallNumAllocs(smallAllocNumAllocs) +, x30_smallAllocatedSize(smallAllocAllocatedSize) +, x34_smallRemainingSize(smallAllocRemainingSize) +, x38_mediumNumAllocs(mediumAllocNumAllocs) +, x3c_mediumAllocatedSize(mediumAllocAllocatedSize) +, x40_mediumBlocksAvailable(mediumAllocBlocksAvailable) +, x44_(unk10) +, x48_(unk11) +, x4c_(unk12) +, x50_mediumTotalAllocated(mediumAllocTotalAllocated) +, x54_fakeStatics(fakeStatics) {} +} diff --git a/Runtime/IAllocator.hpp b/Runtime/IAllocator.hpp new file mode 100644 index 000000000..de0af3e85 --- /dev/null +++ b/Runtime/IAllocator.hpp @@ -0,0 +1,85 @@ +#pragma once + +#include +#include "Runtime/GCNTypes.hpp" + +namespace metaforce { +class CCallStack { + const char* x0_line; + const char* x4_type; + +public: + CCallStack(int lineNum, const char* lineStr, const char* type) : x0_line(lineStr), x4_type(type) {} +}; + +enum class EHint { + Unk = (1 << 0), + RoundUpLen = (1 << 1), +}; +ENABLE_BITWISE_ENUM(EHint); + +enum class EScope { + +}; + +enum class EType { + +}; + +class IAllocator { +public: + using FOutOfMemoryCb = bool (*)(void*, u32); + struct SMetrics { + u32 x0_heapSize; + u32 x4_; + u32 x8_; + u32 xc_; + u32 x10_; + u32 x14_heapSize2; // Remaining heap size? + u32 x18_; + u32 x1c_; + u32 x20_; + u32 x24_; + u32 x28_; + u32 x2c_smallNumAllocs; + u32 x30_smallAllocatedSize; + u32 x34_smallRemainingSize; + u32 x38_mediumNumAllocs; + u32 x3c_mediumAllocatedSize; + u32 x40_mediumBlocksAvailable; + u32 x44_; + u32 x48_; + u32 x4c_; + u32 x50_mediumTotalAllocated; + u32 x54_fakeStatics; + SMetrics(u32 heapSize, u32 unk1, u32 unk2, u32 unk3, u32 unk4, u32 heapSize2, u32 unk5, u32 unk6, u32 unk7, + u32 unk8, u32 unk9, u32 smallAllocNumAllocs, u32 smallAllocAllocatedSize, u32 smallAllocRemainingSize, + u32 mediumAllocNumAllocs, u32 mediumAllocAllocatedSize, u32 mediumAllocBlocksAvailable, u32 unk10, u32 unk11, u32 unk12, + u32 mediumAllocTotalAllocated, u32 fakeStatics); + }; + + struct SAllocInfo { + void* x0_infoPtr; + size_t x4_len; + bool x8_hasPrevious; + bool x9_; + const char* xc_fileAndLne; + const char* x10_type; + }; + + using FEnumAllocationsCb = const bool (*)(const SAllocInfo& info, const void* ptr); + virtual bool Initialize() = 0; // const COSContext& ctx) = 0; + + virtual void* Alloc(size_t size) = 0; + virtual bool Free(void* ptr) = 0; + virtual void ReleaseAll() = 0; + virtual void* AllocSecondary(size_t size) = 0; + virtual bool FreeSecondary(void* ptr) = 0; + virtual void ReleaseAllSecondary() = 0; + virtual void SetOutOfMemoryCallback(FOutOfMemoryCb cb, void* target) = 0; + virtual s32 EnumAllocations(FEnumAllocationsCb cb, const void* ptr, bool b) = 0; + virtual SAllocInfo GetAllocInfo(void* ptr) = 0; + virtual void OffsetFakeStatics(s32 offset) = 0; + virtual SMetrics GetMetrics() = 0; +}; +} \ No newline at end of file