From efe015017a96d6d1e505e00f35998dc911198fa2 Mon Sep 17 00:00:00 2001 From: Doyle T Date: Wed, 18 Jul 2018 01:53:58 +1000 Subject: [PATCH] Start reworking dqnmemstack to have unified push/pop interface --- DqnUnitTest.cpp | 48 ++++---- dqn.h | 317 +++++++++++++++++------------------------------- 2 files changed, 138 insertions(+), 227 deletions(-) diff --git a/DqnUnitTest.cpp b/DqnUnitTest.cpp index 4a7e8a3..2eb82f9 100644 --- a/DqnUnitTest.cpp +++ b/DqnUnitTest.cpp @@ -2330,13 +2330,13 @@ FILE_SCOPE void DqnMemStack_Test() { auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroClear::Yes, DqnMemStack::Flag::BoundsGuard); - i32 const ALIGN64 = 64; - i32 const ALIGN16 = 16; - i32 const ALIGN4 = 4; - + i32 const ALIGN64 = 64; + i32 const ALIGN16 = 16; + i32 const ALIGN4 = 4; + DqnMemStack::AllocTo allocTo = DqnMemStack::AllocTo::Head; 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); DQN_ASSERT(result1 == result2); stack.Pop(result1); @@ -2344,7 +2344,7 @@ FILE_SCOPE void DqnMemStack_Test() 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); DQN_ASSERT(result1 == result2); stack.Pop(result1); @@ -2352,7 +2352,7 @@ FILE_SCOPE void DqnMemStack_Test() 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); DQN_ASSERT(result1 == result2); stack.Pop(result1); @@ -2378,7 +2378,7 @@ FILE_SCOPE void DqnMemStack_Test() if (1) { 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; 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 *pop1 = stack.Push(222); - auto *pop2 = stack.PushOnTail(333); + auto *pop2 = stack.Push(333, DqnMemStack::AllocTo::Tail); DqnMemStack::Block *blockToReturnTo = stack.block; auto headBefore = blockToReturnTo->head; @@ -2480,9 +2480,9 @@ FILE_SCOPE void DqnMemStack_Test() { auto memGuard1 = stack.TempRegionGuard(); auto *result2 = stack.Push(100); - auto *result3 = stack.PushOnTail(100); + auto *result3 = stack.Push(100, DqnMemStack::AllocTo::Tail); 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(result3 > result5); DQN_ASSERT(result2 < result4); @@ -2502,7 +2502,7 @@ FILE_SCOPE void DqnMemStack_Test() DQN_ASSERT(stack.block->tail == tailBefore); stack.Pop(pop1); - stack.PopOnTail(pop2); + stack.Pop(pop2); DQN_ASSERT(stack.block->head == stack.block->memory); DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size); @@ -2603,8 +2603,8 @@ FILE_SCOPE void DqnMemStack_Test() char *result = static_cast(stack.Push(64)); // TODO(doyle): check head and tail are adjacent to the bounds of the allocation - u32 *head = stack.tracker.PtrToHeadBoundsGuard(result); - u32 *tail = stack.tracker.PtrToTailBoundsGuard(result); + u32 *head = stack.tracker.PtrToHeadGuard(result); + u32 *tail = stack.tracker.PtrToTailGuard(result); DQN_ASSERT(*head == DqnMemTracker::HEAD_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); auto *result1 = stack.Push(100); - auto *result2 = stack.PushOnTail(100); + auto *result2 = stack.Push(100, DqnMemStack::AllocTo::Tail); auto *headBefore = stack.block->head; auto *tailBefore = stack.block->tail; DQN_ASSERT(result2 && result1); DQN_ASSERT(result2 != result1 && result1 < result2); - stack.PopOnTail(result2); + stack.Pop(result2); DQN_ASSERT(headBefore == stack.block->head) 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); 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(stack.block->prevBlock == blockBefore); @@ -2662,7 +2662,7 @@ FILE_SCOPE void DqnMemStack_Test() DQN_ASSERT(stack.block->tail < stack.block->memory + stack.block->size && stack.block->tail >= stack.block->head); - stack.PopOnTail(result2); + stack.Pop(result2); DQN_ASSERT(blockBefore == stack.block); stack.Pop(result1); @@ -2682,14 +2682,14 @@ FILE_SCOPE void DqnMemStack_Test() DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size); 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(stack.block->prevBlock == nullptr); DQN_ASSERT(stack.block == blockBefore); 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); - stack.PopOnTail(result2); + stack.Pop(result2); DQN_ASSERT(blockBefore == stack.block); stack.Pop(result1); @@ -2748,7 +2748,7 @@ FILE_SCOPE void DqnMemStack_Test() auto *tailBefore = stack.block->tail; isize bufSize = 16; - char *buf = (char *)stack.PushOnTail(bufSize); + char *buf = (char *)stack.Push(bufSize, DqnMemStack::AllocTo::Tail); DqnMem_Set(buf, 'X', bufSize); 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(tailBefore > stack.block->tail); - stack.PopOnTail(buf); + stack.Pop(buf); DQN_ASSERT(blockBefore == stack.block); DQN_ASSERT(tailBefore == stack.block->tail); @@ -2812,7 +2812,7 @@ FILE_SCOPE void DqnMemStack_Test() auto *tailBefore = stack.block->tail; isize bufSize = 16; - char *buf = (char *)stack.PushOnTail(bufSize); + char *buf = (char *)stack.Push(bufSize, DqnMemStack::AllocTo::Tail); DqnMem_Set(buf, 'X', bufSize); 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->prevBlock); - stack.PopOnTail(buf); + stack.Pop(buf); DQN_ASSERT(blockBefore == stack.block); DQN_ASSERT(tailBefore == stack.block->tail); diff --git a/dqn.h b/dqn.h index 98795ee..a8d1880 100644 --- a/dqn.h +++ b/dqn.h @@ -1413,13 +1413,14 @@ template void DqnArray::Reserve(isize newMax) // #DqnMemTracker // ================================================================================================= // Allocation Layout -// +------------------------------------------------------------+ +-----------------+ -// | Allocation Head | | Allocation Tail | -// +--------------------+------------------------------------------------------------+------------------------+-----------------+ -// | Ptr From Allocator | Offset To Src | Alignment | Alloc Amount | B. Guard (Opt.) | Aligned Ptr For Client | B. Guard (Opt.) | -// +----------------------------------------------------------------------------------------------------------------------------+ +// +-------------------------------------------------------------------------+ +-----------------+ +// | Allocation Head | | Allocation Tail | +// +--------------------+-------------------------------------------------------------------------------------+-----------------------------------+ +// | 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 // 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) // B. Guard: Bounds Guard value. // 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 OFFSET_TO_SRC_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); - DqnArray allocations; // When BoundsGuard is enabled, tracks all allocations. + DqnArray 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 Free (); + void Free () { allocations.Free(); } void AddAllocation (char *ptr) { DQN_ASSERT(allocations.Push(ptr) != nullptr); } void RemoveAllocation (char *ptr); + void CheckAllocations () const; + isize GetAllocationSize (isize size, u8 alignment) const { return allocHeadSize + size + allocTailSize + (alignment - 1); } - auto GetBoundsGuardSize () const { return boundsGuardSize; } - auto GetAllocHeadSize () const { return allocHeadSize; } - auto GetAllocTailSize () const { return allocTailSize; } + // ptr: The ptr given to the client when allocating. + 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; } - 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. - u32 *PtrToTailBoundsGuard(char *ptr) const; // IMPORTANT: Uses "Alloc Amount" metadata to find the tail! - u8 *PtrToAlignment (char *ptr) const; - 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 + // 0 if Pushed to Head on memstack, 1 if Pushed to Tail on memstack + u8 *PtrToAllocType (char *ptr) const { union { char *charPtr; u8 *u8Ptr; }; charPtr = ptr - allocHeadSize + OFFSET_TO_SRC_SIZE + ALIGNMENT_SIZE; return u8Ptr; } + isize *PtrToAllocAmount(char *ptr) const { union { char *charPtr; isize *isizePtr; }; charPtr = ptr - allocHeadSize + OFFSET_TO_SRC_SIZE + ALIGNMENT_SIZE + ALLOC_TYPE_SIZE; return isizePtr; } }; // #DqnMemStack API @@ -1481,7 +1483,7 @@ struct DqnMemStack enum Flag { 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 PushAssertsOnFail = (1 << 3), // Assert when push*() fails. All = (NonExpandable | NonExpandableAssert | BoundsGuard | PushAssertsOnFail), @@ -1526,16 +1528,18 @@ struct DqnMemStack // Allocation API // ============================================================================================= + enum struct AllocTo + { + Head, Tail + }; // Allocate memory from the MemStack. // 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. - void *Push (isize size, u8 alignment = 4); - void *PushOnTail (isize size, u8 alignment = 4); + // return: nullptr if out of space OR stack is using fixed memory/size OR stack full and platform malloc fails. + void *Push (isize size, AllocTo allocTo = AllocTo::Head, u8 alignment = 4); // 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 PopOnTail (void *ptr, Dqn::ZeroClear zeroClear = Dqn::ZeroClear::No); // Frees all blocks belonging to this stack. void Free (); @@ -3313,13 +3317,13 @@ struct DqnMemAPI__DqnMemStackContext Mode mode; }; -FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api, - DqnMemAPI::Request request_, - bool pushToHead) +FILE_SCOPE void * +DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api, DqnMemAPI::Request request_, bool pushToHead) { DqnMemAPI__ValidateRequest(request_); DQN_ASSERT(request_.userContext); + DqnMemStack::AllocTo const allocTo = (pushToHead) ? DqnMemStack::AllocTo::Head : DqnMemStack::AllocTo::Tail; auto *const stack = (DqnMemStack *)(request_.userContext); void *result = nullptr; bool success = false; @@ -3331,6 +3335,7 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api, Tail, }; + // TODO(doyle): Should use the metadata in the ptr head auto ClassifyPtr = [](DqnMemStack::Block const *block, char const *ptr) -> PtrType { PtrType result = PtrType::NotInCurrentBlock; @@ -3355,7 +3360,7 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api, if (type == PtrType::Head) { 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)); } else if (type == PtrType::Tail) @@ -3371,9 +3376,7 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api, if (request_.type == DqnMemAPI::Type::Alloc) { auto *request = &request_.e.alloc; - if (pushToHead) result = static_cast(stack->Push(request->requestSize)); - else result = static_cast(stack->PushOnTail(request->requestSize)); - + result = static_cast(stack->Push(request->requestSize, allocTo)); if (result) { success = true; @@ -3408,7 +3411,7 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api, if (enoughSpace) { stack->Pop(ptr, Dqn::ZeroClear::No); - result = static_cast(stack->Push(request->newSize, alignment)); + result = static_cast(stack->Push(request->newSize, DqnMemStack::AllocTo::Head, alignment)); DQN_ASSERT(stack->block == block && result == request->oldMemPtr); success = true; } @@ -3421,8 +3424,8 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api, enoughSpace = (block->tail - extraBytesReq) > block->head; if (enoughSpace) { - stack->PopOnTail(ptr, Dqn::ZeroClear::No); - result = static_cast(stack->PushOnTail(request->newSize, alignment)); + stack->Pop(ptr, Dqn::ZeroClear::No); + result = static_cast(stack->Push(request->newSize, DqnMemStack::AllocTo::Tail, alignment)); DqnMem_Copy(result, ptr, oldMemSize); (static_cast(result))[oldMemSize] = 0; @@ -3439,12 +3442,12 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api, DqnMemStack::Block *oldBlock = block; if (type == PtrType::Head) { - result = static_cast(stack->Push(request->newSize, alignment)); + result = static_cast(stack->Push(request->newSize, DqnMemStack::AllocTo::Head, alignment)); } else { DQN_ASSERT(type == PtrType::Tail); - result = (u8 *)stack->PushOnTail(request->newSize, alignment); + result = static_cast(stack->Push(request->newSize, DqnMemStack::AllocTo::Tail, alignment)); } if (result) @@ -3457,8 +3460,7 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api, auto *newBlock = stack->block; stack->block = oldBlock; - if (type == PtrType::Head) stack->Pop(ptr, Dqn::ZeroClear::No); - else stack->PopOnTail(ptr, Dqn::ZeroClear::No); + stack->Pop(ptr, Dqn::ZeroClear::No); stack->block = newBlock; success = true; } @@ -3475,18 +3477,16 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api, } else { - DQN_LOGE( - "Lost %$_d, the ptr to realloc is sandwiched between other allocations (LIFO)", - oldMemSize); + DQN_LOGE("Lost %$_d, the ptr to realloc is sandwiched between other allocations (LIFO)", oldMemSize); if (type == PtrType::Head) { - result = (u8 *)stack->Push(request->newSize, alignment); + result = (u8 *)stack->Push(request->newSize, DqnMemStack::AllocTo::Head, alignment); } else { DQN_ASSERT(type == PtrType::Tail); - result = (u8 *)stack->PushOnTail(request->newSize, alignment); + result = (u8 *)stack->Push(request->newSize, DqnMemStack::AllocTo::Tail, alignment); } if (result) @@ -3507,9 +3507,7 @@ FILE_SCOPE void *DqnMemAPI__StackAllocatorCallback(DqnMemAPI *api, if (PtrIsLastAllocationInBlock(&stack->tracker, block, ptr)) { - PtrType type = ClassifyPtr(block, ptr); - if (type == PtrType::Head) stack->Pop(ptr, Dqn::ZeroClear::No); - else stack->PopOnTail(ptr, Dqn::ZeroClear::No); + stack->Pop(ptr, Dqn::ZeroClear::No); } else { @@ -3613,15 +3611,10 @@ void DqnMemTracker::Init(bool boundsGuard) 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; } -void DqnMemTracker::Free() -{ - this->allocations.Free(); -} - void DqnMemTracker::RemoveAllocation(char *ptr) { isize deleteIndex = -1; @@ -3643,8 +3636,8 @@ void DqnMemTracker::CheckAllocations() const for (auto index = 0; index < this->allocations.count; index++) { char *ptr = static_cast(this->allocations.data[index]); - u32 const *headGuard = this->PtrToHeadBoundsGuard(ptr); - u32 const *tailGuard = this->PtrToTailBoundsGuard(ptr); + u32 const *headGuard = this->PtrToHeadGuard(ptr); + u32 const *tailGuard = this->PtrToTailGuard(ptr); DQN_ASSERTM(*headGuard == HEAD_GUARD_VALUE, "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 // ================================================================================================= DQN_FILE_SCOPE DqnMemStack::Block * @@ -3762,7 +3702,7 @@ DqnMemStack::DqnMemStack(isize size, Dqn::ZeroClear clear, u32 flags_, DqnMemAPI 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_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) return nullptr; + bool const pushToHead = (allocTo == AllocTo::Head); + isize sizeToAllocate = this->tracker.GetAllocationSize(size, alignment); + // Allocate New Block If Full // ============================================================================================= - DqnMemTracker *tracker = &stack->tracker; - isize actualSize = tracker->GetAllocationSize(size, alignment); - bool needNewBlock = false; - if (stack->block) + bool needNewBlock = false; + if (this->block) { - if (pushToHead) needNewBlock = ((stack->block->head + actualSize) > stack->block->tail); - else needNewBlock = ((stack->block->tail - actualSize) < stack->block->head); + if (pushToHead) needNewBlock = ((this->block->head + sizeToAllocate) > this->block->tail); + else needNewBlock = ((this->block->tail - sizeToAllocate) < this->block->head); } 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(stack->flags, DqnMemStack::Flag::NonExpandableAssert)) - DQN_ASSERT(DQN_INVALID_CODE_PATH); + if (Dqn_BitIsSet(this->flags, Flag::NonExpandableAssert)) + DQN_ASSERTM(Dqn_BitIsSet(this->flags, Flag::NonExpandable), "Allocator is non-expandable and has run out of memory"); return nullptr; } - isize newBlockSize = DQN_MAX(actualSize, DqnMemStack::MINIMUM_BLOCK_SIZE); - DqnMemStack::Block *newBlock = DqnMemStack__AllocateBlock(newBlockSize, Dqn::ZeroClear::No, stack->memAPI); - if (!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; + isize newBlockSize = DQN_MAX(sizeToAllocate, MINIMUM_BLOCK_SIZE); + Block *newBlock = DqnMemStack__AllocateBlock(newBlockSize, Dqn::ZeroClear::No, this->memAPI); + newBlock->prevBlock = this->block; + this->block = newBlock; } // Calculate Ptr To Give Client // ============================================================================================= - char *currPtr = (pushToHead) ? (stack->block->head) : (stack->block->tail - actualSize); - char *result = reinterpret_cast(DQN_ALIGN_POW_N((currPtr + tracker->GetAllocHeadSize()), alignment)); + char *currPtr = (pushToHead) ? (this->block->head) : (this->block->tail - sizeToAllocate); + char *result = reinterpret_cast(DQN_ALIGN_POW_N(currPtr + this->tracker.allocHeadSize, alignment)); isize const offsetToSrc = result - currPtr; DQN_ASSERT(offsetToSrc > 0 && offsetToSrc < (u8)-1); if (pushToHead) { - stack->block->head += actualSize; - DQN_ASSERT(stack->block->head <= stack->block->tail); + this->block->head += sizeToAllocate; + DQN_ASSERT(this->block->head <= this->block->tail); } else { - stack->block->tail -= actualSize; - DQN_ASSERT(stack->block->tail >= stack->block->head); + this->block->tail -= sizeToAllocate; + DQN_ASSERT(this->block->tail >= this->block->head); } - // Instrument allocation with guards and tracker // ============================================================================================= { - auto *myOffsetToSrc = tracker->PtrToOffsetToSrc(result); + auto *myOffsetToSrc = this->tracker.PtrToOffsetToSrc(result); *myOffsetToSrc = (u8)offsetToSrc; - auto *myAlignment = tracker->PtrToAlignment(result); + auto *myAlignment = this->tracker.PtrToAlignment(result); *myAlignment = alignment; - auto *allocAmount = tracker->PtrToAllocAmount(result); - *allocAmount = size; + auto *allocAmount = this->tracker.PtrToAllocAmount(result); + *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 *tailGuard = tracker->PtrToTailBoundsGuard(result); - *headGuard = DqnMemTracker::HEAD_GUARD_VALUE; - *tailGuard = DqnMemTracker::TAIL_GUARD_VALUE; + auto *headGuard = this->tracker.PtrToHeadGuard(result); + auto *tailGuard = this->tracker.PtrToTailGuard(result); + *headGuard = DqnMemTracker::HEAD_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(DQN_ALIGN_POW_N(result, alignment)); 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); - tracker->CheckAllocations(); + this->tracker.AddAllocation(result); + this->tracker.CheckAllocations(); } } return result; } -void *DqnMemStack::PushOnTail(isize size, u8 alignment) -{ - 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) +FILE_SCOPE void DqnMemStack__KillTrackedPtrsInRange(DqnMemTracker *tracker, char const *start, char const *end) { 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(tracker->allocations.data[index]); 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 *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; - DQN_ASSERT(stack->block); - char *const bytePtr = static_cast(ptr); - DqnMemTracker *tracker = &stack->tracker; + char *bytePtr = static_cast(ptr); // Check instrumented data - if (Dqn_BitIsSet(stack->flags, DqnMemStack::Flag::BoundsGuard)) + if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard)) { - tracker->CheckAllocations(); - tracker->RemoveAllocation(bytePtr); + this->tracker.CheckAllocations(); + this->tracker.RemoveAllocation(bytePtr); } - isize const size = *(tracker->PtrToAllocAmount(bytePtr)); - u8 const alignment = *(tracker->PtrToAlignment(bytePtr)); - u8 const offsetToSrc = *(tracker->PtrToOffsetToSrc(bytePtr)); + bool const popHead = (*(this->tracker.PtrToAllocType(bytePtr)) == 0); + isize const size = *(this->tracker.PtrToAllocAmount(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 *end = start + actualSize; - char const *blockEnd = stack->block->memory + stack->block->size; + char const *blockEnd = this->block->memory + this->block->size; if (popHead) { - DQN_ASSERTM(end == stack->block->head, "Pointer to pop was not the last allocation! %p != %p", end, stack->block->head); - stack->block->head -= actualSize; - DQN_ASSERT(stack->block->head >= stack->block->memory); + DQN_ASSERTM(end == this->block->head, "Pointer to pop was not the last allocation! %p != %p", end, this->block->head); + this->block->head -= actualSize; + DQN_ASSERT(this->block->head >= this->block->memory); } else { - DQN_ASSERTM(start == stack->block->tail, "Pointer to pop was not the last allocation! %p != %p", start, stack->block->tail); - stack->block->tail += actualSize; - DQN_ASSERT(stack->block->tail <= blockEnd); + DQN_ASSERTM(start == this->block->tail, "Pointer to pop was not the last allocation! %p != %p", start, this->block->tail); + this->block->tail += actualSize; + DQN_ASSERT(this->block->tail <= blockEnd); } if (clear == Dqn::ZeroClear::Yes) 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() { if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard)) @@ -3988,7 +3899,7 @@ bool DqnMemStack::FreeMemBlock(DqnMemStack::Block *memBlock) if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard)) { - DqnMemStack__KillTrackerPtrsExistingInBlock(&this->tracker, blockToFree); + DqnMemStack__KillTrackedPtrsInBlock(&this->tracker, blockToFree); } isize realSize = blockToFree->size + sizeof(DqnMemStack::Block); @@ -4008,7 +3919,7 @@ void DqnMemStack::ResetTail() char *end = this->block->memory + this->block->size; if (Dqn_BitIsSet(this->flags, Flag::BoundsGuard)) { - DqnMemStack__KillTrackerPtrsExistingIn(&this->tracker, start, end); + DqnMemStack__KillTrackedPtrsInRange(&this->tracker, start, end); } this->block->tail = end; @@ -4036,7 +3947,7 @@ void DqnMemStack::ClearCurrBlock(Dqn::ZeroClear clear) { 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; @@ -4136,7 +4047,7 @@ void DqnMemStack::TempRegionEnd(TempRegion region) { char *blockStart = this->block->head; char *blockEnd = this->block->tail; - DqnMemStack__KillTrackerPtrsExistingIn(&this->tracker, blockStart, blockEnd); + DqnMemStack__KillTrackedPtrsInRange(&this->tracker, blockStart, blockEnd); } break; } @@ -4161,7 +4072,7 @@ void DqnMemStack::TempRegionEnd(TempRegion region) if (Dqn_BitIsSet(this->flags, DqnMemStack::Flag::BoundsGuard)) { - DqnMemStack__KillTrackerPtrsExistingIn(&this->tracker, blockStart, blockEnd); + DqnMemStack__KillTrackedPtrsInRange(&this->tracker, blockStart, blockEnd); } } }