Start reworking dqnmemstack to have unified push/pop interface
This commit is contained in:
parent
0bfca792ee
commit
efe015017a
@ -2330,13 +2330,13 @@ FILE_SCOPE void DqnMemStack_Test()
|
|||||||
{
|
{
|
||||||
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
|
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
|
||||||
|
|
||||||
i32 const ALIGN64 = 64;
|
i32 const ALIGN64 = 64;
|
||||||
i32 const ALIGN16 = 16;
|
i32 const ALIGN16 = 16;
|
||||||
i32 const ALIGN4 = 4;
|
i32 const ALIGN4 = 4;
|
||||||
|
DqnMemStack::AllocTo allocTo = DqnMemStack::AllocTo::Head;
|
||||||
if (1)
|
if (1)
|
||||||
{
|
{
|
||||||
u8 *result1 = (u8 *)stack.Push(2, ALIGN4);
|
u8 *result1 = (u8 *)stack.Push(2, allocTo, ALIGN4);
|
||||||
u8 *result2 = (u8 *)DQN_ALIGN_POW_N(result1, ALIGN4);
|
u8 *result2 = (u8 *)DQN_ALIGN_POW_N(result1, ALIGN4);
|
||||||
DQN_ASSERT(result1 == result2);
|
DQN_ASSERT(result1 == result2);
|
||||||
stack.Pop(result1);
|
stack.Pop(result1);
|
||||||
@ -2344,7 +2344,7 @@ FILE_SCOPE void DqnMemStack_Test()
|
|||||||
|
|
||||||
if (1)
|
if (1)
|
||||||
{
|
{
|
||||||
u8 *result1 = (u8 *)stack.Push(120, ALIGN16);
|
u8 *result1 = (u8 *)stack.Push(120, allocTo, ALIGN16);
|
||||||
u8 *result2 = (u8 *)DQN_ALIGN_POW_N(result1, ALIGN16);
|
u8 *result2 = (u8 *)DQN_ALIGN_POW_N(result1, ALIGN16);
|
||||||
DQN_ASSERT(result1 == result2);
|
DQN_ASSERT(result1 == result2);
|
||||||
stack.Pop(result1);
|
stack.Pop(result1);
|
||||||
@ -2352,7 +2352,7 @@ FILE_SCOPE void DqnMemStack_Test()
|
|||||||
|
|
||||||
if (1)
|
if (1)
|
||||||
{
|
{
|
||||||
u8 *result1 = (u8 *)stack.Push(12, ALIGN64);
|
u8 *result1 = (u8 *)stack.Push(12, allocTo, ALIGN64);
|
||||||
u8 *result2 = (u8 *)DQN_ALIGN_POW_N(result1, ALIGN64);
|
u8 *result2 = (u8 *)DQN_ALIGN_POW_N(result1, ALIGN64);
|
||||||
DQN_ASSERT(result1 == result2);
|
DQN_ASSERT(result1 == result2);
|
||||||
stack.Pop(result1);
|
stack.Pop(result1);
|
||||||
@ -2378,7 +2378,7 @@ FILE_SCOPE void DqnMemStack_Test()
|
|||||||
if (1)
|
if (1)
|
||||||
{
|
{
|
||||||
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes);
|
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes);
|
||||||
DQN_ASSERT(stack.tracker.GetBoundsGuardSize() == 0);
|
DQN_ASSERT(stack.tracker.boundsGuardSize == 0);
|
||||||
|
|
||||||
auto *oldBlock = stack.block;
|
auto *oldBlock = stack.block;
|
||||||
DQN_ASSERT(oldBlock);
|
DQN_ASSERT(oldBlock);
|
||||||
@ -2471,7 +2471,7 @@ FILE_SCOPE void DqnMemStack_Test()
|
|||||||
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
|
auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
|
||||||
|
|
||||||
auto *pop1 = stack.Push(222);
|
auto *pop1 = stack.Push(222);
|
||||||
auto *pop2 = stack.PushOnTail(333);
|
auto *pop2 = stack.Push(333, DqnMemStack::AllocTo::Tail);
|
||||||
|
|
||||||
DqnMemStack::Block *blockToReturnTo = stack.block;
|
DqnMemStack::Block *blockToReturnTo = stack.block;
|
||||||
auto headBefore = blockToReturnTo->head;
|
auto headBefore = blockToReturnTo->head;
|
||||||
@ -2480,9 +2480,9 @@ FILE_SCOPE void DqnMemStack_Test()
|
|||||||
{
|
{
|
||||||
auto memGuard1 = stack.TempRegionGuard();
|
auto memGuard1 = stack.TempRegionGuard();
|
||||||
auto *result2 = stack.Push(100);
|
auto *result2 = stack.Push(100);
|
||||||
auto *result3 = stack.PushOnTail(100);
|
auto *result3 = stack.Push(100, DqnMemStack::AllocTo::Tail);
|
||||||
auto *result4 = stack.Push(100);
|
auto *result4 = stack.Push(100);
|
||||||
auto *result5 = stack.PushOnTail(100);
|
auto *result5 = stack.Push(100, DqnMemStack::AllocTo::Tail);
|
||||||
DQN_ASSERT(result2 && result3 && result4 && result5);
|
DQN_ASSERT(result2 && result3 && result4 && result5);
|
||||||
DQN_ASSERT(result3 > result5);
|
DQN_ASSERT(result3 > result5);
|
||||||
DQN_ASSERT(result2 < result4);
|
DQN_ASSERT(result2 < result4);
|
||||||
@ -2502,7 +2502,7 @@ FILE_SCOPE void DqnMemStack_Test()
|
|||||||
DQN_ASSERT(stack.block->tail == tailBefore);
|
DQN_ASSERT(stack.block->tail == tailBefore);
|
||||||
|
|
||||||
stack.Pop(pop1);
|
stack.Pop(pop1);
|
||||||
stack.PopOnTail(pop2);
|
stack.Pop(pop2);
|
||||||
DQN_ASSERT(stack.block->head == stack.block->memory);
|
DQN_ASSERT(stack.block->head == stack.block->memory);
|
||||||
DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size);
|
DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size);
|
||||||
|
|
||||||
@ -2603,8 +2603,8 @@ FILE_SCOPE void DqnMemStack_Test()
|
|||||||
char *result = static_cast<char *>(stack.Push(64));
|
char *result = static_cast<char *>(stack.Push(64));
|
||||||
|
|
||||||
// TODO(doyle): check head and tail are adjacent to the bounds of the allocation
|
// TODO(doyle): check head and tail are adjacent to the bounds of the allocation
|
||||||
u32 *head = stack.tracker.PtrToHeadBoundsGuard(result);
|
u32 *head = stack.tracker.PtrToHeadGuard(result);
|
||||||
u32 *tail = stack.tracker.PtrToTailBoundsGuard(result);
|
u32 *tail = stack.tracker.PtrToTailGuard(result);
|
||||||
DQN_ASSERT(*head == DqnMemTracker::HEAD_GUARD_VALUE);
|
DQN_ASSERT(*head == DqnMemTracker::HEAD_GUARD_VALUE);
|
||||||
DQN_ASSERT(*tail == DqnMemTracker::TAIL_GUARD_VALUE);
|
DQN_ASSERT(*tail == DqnMemTracker::TAIL_GUARD_VALUE);
|
||||||
|
|
||||||
@ -2620,13 +2620,13 @@ FILE_SCOPE void DqnMemStack_Test()
|
|||||||
DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
|
DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard);
|
||||||
|
|
||||||
auto *result1 = stack.Push(100);
|
auto *result1 = stack.Push(100);
|
||||||
auto *result2 = stack.PushOnTail(100);
|
auto *result2 = stack.Push(100, DqnMemStack::AllocTo::Tail);
|
||||||
auto *headBefore = stack.block->head;
|
auto *headBefore = stack.block->head;
|
||||||
auto *tailBefore = stack.block->tail;
|
auto *tailBefore = stack.block->tail;
|
||||||
DQN_ASSERT(result2 && result1);
|
DQN_ASSERT(result2 && result1);
|
||||||
DQN_ASSERT(result2 != result1 && result1 < result2);
|
DQN_ASSERT(result2 != result1 && result1 < result2);
|
||||||
|
|
||||||
stack.PopOnTail(result2);
|
stack.Pop(result2);
|
||||||
DQN_ASSERT(headBefore == stack.block->head)
|
DQN_ASSERT(headBefore == stack.block->head)
|
||||||
DQN_ASSERT(tailBefore != stack.block->tail)
|
DQN_ASSERT(tailBefore != stack.block->tail)
|
||||||
|
|
||||||
@ -2652,7 +2652,7 @@ FILE_SCOPE void DqnMemStack_Test()
|
|||||||
DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size);
|
DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size);
|
||||||
auto *blockBefore = stack.block;
|
auto *blockBefore = stack.block;
|
||||||
|
|
||||||
auto *result2 = stack.PushOnTail(DQN_MEGABYTE(1));
|
auto *result2 = stack.Push(DQN_MEGABYTE(1), DqnMemStack::AllocTo::Tail);
|
||||||
DQN_ASSERT(result2 && result1);
|
DQN_ASSERT(result2 && result1);
|
||||||
DQN_ASSERT(result2 != result1);
|
DQN_ASSERT(result2 != result1);
|
||||||
DQN_ASSERT(stack.block->prevBlock == blockBefore);
|
DQN_ASSERT(stack.block->prevBlock == blockBefore);
|
||||||
@ -2662,7 +2662,7 @@ FILE_SCOPE void DqnMemStack_Test()
|
|||||||
DQN_ASSERT(stack.block->tail < stack.block->memory + stack.block->size &&
|
DQN_ASSERT(stack.block->tail < stack.block->memory + stack.block->size &&
|
||||||
stack.block->tail >= stack.block->head);
|
stack.block->tail >= stack.block->head);
|
||||||
|
|
||||||
stack.PopOnTail(result2);
|
stack.Pop(result2);
|
||||||
DQN_ASSERT(blockBefore == stack.block);
|
DQN_ASSERT(blockBefore == stack.block);
|
||||||
|
|
||||||
stack.Pop(result1);
|
stack.Pop(result1);
|
||||||
@ -2682,14 +2682,14 @@ FILE_SCOPE void DqnMemStack_Test()
|
|||||||
DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size);
|
DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size);
|
||||||
auto *blockBefore = stack.block;
|
auto *blockBefore = stack.block;
|
||||||
|
|
||||||
auto *result2 = stack.PushOnTail(DQN_MEGABYTE(1));
|
auto *result2 = stack.Push(DQN_MEGABYTE(1), DqnMemStack::AllocTo::Tail);
|
||||||
DQN_ASSERT(result2 == nullptr);
|
DQN_ASSERT(result2 == nullptr);
|
||||||
DQN_ASSERT(stack.block->prevBlock == nullptr);
|
DQN_ASSERT(stack.block->prevBlock == nullptr);
|
||||||
DQN_ASSERT(stack.block == blockBefore);
|
DQN_ASSERT(stack.block == blockBefore);
|
||||||
DQN_ASSERT(stack.block->head > stack.block->memory && stack.block->head < stack.block->tail);
|
DQN_ASSERT(stack.block->head > stack.block->memory && stack.block->head < stack.block->tail);
|
||||||
DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size);
|
DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size);
|
||||||
|
|
||||||
stack.PopOnTail(result2);
|
stack.Pop(result2);
|
||||||
DQN_ASSERT(blockBefore == stack.block);
|
DQN_ASSERT(blockBefore == stack.block);
|
||||||
|
|
||||||
stack.Pop(result1);
|
stack.Pop(result1);
|
||||||
@ -2748,7 +2748,7 @@ FILE_SCOPE void DqnMemStack_Test()
|
|||||||
auto *tailBefore = stack.block->tail;
|
auto *tailBefore = stack.block->tail;
|
||||||
|
|
||||||
isize bufSize = 16;
|
isize bufSize = 16;
|
||||||
char *buf = (char *)stack.PushOnTail(bufSize);
|
char *buf = (char *)stack.Push(bufSize, DqnMemStack::AllocTo::Tail);
|
||||||
DqnMem_Set(buf, 'X', bufSize);
|
DqnMem_Set(buf, 'X', bufSize);
|
||||||
for (auto i = 0; i < bufSize; i++) DQN_ASSERT(buf[i] == 'X');
|
for (auto i = 0; i < bufSize; i++) DQN_ASSERT(buf[i] == 'X');
|
||||||
|
|
||||||
@ -2760,7 +2760,7 @@ FILE_SCOPE void DqnMemStack_Test()
|
|||||||
|
|
||||||
DQN_ASSERT(blockBefore == stack.block);
|
DQN_ASSERT(blockBefore == stack.block);
|
||||||
DQN_ASSERT(tailBefore > stack.block->tail);
|
DQN_ASSERT(tailBefore > stack.block->tail);
|
||||||
stack.PopOnTail(buf);
|
stack.Pop(buf);
|
||||||
|
|
||||||
DQN_ASSERT(blockBefore == stack.block);
|
DQN_ASSERT(blockBefore == stack.block);
|
||||||
DQN_ASSERT(tailBefore == stack.block->tail);
|
DQN_ASSERT(tailBefore == stack.block->tail);
|
||||||
@ -2812,7 +2812,7 @@ FILE_SCOPE void DqnMemStack_Test()
|
|||||||
auto *tailBefore = stack.block->tail;
|
auto *tailBefore = stack.block->tail;
|
||||||
|
|
||||||
isize bufSize = 16;
|
isize bufSize = 16;
|
||||||
char *buf = (char *)stack.PushOnTail(bufSize);
|
char *buf = (char *)stack.Push(bufSize, DqnMemStack::AllocTo::Tail);
|
||||||
DqnMem_Set(buf, 'X', bufSize);
|
DqnMem_Set(buf, 'X', bufSize);
|
||||||
for (auto i = 0; i < bufSize; i++) DQN_ASSERT(buf[i] == 'X');
|
for (auto i = 0; i < bufSize; i++) DQN_ASSERT(buf[i] == 'X');
|
||||||
|
|
||||||
@ -2825,7 +2825,7 @@ FILE_SCOPE void DqnMemStack_Test()
|
|||||||
|
|
||||||
DQN_ASSERT(blockBefore != stack.block);
|
DQN_ASSERT(blockBefore != stack.block);
|
||||||
DQN_ASSERT(blockBefore == stack.block->prevBlock);
|
DQN_ASSERT(blockBefore == stack.block->prevBlock);
|
||||||
stack.PopOnTail(buf);
|
stack.Pop(buf);
|
||||||
|
|
||||||
DQN_ASSERT(blockBefore == stack.block);
|
DQN_ASSERT(blockBefore == stack.block);
|
||||||
DQN_ASSERT(tailBefore == stack.block->tail);
|
DQN_ASSERT(tailBefore == stack.block->tail);
|
||||||
|
317
dqn.h
317
dqn.h
@ -1413,13 +1413,14 @@ template <typename T> void DqnArray<T>::Reserve(isize newMax)
|
|||||||
// #DqnMemTracker
|
// #DqnMemTracker
|
||||||
// =================================================================================================
|
// =================================================================================================
|
||||||
// Allocation Layout
|
// Allocation Layout
|
||||||
// +------------------------------------------------------------+ +-----------------+
|
// +-------------------------------------------------------------------------+ +-----------------+
|
||||||
// | Allocation Head | | Allocation Tail |
|
// | Allocation Head | | Allocation Tail |
|
||||||
// +--------------------+------------------------------------------------------------+------------------------+-----------------+
|
// +--------------------+-------------------------------------------------------------------------------------+-----------------------------------+
|
||||||
// | Ptr From Allocator | Offset To Src | Alignment | Alloc Amount | B. Guard (Opt.) | Aligned Ptr For Client | B. Guard (Opt.) |
|
// | Ptr From Allocator | Offset To Src | Alignment | Alloc Type | Alloc Amount | B. Guard (Opt.) | Aligned Ptr For Client | B. Guard (Opt.) |
|
||||||
// +----------------------------------------------------------------------------------------------------------------------------+
|
// +----------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
// Ptr From Allocator: The pointer returned by the allocator, not aligned
|
// Ptr From Allocator: The pointer returned by the allocator, not aligned
|
||||||
// Alignment: The pointer given to the client is aligned to this power of two boundary
|
// Alignment: The pointer given to the client is aligned to this power of two boundary
|
||||||
|
// Alloc Type: If the allocation was allocated from the head or tail of the memory block (mainly for memstacks).
|
||||||
// Alloc Amount: The requested allocation amount by the client (so does not include metadata)
|
// Alloc Amount: The requested allocation amount by the client (so does not include metadata)
|
||||||
// B. Guard: Bounds Guard value.
|
// B. Guard: Bounds Guard value.
|
||||||
// Aligned Ptr For Client: The allocated memory for the client.
|
// Aligned Ptr For Client: The allocated memory for the client.
|
||||||
@ -1430,32 +1431,33 @@ struct DqnMemTracker
|
|||||||
static u32 const TAIL_GUARD_VALUE = 0xDEADBEEF;
|
static u32 const TAIL_GUARD_VALUE = 0xDEADBEEF;
|
||||||
static u32 const OFFSET_TO_SRC_SIZE = sizeof(u8);
|
static u32 const OFFSET_TO_SRC_SIZE = sizeof(u8);
|
||||||
static u32 const ALIGNMENT_SIZE = sizeof(u8);
|
static u32 const ALIGNMENT_SIZE = sizeof(u8);
|
||||||
|
static u32 const ALLOC_TYPE_SIZE = sizeof(u8);
|
||||||
static u32 const ALLOC_AMOUNT_SIZE = sizeof(usize);
|
static u32 const ALLOC_AMOUNT_SIZE = sizeof(usize);
|
||||||
|
|
||||||
DqnArray<void *> allocations; // When BoundsGuard is enabled, tracks all allocations.
|
DqnArray<void *> allocations; // Read: When BoundsGuard is enabled, tracks all allocations.
|
||||||
|
u32 boundsGuardSize; // Read: sizeof(GUARD_VALUE) OR 0 if BoundsGuard is disabled.
|
||||||
|
u32 allocHeadSize; // Read: The size of all the metadata at the head of the allocated ptr i.e. (offset, alignment ... bounds guard)
|
||||||
|
u32 allocTailSize; // Read: The size of all the metadata at the end of the allocated ptr i.e. (bounds guard)
|
||||||
|
|
||||||
void Init (bool boundsGuard);
|
void Init (bool boundsGuard);
|
||||||
void Free ();
|
void Free () { allocations.Free(); }
|
||||||
void AddAllocation (char *ptr) { DQN_ASSERT(allocations.Push(ptr) != nullptr); }
|
void AddAllocation (char *ptr) { DQN_ASSERT(allocations.Push(ptr) != nullptr); }
|
||||||
void RemoveAllocation (char *ptr);
|
void RemoveAllocation (char *ptr);
|
||||||
|
|
||||||
void CheckAllocations () const;
|
void CheckAllocations () const;
|
||||||
|
isize GetAllocationSize (isize size, u8 alignment) const { return allocHeadSize + size + allocTailSize + (alignment - 1); }
|
||||||
|
|
||||||
auto GetBoundsGuardSize () const { return boundsGuardSize; }
|
// ptr: The ptr given to the client when allocating.
|
||||||
auto GetAllocHeadSize () const { return allocHeadSize; }
|
u32 *PtrToHeadGuard (char *ptr) const { union { char *charPtr; u32 *u32Ptr; }; charPtr = ptr - allocHeadSize + OFFSET_TO_SRC_SIZE + ALIGNMENT_SIZE + ALLOC_TYPE_SIZE + ALLOC_AMOUNT_SIZE; return u32Ptr; }
|
||||||
auto GetAllocTailSize () const { return allocTailSize; }
|
|
||||||
|
|
||||||
isize GetAllocationSize (isize size, u8 alignment) const { return GetAllocHeadSize() + size + GetAllocTailSize() + (alignment - 1); }
|
// IMPORTANT: Getting the tail uses "Alloc Amount" metadata
|
||||||
|
u32 *PtrToTailGuard (char *ptr) const { union { char *charPtr; u32 *u32Ptr; }; charPtr = ptr + *PtrToAllocAmount(ptr); return u32Ptr; }
|
||||||
|
u8 *PtrToAlignment (char *ptr) const { union { char *charPtr; u8 *u8Ptr; }; charPtr = ptr - allocHeadSize + OFFSET_TO_SRC_SIZE; return u8Ptr; }
|
||||||
|
u8 *PtrToOffsetToSrc(char *ptr) const { union { char *charPtr; u8 *u8Ptr; }; charPtr = ptr - allocHeadSize; return u8Ptr; }
|
||||||
|
|
||||||
u32 *PtrToHeadBoundsGuard(char *ptr) const; // ptr: The ptr given to the client when allocating.
|
// 0 if Pushed to Head on memstack, 1 if Pushed to Tail on memstack
|
||||||
u32 *PtrToTailBoundsGuard(char *ptr) const; // IMPORTANT: Uses "Alloc Amount" metadata to find the tail!
|
u8 *PtrToAllocType (char *ptr) const { union { char *charPtr; u8 *u8Ptr; }; charPtr = ptr - allocHeadSize + OFFSET_TO_SRC_SIZE + ALIGNMENT_SIZE; return u8Ptr; }
|
||||||
u8 *PtrToAlignment (char *ptr) const;
|
isize *PtrToAllocAmount(char *ptr) const { union { char *charPtr; isize *isizePtr; }; charPtr = ptr - allocHeadSize + OFFSET_TO_SRC_SIZE + ALIGNMENT_SIZE + ALLOC_TYPE_SIZE; return isizePtr; }
|
||||||
u8 *PtrToOffsetToSrc (char *ptr) const;
|
|
||||||
isize *PtrToAllocAmount (char *ptr) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
u32 boundsGuardSize; // sizeof(GUARD_VALUE) OR 0 if BoundsGuard is disabled.
|
|
||||||
u32 allocHeadSize; // Bounds Guard Size + Offset To Src Size + Alloc Amount Size
|
|
||||||
u32 allocTailSize; // Bounds Guard Size
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// #DqnMemStack API
|
// #DqnMemStack API
|
||||||
@ -1481,7 +1483,7 @@ struct DqnMemStack
|
|||||||
enum Flag
|
enum Flag
|
||||||
{
|
{
|
||||||
NonExpandable = (1 << 0), // Disallow additional memory blocks when full.
|
NonExpandable = (1 << 0), // Disallow additional memory blocks when full.
|
||||||
NonExpandableAssert = (1 << 1), // Assert when NonExpandable is set with allocation on a full stack.
|
NonExpandableAssert = (1 << 1), // Assert when non-expandable is set and we run out of space
|
||||||
BoundsGuard = (1 << 2), // Track, check and add guards on all allocations
|
BoundsGuard = (1 << 2), // Track, check and add guards on all allocations
|
||||||
PushAssertsOnFail = (1 << 3), // Assert when push*() fails.
|
PushAssertsOnFail = (1 << 3), // Assert when push*() fails.
|
||||||
All = (NonExpandable | NonExpandableAssert | BoundsGuard | PushAssertsOnFail),
|
All = (NonExpandable | NonExpandableAssert | BoundsGuard | PushAssertsOnFail),
|
||||||
@ -1526,16 +1528,18 @@ struct DqnMemStack
|
|||||||
|
|
||||||
// Allocation API
|
// Allocation API
|
||||||
// =============================================================================================
|
// =============================================================================================
|
||||||
|
enum struct AllocTo
|
||||||
|
{
|
||||||
|
Head, Tail
|
||||||
|
};
|
||||||
|
|
||||||
// Allocate memory from the MemStack.
|
// Allocate memory from the MemStack.
|
||||||
// alignment: Ptr returned from allocator is aligned to this value and MUST be power of 2.
|
// alignment: Ptr returned from allocator is aligned to this value and MUST be power of 2.
|
||||||
// return: nullptr if out of space OR stack is using fixed memory/size OR stack full and platform malloc fails.
|
// return: nullptr if out of space OR stack is using fixed memory/size OR stack full and platform malloc fails.
|
||||||
void *Push (isize size, u8 alignment = 4);
|
void *Push (isize size, AllocTo allocTo = AllocTo::Head, u8 alignment = 4);
|
||||||
void *PushOnTail (isize size, u8 alignment = 4);
|
|
||||||
|
|
||||||
// Frees the given ptr. It MUST be the last allocated item in the stack, asserts otherwise.
|
// Frees the given ptr. It MUST be the last allocated item in the stack, asserts otherwise.
|
||||||
void Pop (void *ptr, Dqn::ZeroClear clear = Dqn::ZeroClear::No);
|
void Pop (void *ptr, Dqn::ZeroClear clear = Dqn::ZeroClear::No);
|
||||||
void PopOnTail (void *ptr, Dqn::ZeroClear zeroClear = Dqn::ZeroClear::No);
|
|
||||||
|
|
||||||
// Frees all blocks belonging to this stack.
|
// Frees all blocks belonging to this stack.
|
||||||
void Free ();
|
void Free ();
|
||||||
@ -3313,13 +3317,13 @@ struct DqnMemAPI__DqnMemStackContext
|
|||||||
Mode mode;
|
Mode mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api,
|
FILE_SCOPE void *
|
||||||
DqnMemAPI::Request request_,
|
DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api, DqnMemAPI::Request request_, bool pushToHead)
|
||||||
bool pushToHead)
|
|
||||||
{
|
{
|
||||||
DqnMemAPI__ValidateRequest(request_);
|
DqnMemAPI__ValidateRequest(request_);
|
||||||
DQN_ASSERT(request_.userContext);
|
DQN_ASSERT(request_.userContext);
|
||||||
|
|
||||||
|
DqnMemStack::AllocTo const allocTo = (pushToHead) ? DqnMemStack::AllocTo::Head : DqnMemStack::AllocTo::Tail;
|
||||||
auto *const stack = (DqnMemStack *)(request_.userContext);
|
auto *const stack = (DqnMemStack *)(request_.userContext);
|
||||||
void *result = nullptr;
|
void *result = nullptr;
|
||||||
bool success = false;
|
bool success = false;
|
||||||
@ -3331,6 +3335,7 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api,
|
|||||||
Tail,
|
Tail,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO(doyle): Should use the metadata in the ptr head
|
||||||
auto ClassifyPtr = [](DqnMemStack::Block const *block, char const *ptr) -> PtrType {
|
auto ClassifyPtr = [](DqnMemStack::Block const *block, char const *ptr) -> PtrType {
|
||||||
|
|
||||||
PtrType result = PtrType::NotInCurrentBlock;
|
PtrType result = PtrType::NotInCurrentBlock;
|
||||||
@ -3355,7 +3360,7 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api,
|
|||||||
if (type == PtrType::Head)
|
if (type == PtrType::Head)
|
||||||
{
|
{
|
||||||
isize const oldMemSize = *(tracker->PtrToAllocAmount(ptr));
|
isize const oldMemSize = *(tracker->PtrToAllocAmount(ptr));
|
||||||
char const *ptrEnd = ptr + oldMemSize + tracker->GetAllocTailSize();
|
char const *ptrEnd = ptr + oldMemSize + tracker->allocTailSize;
|
||||||
result = (ptrEnd == (block->head - 1));
|
result = (ptrEnd == (block->head - 1));
|
||||||
}
|
}
|
||||||
else if (type == PtrType::Tail)
|
else if (type == PtrType::Tail)
|
||||||
@ -3371,9 +3376,7 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api,
|
|||||||
if (request_.type == DqnMemAPI::Type::Alloc)
|
if (request_.type == DqnMemAPI::Type::Alloc)
|
||||||
{
|
{
|
||||||
auto *request = &request_.e.alloc;
|
auto *request = &request_.e.alloc;
|
||||||
if (pushToHead) result = static_cast<char *>(stack->Push(request->requestSize));
|
result = static_cast<char *>(stack->Push(request->requestSize, allocTo));
|
||||||
else result = static_cast<char *>(stack->PushOnTail(request->requestSize));
|
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
success = true;
|
success = true;
|
||||||
@ -3408,7 +3411,7 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api,
|
|||||||
if (enoughSpace)
|
if (enoughSpace)
|
||||||
{
|
{
|
||||||
stack->Pop(ptr, Dqn::ZeroClear::No);
|
stack->Pop(ptr, Dqn::ZeroClear::No);
|
||||||
result = static_cast<char *>(stack->Push(request->newSize, alignment));
|
result = static_cast<char *>(stack->Push(request->newSize, DqnMemStack::AllocTo::Head, alignment));
|
||||||
DQN_ASSERT(stack->block == block && result == request->oldMemPtr);
|
DQN_ASSERT(stack->block == block && result == request->oldMemPtr);
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
@ -3421,8 +3424,8 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api,
|
|||||||
enoughSpace = (block->tail - extraBytesReq) > block->head;
|
enoughSpace = (block->tail - extraBytesReq) > block->head;
|
||||||
if (enoughSpace)
|
if (enoughSpace)
|
||||||
{
|
{
|
||||||
stack->PopOnTail(ptr, Dqn::ZeroClear::No);
|
stack->Pop(ptr, Dqn::ZeroClear::No);
|
||||||
result = static_cast<char *>(stack->PushOnTail(request->newSize, alignment));
|
result = static_cast<char *>(stack->Push(request->newSize, DqnMemStack::AllocTo::Tail, alignment));
|
||||||
DqnMem_Copy(result, ptr, oldMemSize);
|
DqnMem_Copy(result, ptr, oldMemSize);
|
||||||
(static_cast<char *>(result))[oldMemSize] = 0;
|
(static_cast<char *>(result))[oldMemSize] = 0;
|
||||||
|
|
||||||
@ -3439,12 +3442,12 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api,
|
|||||||
DqnMemStack::Block *oldBlock = block;
|
DqnMemStack::Block *oldBlock = block;
|
||||||
if (type == PtrType::Head)
|
if (type == PtrType::Head)
|
||||||
{
|
{
|
||||||
result = static_cast<char *>(stack->Push(request->newSize, alignment));
|
result = static_cast<char *>(stack->Push(request->newSize, DqnMemStack::AllocTo::Head, alignment));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DQN_ASSERT(type == PtrType::Tail);
|
DQN_ASSERT(type == PtrType::Tail);
|
||||||
result = (u8 *)stack->PushOnTail(request->newSize, alignment);
|
result = static_cast<char *>(stack->Push(request->newSize, DqnMemStack::AllocTo::Tail, alignment));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
@ -3457,8 +3460,7 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api,
|
|||||||
auto *newBlock = stack->block;
|
auto *newBlock = stack->block;
|
||||||
stack->block = oldBlock;
|
stack->block = oldBlock;
|
||||||
|
|
||||||
if (type == PtrType::Head) stack->Pop(ptr, Dqn::ZeroClear::No);
|
stack->Pop(ptr, Dqn::ZeroClear::No);
|
||||||
else stack->PopOnTail(ptr, Dqn::ZeroClear::No);
|
|
||||||
stack->block = newBlock;
|
stack->block = newBlock;
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
@ -3475,18 +3477,16 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DQN_LOGE(
|
DQN_LOGE("Lost %$_d, the ptr to realloc is sandwiched between other allocations (LIFO)", oldMemSize);
|
||||||
"Lost %$_d, the ptr to realloc is sandwiched between other allocations (LIFO)",
|
|
||||||
oldMemSize);
|
|
||||||
|
|
||||||
if (type == PtrType::Head)
|
if (type == PtrType::Head)
|
||||||
{
|
{
|
||||||
result = (u8 *)stack->Push(request->newSize, alignment);
|
result = (u8 *)stack->Push(request->newSize, DqnMemStack::AllocTo::Head, alignment);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DQN_ASSERT(type == PtrType::Tail);
|
DQN_ASSERT(type == PtrType::Tail);
|
||||||
result = (u8 *)stack->PushOnTail(request->newSize, alignment);
|
result = (u8 *)stack->Push(request->newSize, DqnMemStack::AllocTo::Tail, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
@ -3507,9 +3507,7 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api,
|
|||||||
|
|
||||||
if (PtrIsLastAllocationInBlock(&stack->tracker, block, ptr))
|
if (PtrIsLastAllocationInBlock(&stack->tracker, block, ptr))
|
||||||
{
|
{
|
||||||
PtrType type = ClassifyPtr(block, ptr);
|
stack->Pop(ptr, Dqn::ZeroClear::No);
|
||||||
if (type == PtrType::Head) stack->Pop(ptr, Dqn::ZeroClear::No);
|
|
||||||
else stack->PopOnTail(ptr, Dqn::ZeroClear::No);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -3613,15 +3611,10 @@ void DqnMemTracker::Init(bool boundsGuard)
|
|||||||
this->boundsGuardSize = 0;
|
this->boundsGuardSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->allocHeadSize = OFFSET_TO_SRC_SIZE + ALIGNMENT_SIZE + ALLOC_AMOUNT_SIZE + this->boundsGuardSize;
|
this->allocHeadSize = OFFSET_TO_SRC_SIZE + ALIGNMENT_SIZE + ALLOC_TYPE_SIZE + ALLOC_AMOUNT_SIZE + this->boundsGuardSize;
|
||||||
this->allocTailSize = this->boundsGuardSize;
|
this->allocTailSize = this->boundsGuardSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DqnMemTracker::Free()
|
|
||||||
{
|
|
||||||
this->allocations.Free();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DqnMemTracker::RemoveAllocation(char *ptr)
|
void DqnMemTracker::RemoveAllocation(char *ptr)
|
||||||
{
|
{
|
||||||
isize deleteIndex = -1;
|
isize deleteIndex = -1;
|
||||||
@ -3643,8 +3636,8 @@ void DqnMemTracker::CheckAllocations() const
|
|||||||
for (auto index = 0; index < this->allocations.count; index++)
|
for (auto index = 0; index < this->allocations.count; index++)
|
||||||
{
|
{
|
||||||
char *ptr = static_cast<char *>(this->allocations.data[index]);
|
char *ptr = static_cast<char *>(this->allocations.data[index]);
|
||||||
u32 const *headGuard = this->PtrToHeadBoundsGuard(ptr);
|
u32 const *headGuard = this->PtrToHeadGuard(ptr);
|
||||||
u32 const *tailGuard = this->PtrToTailBoundsGuard(ptr);
|
u32 const *tailGuard = this->PtrToTailGuard(ptr);
|
||||||
|
|
||||||
DQN_ASSERTM(*headGuard == HEAD_GUARD_VALUE,
|
DQN_ASSERTM(*headGuard == HEAD_GUARD_VALUE,
|
||||||
"Bounds guard has been destroyed at the head end of the allocation! Expected: "
|
"Bounds guard has been destroyed at the head end of the allocation! Expected: "
|
||||||
@ -3658,59 +3651,6 @@ void DqnMemTracker::CheckAllocations() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
u32 *DqnMemTracker::PtrToHeadBoundsGuard(char *ptr) const
|
|
||||||
{
|
|
||||||
union {
|
|
||||||
char *charPtr;
|
|
||||||
u32 *u32Ptr;
|
|
||||||
};
|
|
||||||
charPtr = ptr - this->allocHeadSize + OFFSET_TO_SRC_SIZE + ALIGNMENT_SIZE + ALLOC_AMOUNT_SIZE;
|
|
||||||
return u32Ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 *DqnMemTracker::PtrToAlignment(char *ptr) const
|
|
||||||
{
|
|
||||||
union {
|
|
||||||
char *charPtr;
|
|
||||||
u8 *u8Ptr;
|
|
||||||
};
|
|
||||||
charPtr = ptr - this->allocHeadSize + OFFSET_TO_SRC_SIZE;
|
|
||||||
return u8Ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
u8 *DqnMemTracker::PtrToOffsetToSrc(char *ptr) const
|
|
||||||
{
|
|
||||||
union {
|
|
||||||
char *charPtr;
|
|
||||||
u8 *u8Ptr;
|
|
||||||
};
|
|
||||||
charPtr = ptr - this->allocHeadSize;
|
|
||||||
return u8Ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
isize *DqnMemTracker::PtrToAllocAmount(char *ptr) const
|
|
||||||
{
|
|
||||||
union {
|
|
||||||
char *charPtr;
|
|
||||||
isize *isizePtr;
|
|
||||||
};
|
|
||||||
charPtr = ptr - this->allocHeadSize + OFFSET_TO_SRC_SIZE + ALIGNMENT_SIZE;
|
|
||||||
return isizePtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 *DqnMemTracker::PtrToTailBoundsGuard(char *ptr) const
|
|
||||||
{
|
|
||||||
isize size = *PtrToAllocAmount(ptr);
|
|
||||||
union {
|
|
||||||
char *charPtr;
|
|
||||||
u32 *u32Ptr;
|
|
||||||
};
|
|
||||||
charPtr = ptr + size;
|
|
||||||
return u32Ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// #DqnMemStack
|
// #DqnMemStack
|
||||||
// =================================================================================================
|
// =================================================================================================
|
||||||
DQN_FILE_SCOPE DqnMemStack::Block *
|
DQN_FILE_SCOPE DqnMemStack::Block *
|
||||||
@ -3762,7 +3702,7 @@ DqnMemStack::DqnMemStack(isize size, Dqn::ZeroClear clear, u32 flags_, DqnMemAPI
|
|||||||
this->tracker.Init(boundsGuard);
|
this->tracker.Init(boundsGuard);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE_SCOPE void *DqnMemStack__Push(DqnMemStack *stack, isize size, u8 alignment, bool pushToHead)
|
void *DqnMemStack::Push(isize size, AllocTo allocTo, u8 alignment)
|
||||||
{
|
{
|
||||||
DQN_ASSERT(size >= 0 && (alignment % 2 == 0));
|
DQN_ASSERT(size >= 0 && (alignment % 2 == 0));
|
||||||
DQN_ALWAYS_ASSERTM(alignment <= 128, "Alignment supported. Update metadata to use u16 for storing the offset!");
|
DQN_ALWAYS_ASSERTM(alignment <= 128, "Alignment supported. Update metadata to use u16 for storing the offset!");
|
||||||
@ -3770,80 +3710,74 @@ FILE_SCOPE void *DqnMemStack__Push(DqnMemStack *stack, isize size, u8 alignment,
|
|||||||
if (size == 0)
|
if (size == 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
bool const pushToHead = (allocTo == AllocTo::Head);
|
||||||
|
isize sizeToAllocate = this->tracker.GetAllocationSize(size, alignment);
|
||||||
|
|
||||||
// Allocate New Block If Full
|
// Allocate New Block If Full
|
||||||
// =============================================================================================
|
// =============================================================================================
|
||||||
DqnMemTracker *tracker = &stack->tracker;
|
bool needNewBlock = false;
|
||||||
isize actualSize = tracker->GetAllocationSize(size, alignment);
|
if (this->block)
|
||||||
bool needNewBlock = false;
|
|
||||||
if (stack->block)
|
|
||||||
{
|
{
|
||||||
if (pushToHead) needNewBlock = ((stack->block->head + actualSize) > stack->block->tail);
|
if (pushToHead) needNewBlock = ((this->block->head + sizeToAllocate) > this->block->tail);
|
||||||
else needNewBlock = ((stack->block->tail - actualSize) < stack->block->head);
|
else needNewBlock = ((this->block->tail - sizeToAllocate) < this->block->head);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needNewBlock)
|
if (needNewBlock)
|
||||||
{
|
{
|
||||||
if (Dqn_BitIsSet(stack->flags, DqnMemStack::Flag::NonExpandable))
|
if (Dqn_BitIsSet(this->flags, Flag::NonExpandable))
|
||||||
{
|
{
|
||||||
DQN_LOGE("Allocator is non-expandable and has run out of memory.");
|
if (Dqn_BitIsSet(this->flags, Flag::NonExpandableAssert))
|
||||||
if (Dqn_BitIsSet(stack->flags, DqnMemStack::Flag::NonExpandableAssert))
|
DQN_ASSERTM(Dqn_BitIsSet(this->flags, Flag::NonExpandable), "Allocator is non-expandable and has run out of memory");
|
||||||
DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
isize newBlockSize = DQN_MAX(actualSize, DqnMemStack::MINIMUM_BLOCK_SIZE);
|
isize newBlockSize = DQN_MAX(sizeToAllocate, MINIMUM_BLOCK_SIZE);
|
||||||
DqnMemStack::Block *newBlock = DqnMemStack__AllocateBlock(newBlockSize, Dqn::ZeroClear::No, stack->memAPI);
|
Block *newBlock = DqnMemStack__AllocateBlock(newBlockSize, Dqn::ZeroClear::No, this->memAPI);
|
||||||
if (!newBlock)
|
newBlock->prevBlock = this->block;
|
||||||
{
|
this->block = newBlock;
|
||||||
DQN_LOGE(
|
|
||||||
"Allocator is full and could not allocate additional memory blocks, requested: %$d",
|
|
||||||
newBlockSize);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
newBlock->prevBlock = stack->block;
|
|
||||||
stack->block = newBlock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate Ptr To Give Client
|
// Calculate Ptr To Give Client
|
||||||
// =============================================================================================
|
// =============================================================================================
|
||||||
char *currPtr = (pushToHead) ? (stack->block->head) : (stack->block->tail - actualSize);
|
char *currPtr = (pushToHead) ? (this->block->head) : (this->block->tail - sizeToAllocate);
|
||||||
char *result = reinterpret_cast<char *>(DQN_ALIGN_POW_N((currPtr + tracker->GetAllocHeadSize()), alignment));
|
char *result = reinterpret_cast<char *>(DQN_ALIGN_POW_N(currPtr + this->tracker.allocHeadSize, alignment));
|
||||||
|
|
||||||
isize const offsetToSrc = result - currPtr;
|
isize const offsetToSrc = result - currPtr;
|
||||||
DQN_ASSERT(offsetToSrc > 0 && offsetToSrc < (u8)-1);
|
DQN_ASSERT(offsetToSrc > 0 && offsetToSrc < (u8)-1);
|
||||||
|
|
||||||
if (pushToHead)
|
if (pushToHead)
|
||||||
{
|
{
|
||||||
stack->block->head += actualSize;
|
this->block->head += sizeToAllocate;
|
||||||
DQN_ASSERT(stack->block->head <= stack->block->tail);
|
DQN_ASSERT(this->block->head <= this->block->tail);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stack->block->tail -= actualSize;
|
this->block->tail -= sizeToAllocate;
|
||||||
DQN_ASSERT(stack->block->tail >= stack->block->head);
|
DQN_ASSERT(this->block->tail >= this->block->head);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Instrument allocation with guards and tracker
|
// Instrument allocation with guards and tracker
|
||||||
// =============================================================================================
|
// =============================================================================================
|
||||||
{
|
{
|
||||||
auto *myOffsetToSrc = tracker->PtrToOffsetToSrc(result);
|
auto *myOffsetToSrc = this->tracker.PtrToOffsetToSrc(result);
|
||||||
*myOffsetToSrc = (u8)offsetToSrc;
|
*myOffsetToSrc = (u8)offsetToSrc;
|
||||||
|
|
||||||
auto *myAlignment = tracker->PtrToAlignment(result);
|
auto *myAlignment = this->tracker.PtrToAlignment(result);
|
||||||
*myAlignment = alignment;
|
*myAlignment = alignment;
|
||||||
|
|
||||||
auto *allocAmount = tracker->PtrToAllocAmount(result);
|
auto *allocAmount = this->tracker.PtrToAllocAmount(result);
|
||||||
*allocAmount = size;
|
*allocAmount = size;
|
||||||
|
|
||||||
if (Dqn_BitIsSet(stack->flags, DqnMemStack::Flag::BoundsGuard))
|
auto *allocType = this->tracker.PtrToAllocType(result);
|
||||||
|
*allocType = (pushToHead) ? 0 : 1;
|
||||||
|
|
||||||
|
if (Dqn_BitIsSet(this->flags, DqnMemStack::Flag::BoundsGuard))
|
||||||
{
|
{
|
||||||
auto *headGuard = tracker->PtrToHeadBoundsGuard(result);
|
auto *headGuard = this->tracker.PtrToHeadGuard(result);
|
||||||
auto *tailGuard = tracker->PtrToTailBoundsGuard(result);
|
auto *tailGuard = this->tracker.PtrToTailGuard(result);
|
||||||
*headGuard = DqnMemTracker::HEAD_GUARD_VALUE;
|
*headGuard = DqnMemTracker::HEAD_GUARD_VALUE;
|
||||||
*tailGuard = DqnMemTracker::TAIL_GUARD_VALUE;
|
*tailGuard = DqnMemTracker::TAIL_GUARD_VALUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3853,33 +3787,21 @@ FILE_SCOPE void *DqnMemStack__Push(DqnMemStack *stack, isize size, u8 alignment,
|
|||||||
char *checkAlignment = reinterpret_cast<char *>(DQN_ALIGN_POW_N(result, alignment));
|
char *checkAlignment = reinterpret_cast<char *>(DQN_ALIGN_POW_N(result, alignment));
|
||||||
DQN_ASSERTM(checkAlignment == result, "Adding bounds guard should not destroy alignment! %p != %p", result, checkAlignment);
|
DQN_ASSERTM(checkAlignment == result, "Adding bounds guard should not destroy alignment! %p != %p", result, checkAlignment);
|
||||||
|
|
||||||
if (Dqn_BitIsSet(stack->flags, DqnMemStack::Flag::BoundsGuard))
|
if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard))
|
||||||
{
|
{
|
||||||
tracker->AddAllocation(result);
|
this->tracker.AddAllocation(result);
|
||||||
tracker->CheckAllocations();
|
this->tracker.CheckAllocations();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *DqnMemStack::PushOnTail(isize size, u8 alignment)
|
FILE_SCOPE void DqnMemStack__KillTrackedPtrsInRange(DqnMemTracker *tracker, char const *start, char const *end)
|
||||||
{
|
|
||||||
void *result = DqnMemStack__Push(this, size, alignment, false);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *DqnMemStack::Push(isize size, u8 alignment)
|
|
||||||
{
|
|
||||||
void *result = DqnMemStack__Push(this, size, alignment, true);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE_SCOPE void DqnMemStack__KillTrackerPtrsExistingIn(DqnMemTracker *tracker, char const *start, char const *end)
|
|
||||||
{
|
{
|
||||||
if (start >= end) return;
|
if (start >= end) return;
|
||||||
|
|
||||||
for (auto index = 0; index < tracker->allocations.count; index++)
|
for (isize index = 0; index < tracker->allocations.count; index++)
|
||||||
{
|
{
|
||||||
char *ptr = static_cast<char *>(tracker->allocations.data[index]);
|
char *ptr = static_cast<char *>(tracker->allocations.data[index]);
|
||||||
if (ptr >= start && ptr < end)
|
if (ptr >= start && ptr < end)
|
||||||
@ -3890,72 +3812,61 @@ FILE_SCOPE void DqnMemStack__KillTrackerPtrsExistingIn(DqnMemTracker *tracker, c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE_SCOPE void DqnMemStack__KillTrackerPtrsExistingInBlock(DqnMemTracker *tracker, DqnMemStack::Block const *block)
|
FILE_SCOPE void DqnMemStack__KillTrackedPtrsInBlock(DqnMemTracker *tracker, DqnMemStack::Block const *block)
|
||||||
{
|
{
|
||||||
char const *blockStart = block->memory;
|
char const *blockStart = block->memory;
|
||||||
char const *blockEnd = block->memory + block->size;
|
char const *blockEnd = block->memory + block->size;
|
||||||
DqnMemStack__KillTrackerPtrsExistingIn(tracker, blockStart, blockEnd);
|
DqnMemStack__KillTrackedPtrsInRange(tracker, blockStart, blockEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE_SCOPE void DqnMemStack__Pop(DqnMemStack *stack, void *ptr, Dqn::ZeroClear clear, bool popHead)
|
void DqnMemStack::Pop(void *ptr, Dqn::ZeroClear clear)
|
||||||
{
|
{
|
||||||
if (!ptr) return;
|
if (!ptr) return;
|
||||||
DQN_ASSERT(stack->block);
|
|
||||||
|
|
||||||
char *const bytePtr = static_cast<char *>(ptr);
|
char *bytePtr = static_cast<char *>(ptr);
|
||||||
DqnMemTracker *tracker = &stack->tracker;
|
|
||||||
|
|
||||||
// Check instrumented data
|
// Check instrumented data
|
||||||
if (Dqn_BitIsSet(stack->flags, DqnMemStack::Flag::BoundsGuard))
|
if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard))
|
||||||
{
|
{
|
||||||
tracker->CheckAllocations();
|
this->tracker.CheckAllocations();
|
||||||
tracker->RemoveAllocation(bytePtr);
|
this->tracker.RemoveAllocation(bytePtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
isize const size = *(tracker->PtrToAllocAmount(bytePtr));
|
bool const popHead = (*(this->tracker.PtrToAllocType(bytePtr)) == 0);
|
||||||
u8 const alignment = *(tracker->PtrToAlignment(bytePtr));
|
isize const size = *(this->tracker.PtrToAllocAmount(bytePtr));
|
||||||
u8 const offsetToSrc = *(tracker->PtrToOffsetToSrc(bytePtr));
|
u8 const alignment = *(this->tracker.PtrToAlignment(bytePtr));
|
||||||
|
u8 const offsetToSrc = *(this->tracker.PtrToOffsetToSrc(bytePtr));
|
||||||
|
|
||||||
isize actualSize = tracker->GetAllocationSize(size, alignment);
|
isize actualSize = this->tracker.GetAllocationSize(size, alignment);
|
||||||
char *start = bytePtr - offsetToSrc;
|
char *start = bytePtr - offsetToSrc;
|
||||||
char *end = start + actualSize;
|
char *end = start + actualSize;
|
||||||
char const *blockEnd = stack->block->memory + stack->block->size;
|
char const *blockEnd = this->block->memory + this->block->size;
|
||||||
|
|
||||||
if (popHead)
|
if (popHead)
|
||||||
{
|
{
|
||||||
DQN_ASSERTM(end == stack->block->head, "Pointer to pop was not the last allocation! %p != %p", end, stack->block->head);
|
DQN_ASSERTM(end == this->block->head, "Pointer to pop was not the last allocation! %p != %p", end, this->block->head);
|
||||||
stack->block->head -= actualSize;
|
this->block->head -= actualSize;
|
||||||
DQN_ASSERT(stack->block->head >= stack->block->memory);
|
DQN_ASSERT(this->block->head >= this->block->memory);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DQN_ASSERTM(start == stack->block->tail, "Pointer to pop was not the last allocation! %p != %p", start, stack->block->tail);
|
DQN_ASSERTM(start == this->block->tail, "Pointer to pop was not the last allocation! %p != %p", start, this->block->tail);
|
||||||
stack->block->tail += actualSize;
|
this->block->tail += actualSize;
|
||||||
DQN_ASSERT(stack->block->tail <= blockEnd);
|
DQN_ASSERT(this->block->tail <= blockEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clear == Dqn::ZeroClear::Yes)
|
if (clear == Dqn::ZeroClear::Yes)
|
||||||
DqnMem_Set(start, 0, end - start);
|
DqnMem_Set(start, 0, end - start);
|
||||||
|
|
||||||
if (stack->block->tail == blockEnd && stack->block->head == stack->block->memory)
|
if (this->block->tail == blockEnd && this->block->head == this->block->memory)
|
||||||
{
|
{
|
||||||
if (stack->block->prevBlock)
|
if (this->block->prevBlock)
|
||||||
{
|
{
|
||||||
stack->FreeLastBlock();
|
this->FreeLastBlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DqnMemStack::Pop(void *ptr, Dqn::ZeroClear clear)
|
|
||||||
{
|
|
||||||
DqnMemStack__Pop(this, ptr, clear, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DqnMemStack::PopOnTail(void *ptr, Dqn::ZeroClear clear)
|
|
||||||
{
|
|
||||||
DqnMemStack__Pop(this, ptr, clear, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DqnMemStack::Free()
|
void DqnMemStack::Free()
|
||||||
{
|
{
|
||||||
if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard))
|
if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard))
|
||||||
@ -3988,7 +3899,7 @@ bool DqnMemStack::FreeMemBlock(DqnMemStack::Block *memBlock)
|
|||||||
|
|
||||||
if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard))
|
if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard))
|
||||||
{
|
{
|
||||||
DqnMemStack__KillTrackerPtrsExistingInBlock(&this->tracker, blockToFree);
|
DqnMemStack__KillTrackedPtrsInBlock(&this->tracker, blockToFree);
|
||||||
}
|
}
|
||||||
|
|
||||||
isize realSize = blockToFree->size + sizeof(DqnMemStack::Block);
|
isize realSize = blockToFree->size + sizeof(DqnMemStack::Block);
|
||||||
@ -4008,7 +3919,7 @@ void DqnMemStack::ResetTail()
|
|||||||
char *end = this->block->memory + this->block->size;
|
char *end = this->block->memory + this->block->size;
|
||||||
if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard))
|
if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard))
|
||||||
{
|
{
|
||||||
DqnMemStack__KillTrackerPtrsExistingIn(&this->tracker, start, end);
|
DqnMemStack__KillTrackedPtrsInRange(&this->tracker, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->block->tail = end;
|
this->block->tail = end;
|
||||||
@ -4036,7 +3947,7 @@ void DqnMemStack::ClearCurrBlock(Dqn::ZeroClear clear)
|
|||||||
{
|
{
|
||||||
if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard))
|
if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard))
|
||||||
{
|
{
|
||||||
DqnMemStack__KillTrackerPtrsExistingInBlock(&this->tracker, this->block);
|
DqnMemStack__KillTrackedPtrsInBlock(&this->tracker, this->block);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->block->head = this->block->memory;
|
this->block->head = this->block->memory;
|
||||||
@ -4136,7 +4047,7 @@ void DqnMemStack::TempRegionEnd(TempRegion region)
|
|||||||
{
|
{
|
||||||
char *blockStart = this->block->head;
|
char *blockStart = this->block->head;
|
||||||
char *blockEnd = this->block->tail;
|
char *blockEnd = this->block->tail;
|
||||||
DqnMemStack__KillTrackerPtrsExistingIn(&this->tracker, blockStart, blockEnd);
|
DqnMemStack__KillTrackedPtrsInRange(&this->tracker, blockStart, blockEnd);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -4161,7 +4072,7 @@ void DqnMemStack::TempRegionEnd(TempRegion region)
|
|||||||
|
|
||||||
if (Dqn_BitIsSet(this->flags, DqnMemStack::Flag::BoundsGuard))
|
if (Dqn_BitIsSet(this->flags, DqnMemStack::Flag::BoundsGuard))
|
||||||
{
|
{
|
||||||
DqnMemStack__KillTrackerPtrsExistingIn(&this->tracker, blockStart, blockEnd);
|
DqnMemStack__KillTrackedPtrsInRange(&this->tracker, blockStart, blockEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user