removing useless "realloc" feature in memory arenas
This commit is contained in:
@@ -12,14 +12,6 @@ namespace Juliet
|
||||
constexpr global uint64 g_Arena_Default_Commit_Size = Kilobytes(64);
|
||||
constexpr global uint64 k_ArenaHeaderSize = 128;
|
||||
|
||||
struct ArenaFreeNode
|
||||
{
|
||||
ArenaFreeNode* Next;
|
||||
ArenaFreeNode* Previous;
|
||||
index_t Position;
|
||||
size_t Size;
|
||||
};
|
||||
|
||||
#if JULIET_DEBUG
|
||||
struct ArenaDebugInfo;
|
||||
#endif
|
||||
@@ -41,10 +33,6 @@ namespace Juliet
|
||||
|
||||
Arena* FreeBlockLast;
|
||||
|
||||
ArenaFreeNode* FreeNodes;
|
||||
|
||||
bool AllowRealloc : 1;
|
||||
|
||||
JULIET_DEBUG_ONLY(uint16 LostNodeCount;)
|
||||
JULIET_DEBUG_ONLY(bool CanReserveMore : 1;)
|
||||
|
||||
@@ -66,9 +54,6 @@ namespace Juliet
|
||||
uint64 ReserveSize = g_Arena_Default_Reserve_Size;
|
||||
uint64 CommitSize = g_Arena_Default_Commit_Size;
|
||||
|
||||
// True: All push will be 32 bytes minimum
|
||||
bool AllowRealloc = false;
|
||||
|
||||
// When false, will assert if a new block is reserved.
|
||||
JULIET_DEBUG_ONLY(bool CanReserveMore : 1 = true;)
|
||||
};
|
||||
@@ -78,10 +63,8 @@ namespace Juliet
|
||||
JULIET_API void ArenaRelease(NonNullPtr<Arena> arena);
|
||||
|
||||
// Raw Push, can be used but templated helpers exists below
|
||||
[[nodiscard]] JULIET_API void* ArenaPush(NonNullPtr<Arena> arena, size_t size, size_t align,
|
||||
bool shouldBeZeroed JULIET_DEBUG_ONLY(, const char* tag));
|
||||
[[nodiscard]] JULIET_API void* ArenaReallocate(NonNullPtr<Arena> arena, void* oldPtr, size_t oldSize, size_t newSize,
|
||||
size_t align, bool shouldBeZeroed JULIET_DEBUG_ONLY(, const char* tag));
|
||||
[[nodiscard]] JULIET_API void* ArenaPush(NonNullPtr<Arena> arena, size_t size, size_t align,
|
||||
bool shouldBeZeroed JULIET_DEBUG_ONLY(, const char* tag));
|
||||
JULIET_API void ArenaPopTo(NonNullPtr<Arena> arena, size_t position);
|
||||
JULIET_API void ArenaPop(NonNullPtr<Arena> arena, size_t amount);
|
||||
JULIET_API void ArenaClear(NonNullPtr<Arena> arena);
|
||||
|
||||
@@ -18,12 +18,6 @@ namespace Juliet
|
||||
constexpr uint64 k_PageSize = Kilobytes(4);
|
||||
} // namespace
|
||||
|
||||
namespace
|
||||
{
|
||||
static_assert(sizeof(ArenaFreeNode) == 32, "ArenaFreeNode should be 32 bytes and not more");
|
||||
constexpr size_t k_ArenaFreeNodeSize = sizeof(ArenaFreeNode);
|
||||
} // namespace
|
||||
|
||||
// https://github.com/EpicGamesExt/raddebugger/blob/master/src/base/base_arena.c
|
||||
|
||||
Arena* ArenaAllocate(const ArenaParams& params JULIET_DEBUG_ONLY(, const char* name), const std::source_location& loc)
|
||||
@@ -51,9 +45,6 @@ namespace Juliet
|
||||
arena->BasePosition = 0;
|
||||
arena->Position = k_ArenaHeaderSize;
|
||||
|
||||
arena->FreeNodes = nullptr;
|
||||
arena->AllowRealloc = params.AllowRealloc;
|
||||
|
||||
#if JULIET_DEBUG
|
||||
arena->CanReserveMore = params.CanReserveMore;
|
||||
arena->FirstDebugInfo = nullptr;
|
||||
@@ -86,52 +77,6 @@ namespace Juliet
|
||||
size_t positionPrePush = AlignPow2(current->Position, align);
|
||||
size_t positionPostPush = positionPrePush + size;
|
||||
|
||||
if (arena->AllowRealloc)
|
||||
{
|
||||
size = Max(size, k_ArenaFreeNodeSize);
|
||||
|
||||
for (ArenaFreeNode* freeNode = current->FreeNodes; freeNode != nullptr; freeNode = freeNode->Next)
|
||||
{
|
||||
if (size <= freeNode->Size)
|
||||
{
|
||||
index_t position = freeNode->Position;
|
||||
size_t remainingSize = freeNode->Size - size;
|
||||
if (remainingSize < k_ArenaFreeNodeSize)
|
||||
{
|
||||
ArenaFreeNode* previous = freeNode->Previous;
|
||||
ArenaFreeNode* next = freeNode->Next;
|
||||
if (previous)
|
||||
{
|
||||
previous->Next = next;
|
||||
}
|
||||
if (next)
|
||||
{
|
||||
next->Previous = previous;
|
||||
}
|
||||
|
||||
#if JULIET_DEBUG
|
||||
if (remainingSize > 0)
|
||||
{
|
||||
++current->LostNodeCount;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
freeNode->Position += size;
|
||||
}
|
||||
|
||||
auto* result = reinterpret_cast<Byte*>(current) + position;
|
||||
if (shouldBeZeroed)
|
||||
{
|
||||
MemoryZero(result, size);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If allowed and needed, add a new block and chain it to the arena.
|
||||
if (current->Reserved < positionPostPush /* flags : chaining allowed */)
|
||||
{
|
||||
@@ -225,55 +170,6 @@ namespace Juliet
|
||||
return result;
|
||||
}
|
||||
|
||||
void* ArenaReallocate(NonNullPtr<Arena> arena, void* oldPtr, size_t oldSize, size_t newSize, size_t align,
|
||||
bool shouldBeZeroed JULIET_DEBUG_ONLY(, const char* tag))
|
||||
{
|
||||
void* result = ArenaPush(arena, newSize, align, shouldBeZeroed JULIET_DEBUG_ONLY(, tag));
|
||||
|
||||
// Find the correct block to release
|
||||
Arena* block = nullptr;
|
||||
for (block = arena->Current; block != nullptr; block = block->Previous)
|
||||
{
|
||||
if ((reinterpret_cast<Byte*>(block) < static_cast<Byte*>(oldPtr)) &&
|
||||
(static_cast<Byte*>(oldPtr) <= (reinterpret_cast<Byte*>(block) + block->Reserved)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assert(block != nullptr);
|
||||
|
||||
// Copy old to new
|
||||
MemCopy(result, oldPtr, std::min(oldSize, newSize));
|
||||
|
||||
// Zero the old memory
|
||||
MemoryZero(oldPtr, oldSize);
|
||||
|
||||
if (oldSize >= sizeof(ArenaFreeNode))
|
||||
{
|
||||
ArenaFreeNode* freeNode = static_cast<ArenaFreeNode*>(oldPtr);
|
||||
ptrdiff_t posPtr = static_cast<Byte*>(oldPtr) - reinterpret_cast<Byte*>(block);
|
||||
index_t position = static_cast<index_t>(posPtr);
|
||||
freeNode->Position = position;
|
||||
freeNode->Size = oldSize;
|
||||
|
||||
// Insert at head of the free list
|
||||
freeNode->Next = block->FreeNodes;
|
||||
freeNode->Previous = nullptr;
|
||||
if (block->FreeNodes)
|
||||
{
|
||||
block->FreeNodes->Previous = freeNode;
|
||||
}
|
||||
block->FreeNodes = freeNode;
|
||||
|
||||
#if JULIET_DEBUG
|
||||
// Remove the debug info for the old allocation (since it's now free)
|
||||
size_t oldOffset = static_cast<size_t>(static_cast<Byte*>(oldPtr) - reinterpret_cast<Byte*>(block));
|
||||
DebugArenaRemoveAllocation(block, oldOffset);
|
||||
#endif
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ArenaPopTo(NonNullPtr<Arena> arena, size_t position)
|
||||
{
|
||||
size_t clampedPosition = ClampBottom(k_ArenaHeaderSize, position);
|
||||
|
||||
@@ -117,60 +117,6 @@ namespace Juliet::UnitTest
|
||||
|
||||
ArenaRelease(testArena);
|
||||
|
||||
{
|
||||
// Test reallocate
|
||||
Arena* arena = ArenaAllocate({ .AllowRealloc = true } JULIET_DEBUG_ONLY(, "Test Realloc"));
|
||||
char* charArray = ArenaPushArray<char>(arena, 128);
|
||||
char* secondCharArray = ArenaPushArray<char>(arena, 128);
|
||||
char* thirdCharArray = ArenaPushArray<char>(arena, 128);
|
||||
|
||||
secondCharArray = static_cast<char*>(ArenaReallocate(arena, secondCharArray, 128, 256, alignof(char), true JULIET_DEBUG_ONLY(, "ReallocChar")));
|
||||
|
||||
char* fourthCharArray = ArenaPushArray<char>(arena, 128);
|
||||
|
||||
Assert(charArray);
|
||||
Assert(secondCharArray);
|
||||
Assert(thirdCharArray);
|
||||
Assert(fourthCharArray);
|
||||
|
||||
ArenaRelease(arena);
|
||||
}
|
||||
|
||||
{
|
||||
// Test Reallocate Shrink (Buffer Overflow Bug Check)
|
||||
Arena* arena = ArenaAllocate({ .AllowRealloc = true } JULIET_DEBUG_ONLY(, "Test Shrink"));
|
||||
|
||||
size_t largeSize = 100;
|
||||
char* large = ArenaPushArray<char>(arena, largeSize);
|
||||
MemSet(large, 'A', largeSize);
|
||||
|
||||
size_t smallSize = 50;
|
||||
char* smallData = static_cast<char*>(ArenaReallocate(arena, large, largeSize, smallSize, alignof(char), true JULIET_DEBUG_ONLY(, "ResizeSmall")));
|
||||
|
||||
for (size_t i = 0; i < smallSize; ++i)
|
||||
{
|
||||
Assert(smallData[i] == 'A');
|
||||
}
|
||||
|
||||
// Allocate next block (should be immediately after 'small')
|
||||
// Don't zero it, if overflow happened it will contain 'A's
|
||||
char* next = static_cast<char*>(ArenaPush(arena, 50, alignof(char), false JULIET_DEBUG_ONLY(, "OverflowCheck")));
|
||||
|
||||
bool corrupted = false;
|
||||
for(size_t i = 0; i < 50; ++i)
|
||||
{
|
||||
if (next[i] == 'A')
|
||||
{
|
||||
corrupted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Assert(!corrupted);
|
||||
|
||||
ArenaRelease(arena);
|
||||
}
|
||||
|
||||
printf("All Paged MemoryArena tests passed.\n");
|
||||
}
|
||||
} // namespace Juliet::UnitTest
|
||||
|
||||
@@ -450,24 +450,6 @@ namespace Juliet::Debug
|
||||
info = info->Next;
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
// Draw Free Nodes (Holes) if Realloc is enabled
|
||||
if (arena->AllowRealloc && blk->FreeNodes)
|
||||
{
|
||||
ArenaFreeNode* freeNode = blk->FreeNodes;
|
||||
while (freeNode)
|
||||
{
|
||||
float fxStart = pos.x + static_cast<float>(static_cast<double>(freeNode->Position) * scale);
|
||||
float fWidth = static_cast<float>(static_cast<double>(freeNode->Size) * scale);
|
||||
|
||||
ImVec2 fMin(fxStart, pos.y + 1);
|
||||
ImVec2 fMax(fxStart + fWidth, pos.y + blockHeight - 1);
|
||||
|
||||
dl->AddRectFilled(fMin, fMax, IM_COL32(50, 50, 50, 200));
|
||||
|
||||
freeNode = freeNode->Next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pos.y += blockHeight + blockSpacing;
|
||||
|
||||
@@ -154,7 +154,8 @@ namespace Juliet
|
||||
|
||||
void InitializeEngine(JulietInit_Flags flags)
|
||||
{
|
||||
EngineInstance.PlatformArena = ArenaAllocate({ .AllowRealloc = true } JULIET_DEBUG_PARAM("Platform Arena"));
|
||||
EngineInstance.PlatformArena =
|
||||
ArenaAllocate({ .ReserveSize = Megabytes(128) } JULIET_DEBUG_PARAM("Platform Arena"));
|
||||
|
||||
InitializeLogManager();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user