182 lines
3.9 KiB
C
182 lines
3.9 KiB
C
#include <stdlib.h>
|
|
|
|
#define BLOCK_SIZE (64 * 1024)
|
|
#define BLOCK_1MB 16
|
|
|
|
typedef struct header {
|
|
size_t size : 31;
|
|
uint8_t is_free : 1;
|
|
} header_t;
|
|
static header_t* head;
|
|
|
|
static uintptr_t bump_pointer = (uintptr_t)&__heap_base;
|
|
static uintptr_t heap_end = BLOCK_1MB * BLOCK_SIZE;
|
|
IMPORT(grow) void grow(uint32_t blocks);
|
|
|
|
static void* bump_alloc(uintptr_t n) {
|
|
uintptr_t r = bump_pointer;
|
|
bump_pointer += n;
|
|
|
|
while (bump_pointer >= heap_end) {
|
|
grow(heap_end / BLOCK_SIZE);
|
|
heap_end *= 2;
|
|
}
|
|
|
|
return (void*)r;
|
|
}
|
|
|
|
static header_t* get_next_header(header_t* block) {
|
|
if (!block) {
|
|
return NULL;
|
|
}
|
|
uint8_t* data = (uint8_t*)(block + 1);
|
|
uint8_t* next_header = data + block->size;
|
|
if ((uintptr_t)next_header >= bump_pointer) {
|
|
return NULL;
|
|
}
|
|
return (header_t*)next_header;
|
|
}
|
|
|
|
static header_t* get_prev_header(header_t* block) {
|
|
header_t* curr = head;
|
|
while (curr) {
|
|
header_t* next = get_next_header(curr);
|
|
if (next == block) {
|
|
return curr;
|
|
}
|
|
curr = next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static header_t* get_free_block(size_t size) {
|
|
header_t* curr = head;
|
|
while (curr) {
|
|
if (curr->is_free && curr->size >= size) {
|
|
return curr;
|
|
}
|
|
curr = get_next_header(curr);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void* malloc(size_t size) {
|
|
if (!size) {
|
|
return NULL;
|
|
}
|
|
|
|
header_t* header = get_free_block(size);
|
|
if (header) {
|
|
header->is_free = 0;
|
|
if (header->size > size + sizeof(header_t) * 2) {
|
|
size_t old_size = header->size;
|
|
header->size = size;
|
|
|
|
header_t* next = get_next_header(header);
|
|
next->size = old_size - size - sizeof(header_t);
|
|
next->is_free = 1;
|
|
}
|
|
return (void*)(header + 1);
|
|
}
|
|
size_t total_size = sizeof(header_t) + size;
|
|
|
|
void* block = bump_alloc(total_size);
|
|
if (!block) {
|
|
return NULL;
|
|
}
|
|
|
|
header = block;
|
|
header->size = size;
|
|
header->is_free = 0;
|
|
|
|
if (!head) {
|
|
head = header;
|
|
}
|
|
|
|
return (void*)(header + 1);
|
|
}
|
|
|
|
void free(void* block) {
|
|
if (!block) {
|
|
return;
|
|
}
|
|
|
|
header_t* header = ((header_t*)block) - 1;
|
|
if (header->is_free) {
|
|
return;
|
|
}
|
|
header->is_free = 1;
|
|
|
|
header_t* next_header = get_next_header(header);
|
|
if (next_header && next_header->is_free) {
|
|
header->size += next_header->size + sizeof(header_t);
|
|
}
|
|
|
|
header_t* prev_header = get_prev_header(header);
|
|
if (prev_header && prev_header->is_free) {
|
|
prev_header->size += header->size + sizeof(header_t);
|
|
}
|
|
}
|
|
|
|
void* realloc(void* block, size_t size) {
|
|
header_t* header;
|
|
void* ret;
|
|
|
|
if (!block || !size)
|
|
return malloc(size);
|
|
|
|
header = (header_t*)block - 1;
|
|
if (header->size >= size)
|
|
return block;
|
|
|
|
ret = malloc(size);
|
|
if (ret) {
|
|
memcpy(ret, block, header->size);
|
|
free(block);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void* memset(void* s, uint8_t c, uint32_t n) {
|
|
uint8_t* p = (uint8_t*)s;
|
|
while (n--) {
|
|
*p++ = c;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
void* memcpy(void* dest, const void* src, uint32_t n) {
|
|
uint8_t* d = (uint8_t*)dest;
|
|
const uint8_t* s = (const uint8_t*)src;
|
|
while (n--) {
|
|
*d++ = *s++;
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
int memcmp(const void* s1, const void* s2, uint32_t n) {
|
|
const uint8_t* p1 = (const uint8_t*)s1;
|
|
const uint8_t* p2 = (const uint8_t*)s2;
|
|
|
|
while (n--) {
|
|
if (*p1 != *p2) {
|
|
return (*p1 - *p2);
|
|
}
|
|
p1++;
|
|
p2++;
|
|
}
|
|
|
|
return 0; // Memory blocks are equal
|
|
}
|
|
|
|
static uint64_t rand_state;
|
|
|
|
void srand(uint64_t seed) { rand_state = seed; }
|
|
|
|
uint64_t rand(void) {
|
|
uint64_t z = (rand_state += 0x9e3779b97f4a7c15);
|
|
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
|
|
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
|
|
return z ^ (z >> 31);
|
|
}
|