From cd2bb79f4a231a9fa7096940dbd18f994076bfa4 Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Tue, 19 Mar 2024 12:17:10 -0500 Subject: [PATCH] Implement linearRealloc --- libctru/include/3ds/allocator/linear.h | 1 - libctru/source/allocator/linear.cpp | 18 +++++- libctru/source/allocator/mem_pool.cpp | 85 ++++++++++++++++++++++++++ libctru/source/allocator/mem_pool.h | 2 + 4 files changed, 103 insertions(+), 3 deletions(-) diff --git a/libctru/include/3ds/allocator/linear.h b/libctru/include/3ds/allocator/linear.h index 56135a9..9d5a373 100644 --- a/libctru/include/3ds/allocator/linear.h +++ b/libctru/include/3ds/allocator/linear.h @@ -23,7 +23,6 @@ void* linearMemAlign(size_t size, size_t alignment); /** * @brief Reallocates a buffer. - * Note: Not implemented yet. * @param mem Buffer to reallocate. * @param size Size of the buffer to allocate. * @return The reallocated buffer. diff --git a/libctru/source/allocator/linear.cpp b/libctru/source/allocator/linear.cpp index 74dd88d..3e5dd12 100644 --- a/libctru/source/allocator/linear.cpp +++ b/libctru/source/allocator/linear.cpp @@ -58,8 +58,22 @@ void* linearAlloc(size_t size) void* linearRealloc(void* mem, size_t size) { - // TODO - return NULL; + auto node = getNode(mem); + if (!node) return nullptr; + + if (!sLinearPool.Reallocate(node->chunk, size)) + { + size_t minSize = (size < node->chunk.size) ? size : node->chunk.size; + void* ret = linearMemAlign(size, node->chunk.alignMask); + if (ret) + { + memcpy(ret, mem, minSize); + linearFree(mem); + return ret; + } + return nullptr; + } + return mem; } size_t linearGetSize(void* mem) diff --git a/libctru/source/allocator/mem_pool.cpp b/libctru/source/allocator/mem_pool.cpp index 7482cc6..4dc5849 100644 --- a/libctru/source/allocator/mem_pool.cpp +++ b/libctru/source/allocator/mem_pool.cpp @@ -67,6 +67,7 @@ bool MemPool::Allocate(MemChunk& chunk, u32 size, int align) // Found space! chunk.addr = addr; chunk.size = size; + chunk.alignMask = alignMask; // Resize the block if (!begWaste) @@ -94,6 +95,90 @@ bool MemPool::Allocate(MemChunk& chunk, u32 size, int align) return false; } +bool MemPool::Reallocate(MemChunk& chunk, u32 size) +{ + u8* cAddr = chunk.addr; + u32 cSize = chunk.size; + + u32 newSize = (size + chunk.alignMask) &~ chunk.alignMask; + + if (newSize == cSize) + return true; + + if (newSize > cSize) + { + // Try finding the adjacent memory in the linear pool. + MemBlock* b; + bool memFound = false; + for (b = first; b; b = b->next) + { + auto addr = b->base; + if ((cAddr + cSize) == addr) + { + memFound = true; + break; + } + } + + // Check if adjacent memory is already occupied, or if it isn't large enough. + if (!memFound || newSize > cSize + b->size) + return false; + + { + u32 memAdded = newSize - cSize; + b->base += memAdded; + b->size -= memAdded; + if (!b->size) + DelBlock(b); + + chunk.size = newSize; + } + + return true; + } + + if (newSize < cSize) + { + u8* memFreeBase = cAddr + newSize; + u32 memFreeSize = cSize - newSize; + + bool done = false; + for (auto b = first; !done && b; b = b->next) + { + auto addr = b->base; + if (addr > cAddr) + { + if ((cAddr + cSize) == addr) + { + // Merge the memory to be freed to the left of the block. + b->base = memFreeBase; + b->size += memFreeSize; + } else + { + // We need to insert a new block. + auto c = MemBlock::Create(memFreeBase, memFreeSize); + if (c) InsertBefore(b, c); + else return false; + } + done = true; + } + } + + if (!done) + { + // Either the list is empty or the "memFreeBase" address is past the end + // address of the last block -- let's add a new block at the end + auto b = MemBlock::Create(memFreeBase, memFreeSize); + if (b) AddBlock(b); + else return false; + } + + chunk.size = newSize; + return true; + } + return false; +} + void MemPool::Deallocate(const MemChunk& chunk) { u8* cAddr = chunk.addr; diff --git a/libctru/source/allocator/mem_pool.h b/libctru/source/allocator/mem_pool.h index 8288c3a..2a7eae6 100644 --- a/libctru/source/allocator/mem_pool.h +++ b/libctru/source/allocator/mem_pool.h @@ -15,6 +15,7 @@ struct MemChunk { u8* addr; u32 size; + u32 alignMask; }; struct MemBlock @@ -80,6 +81,7 @@ struct MemPool void CoalesceRight(MemBlock* b); bool Allocate(MemChunk& chunk, u32 size, int align); + bool Reallocate(MemChunk& chunk, u32 size); void Deallocate(const MemChunk& chunk); void Destroy()