diff --git a/src/ast/ast.c b/src/ast/ast.c index 8adfe31..efd737b 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -4,6 +4,7 @@ #include #include #include +#include AST_NODE_PTR AST_new_node(enum AST_SyntaxElement_t kind, const char* value) { DEBUG("creating new AST node: %d \"%s\"", kind, value); diff --git a/src/gc/gc.c b/src/gc/gc.c new file mode 100644 index 0000000..7648655 --- /dev/null +++ b/src/gc/gc.c @@ -0,0 +1,113 @@ +// +// Created by servostar on 5/7/24. +// + +#include +#include +#include + +#undef malloc +#undef free +#undef realloc + +#define GC_HEAP_PREALLOC_CNT 10 + +typedef struct GC_Heap_Statistics_t { + size_t bytes; +} GC_Heap_Statistics; + +static struct GC_Heap_t { + RAW_PTR* blocks; + size_t cap; + size_t len; + GC_Heap_Statistics statistics; +} GC_GLOBAL_HEAP; + +static void __GC_teardown(void) { + INFO("Used %ld bytes in total", GC_GLOBAL_HEAP.statistics.bytes); + + if (GC_GLOBAL_HEAP.blocks == NULL) { + return; + } + + for (size_t i = 0; i < GC_GLOBAL_HEAP.len; i++) { + free(GC_GLOBAL_HEAP.blocks[i]); + } + + free(GC_GLOBAL_HEAP.blocks); + + GC_GLOBAL_HEAP.blocks = NULL; +} + +static void __GC_check_init(void) { + if (GC_GLOBAL_HEAP.blocks == NULL) { + GC_GLOBAL_HEAP.cap = GC_HEAP_PREALLOC_CNT; + const size_t bytes = sizeof(RAW_PTR) * GC_GLOBAL_HEAP.cap; + GC_GLOBAL_HEAP.blocks = malloc(bytes); + GC_GLOBAL_HEAP.len = 0; + } +} + +void GC_init(void) { + atexit(__GC_teardown); +} + +static void __GC_check_overflow(void) { + if (GC_GLOBAL_HEAP.len >= GC_GLOBAL_HEAP.cap) { + GC_GLOBAL_HEAP.cap += GC_HEAP_PREALLOC_CNT; + const size_t bytes = sizeof(RAW_PTR) * GC_GLOBAL_HEAP.cap; + GC_GLOBAL_HEAP.blocks = realloc(GC_GLOBAL_HEAP.blocks, bytes); + } +} + +RAW_PTR GC_malloc(const size_t bytes) { + const RAW_PTR ptr = malloc(bytes); + + if (ptr == NULL) { + FATAL("unable to allocate memory"); + } + + __GC_check_init(); + __GC_check_overflow(); + + GC_GLOBAL_HEAP.blocks[GC_GLOBAL_HEAP.len++] = ptr; + + GC_GLOBAL_HEAP.statistics.bytes += bytes; + + return ptr; +} + +static void __GC_swap_ptr(RAW_PTR old, RAW_PTR new) { + for (size_t i = 0; i < GC_GLOBAL_HEAP.len; i++) { + if (GC_GLOBAL_HEAP.blocks[i] == old) { + GC_GLOBAL_HEAP.blocks[i] = new; + } + } +} + +RAW_PTR GC_realloc(RAW_PTR ptr, size_t bytes) { + const RAW_PTR new_ptr = (RAW_PTR) realloc(ptr, bytes); + + if (new_ptr == NULL) { + FATAL("unable to reallocate memory"); + } + + __GC_swap_ptr(ptr, new_ptr); + + return new_ptr; +} + +void GC_free(RAW_PTR ptr) { + DEBUG("freeing memory: %p", ptr); + + for (size_t i = 0; i < GC_GLOBAL_HEAP.len; i++) { + + if (ptr == GC_GLOBAL_HEAP.blocks[i]) { + free(GC_GLOBAL_HEAP.blocks[i]); + + GC_GLOBAL_HEAP.len--; + + memcpy(&GC_GLOBAL_HEAP.blocks[i], &GC_GLOBAL_HEAP.blocks[i + 1], GC_GLOBAL_HEAP.len - i); + } + } +} diff --git a/src/gc/gc.h b/src/gc/gc.h new file mode 100644 index 0000000..6fe17a3 --- /dev/null +++ b/src/gc/gc.h @@ -0,0 +1,24 @@ +// +// Created by servostar on 5/7/24. +// + +#ifndef GC_H +#define GC_H + +#include + +#define malloc GC_malloc +#define free GC_free +#define realloc GC_realloc + +typedef void* RAW_PTR; + +void GC_init(void); + +RAW_PTR GC_malloc(size_t bytes); + +RAW_PTR GC_realloc(RAW_PTR ptr, size_t bytes); + +void GC_free(RAW_PTR ptr); + +#endif //GC_H diff --git a/src/lex/lexer.l b/src/lex/lexer.l index 8823195..129af69 100644 --- a/src/lex/lexer.l +++ b/src/lex/lexer.l @@ -2,6 +2,7 @@ %{ #include #include + #include int yyLineNumber = 1; int yylex(); diff --git a/src/main.c b/src/main.c index 1689ff0..0b56d88 100644 --- a/src/main.c +++ b/src/main.c @@ -2,6 +2,7 @@ #include #include #include +#include #define LOG_LEVEL LOG_LEVEL_DEBUG @@ -47,6 +48,8 @@ void setup(void) // actual setup AST_init(); + GC_init(); + DEBUG("finished starting up gemstone..."); } diff --git a/src/sys/log.h b/src/sys/log.h index aa18c88..3b4f7ed 100644 --- a/src/sys/log.h +++ b/src/sys/log.h @@ -2,7 +2,7 @@ #define _SYS_ERR_H_ #include -#include +#include #define LOG_DEFAULT_STREAM stderr