From 147e4fcedca332070ca15dbc1db358ce2d42972c Mon Sep 17 00:00:00 2001 From: Anghelo Carvajal Date: Fri, 24 Mar 2023 14:38:04 -0300 Subject: THA docs (#1177) * THA docs Co-authored-by: Tharo <17233964+Thar0@users.noreply.github.com> * format * namefixer * yada * remove zero pad comment * Update include/z64.h Co-authored-by: engineer124 <47598039+engineer124@users.noreply.github.com> * Update include/thga.h Co-authored-by: engineer124 <47598039+engineer124@users.noreply.github.com> * namefixer * bss * namefixer --------- Co-authored-by: Tharo <17233964+Thar0@users.noreply.github.com> Co-authored-by: engineer124 <47598039+engineer124@users.noreply.github.com> --- src/code/TwoHeadArena.c | 117 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 87 insertions(+), 30 deletions(-) (limited to 'src/code/TwoHeadArena.c') diff --git a/src/code/TwoHeadArena.c b/src/code/TwoHeadArena.c index 83d5be3d1..a476c3d74 100644 --- a/src/code/TwoHeadArena.c +++ b/src/code/TwoHeadArena.c @@ -1,79 +1,136 @@ -#include "global.h" +/** + * @file TwoHeadArena.c + * + * This file implements a simple general purpose double-ended stack allocator. + * + * A double-ended stack allocator accepts allocations at either the "head" or "tail" of its allotted memory region. + * While in general this type of allocator could accept deallocations on the most recently allocated block at either + * end, this implementation does not support any individual deallocations; the only provided way to deallocate anything + * is to reset the entire arena, deallocating everything. This scheme is most applicable to allocating similar data + * with identical lifetime. + */ + +#include "tha.h" +#include "alignment.h" +#include "functions.h" void* THA_GetHead(TwoHeadArena* tha) { return tha->head; } -void THA_SetHead(TwoHeadArena* tha, void* start) { - tha->head = start; +void THA_SetHead(TwoHeadArena* tha, void* newHead) { + tha->head = newHead; } void* THA_GetTail(TwoHeadArena* tha) { return tha->tail; } -void* THA_AllocStart(TwoHeadArena* tha, size_t size) { +/** + * Allocates to the head of the Two Head Arena. The allocation will not have any alignment guarantees. + */ +void* THA_AllocHead(TwoHeadArena* tha, size_t size) { void* start = tha->head; - tha->head = (u32)tha->head + size; + tha->head = (u8*)tha->head + size; return start; } -void* THA_AllocStart1(TwoHeadArena* tha) { - return THA_AllocStart(tha, 1); +void* THA_AllocHeadByte(TwoHeadArena* tha) { + return THA_AllocHead(tha, 1); } -void* THA_AllocEnd(TwoHeadArena* tha, size_t size) { - u32 mask; +/** + * Allocates to the tail end of the Two Head Arena. The allocation will be aligned based on the size of the allocation. + * All allocations of 16 bytes or more will be aligned to 16-bytes. Otherwise, the alignment will be the largest power + * of 2 for which the size is a multiple, in order to accommodate the alignment requirements of any data types that can + * fit within the allocation. + */ +void* THA_AllocTail(TwoHeadArena* tha, size_t size) { + uintptr_t mask; if (size >= 0x10) { - mask = ~0xF; + // Align 0x10 for allocations greater than 0x10 + mask = ALIGN_MASK(0x10); } else if (size & 1) { - mask = -1; + // No alignment for odd sizes + mask = ALIGN_MASK(1); } else if (size & 2) { - mask = ~0x1; + // Align 2 for multiples of 2 + mask = ALIGN_MASK(2); } else if (size & 4) { - mask = ~0x3; + // Align 4 for multiples of 4 + mask = ALIGN_MASK(4); + } else if (size & 8) { + // Align 8 for multiples of 8 + mask = ALIGN_MASK(8); } else { - mask = (size & 8) ? ~0x7 : -1; + mask = ALIGN_MASK(1); } - tha->tail = (((u32)tha->tail & mask) - size) & mask; + tha->tail = (void*)((((uintptr_t)tha->tail & mask) - size) & mask); return tha->tail; } -void* THA_AllocEndAlign16(TwoHeadArena* tha, size_t size) { - u32 mask = ~0xF; +/** + * Allocates to the tail end of the Two Head Arena with guaranteed 16-byte alignment. + */ +void* THA_AllocTailAlign16(TwoHeadArena* tha, size_t size) { + uintptr_t mask = ALIGN_MASK(0x10); - tha->tail = (((u32)tha->tail & mask) - size) & mask; + tha->tail = (void*)((((uintptr_t)tha->tail & mask) - size) & mask); return tha->tail; } -void* THA_AllocEndAlign(TwoHeadArena* tha, size_t size, u32 mask) { - tha->tail = (((u32)tha->tail & mask) - size) & mask; +/** + * Allocates to the tail end of the Two Head Arena using the provided mask to align the allocated region. + * + * @param tha Arena to allocate to + * @param size Size of the allocation + * @param mask Mask to use to align the allocated region. To align to n-bytes where n is a power of 2, use the + * ALIGN_MASK(n) macro + * + * @return Pointer to the start of the allocated block + */ +void* THA_AllocTailAlign(TwoHeadArena* tha, size_t size, uintptr_t mask) { + tha->tail = (void*)((((uintptr_t)tha->tail & mask) - size) & mask); return tha->tail; } -s32 THA_GetSize(TwoHeadArena* tha) { - return (u32)tha->tail - (u32)tha->head; +/** + * Gets the remaining size of the Two Head Arena + * + * @return Remaining size. A negative number indicates an overflow. + */ +s32 THA_GetRemaining(TwoHeadArena* tha) { + return (s32)((u8*)tha->tail - (u8*)tha->head); } +/** + * @return true if the Two Head Arena has overflowed, false otherwise + */ u32 THA_IsCrash(TwoHeadArena* tha) { - return THA_GetSize(tha) < 0; + return THA_GetRemaining(tha) < 0; } -void THA_Init(TwoHeadArena* tha) { - tha->head = tha->bufp; - tha->tail = (u32)tha->bufp + tha->size; +void THA_Reset(TwoHeadArena* tha) { + tha->head = tha->start; + tha->tail = (u8*)tha->start + tha->size; } -void THA_Ct(TwoHeadArena* tha, void* ptr, size_t size) { +/** + * Creates a new Two Head Arena at `start` with available size `size` + */ +void THA_Init(TwoHeadArena* tha, void* start, size_t size) { bzero(tha, sizeof(TwoHeadArena)); - tha->bufp = ptr; + tha->start = start; tha->size = size; - THA_Init(tha); + THA_Reset(tha); } -void THA_Dt(TwoHeadArena* tha) { +/** + * Destroys the Two Head Arena, no further allocations are possible + */ +void THA_Destroy(TwoHeadArena* tha) { bzero(tha, sizeof(TwoHeadArena)); } -- cgit v1.2.3