Commit ae57894

kravantokh <kravantokh@noreply.codeberg.org>
2026-08-18 13:18:12
Refactor heap implementation.
1 parent 6a64487
Changed files (3)
memory/heap/heap_debug.h
@@ -19,6 +19,74 @@ STRUCT( Heap,
 	HeapEntry blocklist; /* The existing blocks in a list */
 );
 
+static inline Status _Heap_find_block( Heap *h, HeapEntry *e, HeapEntry **out_prev ) {
+	u8 ptr_correct = 0;
+	HeapEntry *prev = &h->blocklist;
+
+	for( HeapEntry *i = h->blocklist.next; i != 0; i = i->next ) {
+		if( e == i ) {
+			ptr_correct = 1;
+			break;
+		}
+		prev = i;
+	}
+
+	/* The pointer is not pointing to a previously allocated block if this fails or perhaps it is a double-free. */
+	assert( ptr_correct );
+	if( !ptr_correct ) {
+		return S_FAILURE;
+	}
+
+	*out_prev = prev;
+	return S_SUCCESS;
+}
+
+static inline Status _Heap_check_entry( HeapEntry *e ) {
+	u8 ok = 1;
+
+	assert( e->checksum == (e->size ^ e->allowed_size ^ (usize)e->next ^ HEAP_XOR_KEY) || (ok = 0) );
+	assert( e->header_start_guard == HEAP_HEADER_GUARD_NUMBER || (ok = 0) );
+	assert( e->header_end_guard == HEAP_HEADER_GUARD_NUMBER || (ok = 0) );
+	assert( e->allowed_size >= e->size || (ok = 0) );
+
+	u8* data = (u8*)(&e->header_end_guard + 1);
+	assert( *(usize*)(data + e->allowed_size) = HEAP_OVERRUN_GUARD_NUMBER || (ok = 0) );
+
+	if( !ok ) {
+		return S_FAILURE;
+	} else {
+		return S_SUCCESS;
+	}
+}
+
+static inline void _Heap_unlink_entry( HeapEntry *prev, HeapEntry *e ) {
+	prev->next = e->next;
+	prev->checksum = prev->size ^ prev->allowed_size ^ (usize)prev->next ^ HEAP_XOR_KEY;
+}
+
+static inline void _Heap_link_free_entry( Heap *h, HeapEntry *e ) {
+	e->next = h->freelist.next;
+	h->freelist.next = e;
+	e->checksum = e->size ^ e->allowed_size ^ (usize)e->next ^ HEAP_XOR_KEY;
+}
+
+
+static inline void _Heap_link_block( Heap *h, HeapEntry *e ) {
+	e->next = h->blocklist.next;
+	h->blocklist.next = e;
+	e->checksum = e->size ^ e->allowed_size ^ (usize)e->next ^ HEAP_XOR_KEY;
+}
+
+static inline usize Heap_get_asize( Heap *h, u8 *ptr ) {
+	HeapEntry *e = (HeapEntry*)( ptr - sizeof(HeapEntry) );
+	HeapEntry *prev = 0;
+	_Heap_check_entry( e );
+	_Heap_find_block( h, e, &prev );
+	return e->size;
+}
+
+#ifdef NOTLIBC_IMPLEMENT
+
 Status Heap_create( Heap *out, usize size ) {
 	assert( out != 0 );
 	assert( size != 0 );
@@ -53,19 +121,14 @@ Status Heap_alloc( Heap *h, usize amount, u8 **out ) {
 
 		u8* data = (u8*)(&i->header_end_guard + 1);
 		/* If any of these fails, then your freelist has been corrupted somehow - it should not be iterated */
-		assert( i->header_start_guard == HEAP_HEADER_GUARD_NUMBER );
-		assert( i->header_end_guard == HEAP_HEADER_GUARD_NUMBER );
-		assert( i->checksum == (i->size ^ i->allowed_size ^ (usize)i->next ^ HEAP_XOR_KEY) );
-		assert( i->allowed_size >= i->size );
-		assert( *(usize*)(data + i->allowed_size) == HEAP_OVERRUN_GUARD_NUMBER );
+		_Heap_check_entry(i);
 
 		if( i->allowed_size >= amount && i->allowed_size <= max_size ) {
 			new = i;
 			for( usize i = 0; i < new->allowed_size; ++i ) {
 				assert( data[i] == MAGIC_FREED_MEM );
 			}
-			prev->next = new->next;
-			prev->checksum = (prev->size ^ prev->allowed_size ^ (usize)prev->next ^ HEAP_XOR_KEY);
+			_Heap_unlink_entry( prev, new );
 			new->next = 0;
 			break;
 		}
@@ -85,12 +148,10 @@ Status Heap_alloc( Heap *h, usize amount, u8 **out ) {
 
 	*(usize*)(data + new->allowed_size) = HEAP_OVERRUN_GUARD_NUMBER;
 
-	new->next = h->blocklist.next;
-	h->blocklist.next = new;
 	new->size = amount;
-	new->checksum = new->size ^ new->allowed_size ^ (usize)new->next ^ HEAP_XOR_KEY;
 	new->header_start_guard = HEAP_HEADER_GUARD_NUMBER;
 	new->header_end_guard = HEAP_HEADER_GUARD_NUMBER;
+	_Heap_link_block( h, new );
 
 	*out = data;
 
@@ -103,31 +164,13 @@ Status Heap_free( Heap *h, u8 **ptr ) {
 
 	HeapEntry *e = (HeapEntry*)( (u8*)*ptr - sizeof(HeapEntry) );
 
-	u8 ptr_correct = 0;
-	HeapEntry *prev = &h->blocklist;
+	HeapEntry *prev = 0;
 
-	for( HeapEntry *i = h->blocklist.next; i != 0; i = i->next ) {
-		if( e == i ) {
-			ptr_correct = 1;
-			break;
-		}
-		prev = i;
-	}
-
-	/* The pointer is not pointing to a previously allocated block if this fails or perhaps it is a double-free. */
-	assert(ptr_correct);
-
-	/* Check header corruption */
-	assert( e->checksum == (e->size ^ e->allowed_size ^ (usize)e->next ^ HEAP_XOR_KEY) );
-	assert( e->header_start_guard == HEAP_HEADER_GUARD_NUMBER );
-	assert( e->header_end_guard == HEAP_HEADER_GUARD_NUMBER );
+	assert(S_OK( _Heap_find_block( h, e, &prev ) ));
+	assert(S_OK( _Heap_check_entry( e ) ));
 
-	prev->next = e->next;
-	prev->checksum = prev->size ^ prev->allowed_size ^ (usize)prev->next ^ HEAP_XOR_KEY;
-
-	e->next = h->freelist.next;
-	h->freelist.next = e;
-	e->checksum = e->size ^ e->allowed_size ^ (usize)e->next ^ HEAP_XOR_KEY;
+	_Heap_unlink_entry( prev, e );
+	_Heap_link_free_entry( h, e );
 
 	u8* data = (u8*)(&e->header_end_guard + 1);
 	mem_set( data, e->allowed_size, MAGIC_FREED_MEM );
@@ -138,5 +181,6 @@ Status Heap_free( Heap *h, u8 **ptr ) {
 	return S_SUCCESS;
 }
 
+#endif
 
 #endif
memory/heap/heap_release.h
@@ -13,6 +13,13 @@ STRUCT( Heap,
 	HeapEntry *freelist_data;
 );
 
+static inline usize Heap_get_asize( Heap *h, u8 *ptr ) {
+	(void)h;
+	return *((usize*)ptr - 1);
+}
+
+#ifdef NOTLIBC_IMPLEMENT
+
 Status Heap_create( Heap *out, usize size ) {
 	TRY( Arena_create( &out->arena, size ) );
 	out->freelist = (HeapEntry){0};
@@ -78,5 +85,7 @@ Status Heap_free( Heap *h, u8 **ptr ) {
 	return S_SUCCESS;
 }
 
+#endif
+
 
 #endif
memory/heap.h
@@ -4,12 +4,10 @@
 #include "datatypes/error.h"
 #include "platform/info/build.h"
 
-#ifdef NOTLIBC_IMPLEMENT
-	#if BUILD_TYPE == BUILD_RELEASE
-		#include "./heap/heap_release.h"
-	#elif BUILD_TYPE == BUILD_DEBUG
-		#include "./heap/heap_debug.h"
-	#endif
+#if BUILD_TYPE == BUILD_RELEASE
+	#include "./heap/heap_release.h"
+#elif BUILD_TYPE == BUILD_DEBUG
+	#include "./heap/heap_debug.h"
 #endif
 
 ASSERT( sizeof(HeapEntry)%sizeof(usize) == 0 );
@@ -21,6 +19,8 @@ Status Heap_create( Heap *out, usize size ); /* size - size of underlying arena.
 Status Heap_alloc( Heap *h, usize amount, u8 **out );
 Status Heap_free( Heap *h, u8 **ptr ); /* u8** cause it zeroes the pointer on success automatically. */
 
+static inline usize Heap_get_asize( Heap *h, u8 *ptr );
+
 Status Heap_destroy( Heap *h );
 
 #endif