123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- #include <stdio.h>
- #include <stdbool.h>
- #include <string.h>
- #include "./heap.h"
- uintptr_t heap[HEAP_CAP_WORDS] = {0};
- const uintptr_t *stack_base = 0;
- bool reachable_chunks[CHUNK_LIST_CAP] = {0};
- void *to_free[CHUNK_LIST_CAP] = {0};
- size_t to_free_count = 0;
- Chunk_List alloced_chunks = {0};
- Chunk_List freed_chunks = {
- .count = 1,
- .chunks = {
- [0] = {.start = heap, .size = sizeof(heap)}
- },
- };
- Chunk_List tmp_chunks = {0};
- void chunk_list_insert(Chunk_List *list, void *start, size_t size)
- {
- assert(list->count < CHUNK_LIST_CAP);
- list->chunks[list->count].start = start;
- list->chunks[list->count].size = size;
- for (size_t i = list->count;
- i > 0 && list->chunks[i].start < list->chunks[i - 1].start;
- --i) {
- const Chunk t = list->chunks[i];
- list->chunks[i] = list->chunks[i - 1];
- list->chunks[i - 1] = t;
- }
- list->count += 1;
- }
- void chunk_list_merge(Chunk_List *dst, const Chunk_List *src)
- {
- dst->count = 0;
- for (size_t i = 0; i < src->count; ++i) {
- const Chunk chunk = src->chunks[i];
- if (dst->count > 0) {
- Chunk *top_chunk = &dst->chunks[dst->count - 1];
- if (top_chunk->start + top_chunk->size == chunk.start) {
- top_chunk->size += chunk.size;
- } else {
- chunk_list_insert(dst, chunk.start, chunk.size);
- }
- } else {
- chunk_list_insert(dst, chunk.start, chunk.size);
- }
- }
- }
- void chunk_list_dump(const Chunk_List *list, const char *name)
- {
- printf("%s Chunks (%zu):\n", name, list->count);
- for (size_t i = 0; i < list->count; ++i) {
- printf(" start: %p, size: %zu\n",
- (void*) list->chunks[i].start,
- list->chunks[i].size);
- }
- }
- int chunk_list_find(const Chunk_List *list, uintptr_t *ptr)
- {
- for (size_t i = 0; i < list->count; ++i) {
- if (list->chunks[i].start == ptr) {
- return (int) i;
- }
- }
- return -1;
- }
- void chunk_list_remove(Chunk_List *list, size_t index)
- {
- assert(index < list->count);
- for (size_t i = index; i < list->count - 1; ++i) {
- list->chunks[i] = list->chunks[i + 1];
- }
- list->count -= 1;
- }
- void *heap_alloc(size_t size_bytes)
- {
- const size_t size_words = (size_bytes + sizeof(uintptr_t) - 1) / sizeof(uintptr_t);
- if (size_words > 0) {
- chunk_list_merge(&tmp_chunks, &freed_chunks);
- freed_chunks = tmp_chunks;
- for (size_t i = 0; i < freed_chunks.count; ++i) {
- const Chunk chunk = freed_chunks.chunks[i];
- if (chunk.size >= size_words) {
- chunk_list_remove(&freed_chunks, i);
- const size_t tail_size_words = chunk.size - size_words;
- chunk_list_insert(&alloced_chunks, chunk.start, size_words);
- if (tail_size_words > 0) {
- chunk_list_insert(&freed_chunks, chunk.start + size_words, tail_size_words);
- }
- return chunk.start;
- }
- }
- }
- return NULL;
- }
- void heap_free(void *ptr)
- {
- if (ptr != NULL) {
- const int index = chunk_list_find(&alloced_chunks, ptr);
- assert(index >= 0);
- assert(ptr == alloced_chunks.chunks[index].start);
- chunk_list_insert(&freed_chunks,
- alloced_chunks.chunks[index].start,
- alloced_chunks.chunks[index].size);
- chunk_list_remove(&alloced_chunks, (size_t) index);
- }
- }
- static void mark_region(const uintptr_t *start, const uintptr_t *end)
- {
- for (; start < end; start += 1) {
- const uintptr_t *p = (const uintptr_t *) *start;
- for (size_t i = 0; i < alloced_chunks.count; ++i) {
- Chunk chunk = alloced_chunks.chunks[i];
- if (chunk.start <= p && p < chunk.start + chunk.size) {
- if (!reachable_chunks[i]) {
- reachable_chunks[i] = true;
- mark_region(chunk.start, chunk.start + chunk.size);
- }
- }
- }
- }
- }
- void heap_collect()
- {
- const uintptr_t *stack_start = (const uintptr_t*)__builtin_frame_address(0);
- memset(reachable_chunks, 0, sizeof(reachable_chunks));
- mark_region(stack_start, stack_base + 1);
- to_free_count = 0;
- for (size_t i = 0; i < alloced_chunks.count; ++i) {
- if (!reachable_chunks[i]) {
- assert(to_free_count < CHUNK_LIST_CAP);
- to_free[to_free_count++] = alloced_chunks.chunks[i].start;
- }
- }
- for (size_t i = 0; i < to_free_count; ++i) {
- heap_free(to_free[i]);
- }
- }
|