From: Evgenii Akentev Date: Tue, 10 Sep 2024 08:55:53 +0000 (+0400) Subject: Add basic mark-sweep X-Git-Url: https://git.ak3n.com/?a=commitdiff_plain;h=60f2e3f7dd3fb1e7f18aa49425974d184d149dfb;p=gcs.git Add basic mark-sweep --- 60f2e3f7dd3fb1e7f18aa49425974d184d149dfb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cba7efc --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +a.out diff --git a/mark-sweep/basic.c b/mark-sweep/basic.c new file mode 100644 index 0000000..1da70d4 --- /dev/null +++ b/mark-sweep/basic.c @@ -0,0 +1,172 @@ +#include +#include + +// To simplify things sizes are statically defined +#define FIELDS_SIZE 4 +#define HEAP_SIZE 8 +#define ROOTS_SIZE 4 +#define WORKLIST_SIZE 100 + +struct Object; + +typedef struct Object { + int val; + int field_size; + int isMarked; + struct Object* fields[FIELDS_SIZE]; +} Object; + +typedef struct { + int size; + Object** objects; +} Heap; + +typedef struct { + int size; + Object* objects[ROOTS_SIZE]; +} Roots; + +typedef struct { + int current; + Object* objects[WORKLIST_SIZE]; +} Worklist; + +void push(Worklist* w, Object* o) { + w->current += 1; + w->objects[w->current] = o; +} + +int isEmpty(Worklist *w) { + if (w->current == -1) return 1; + + return 0; +} + +Object* pop(Worklist *w) { + Object* item = w->objects[w->current]; + w->current -= 1; + return item; +} + +Heap* mkHeap () { + Heap* h = malloc(sizeof(Heap)); + h->size = HEAP_SIZE; + h->objects = calloc(h->size, sizeof(Object*)); + return h; +} + +int heapObjectsNumber(Heap* h) { + int c = 0; + for (int i = 0; i < h->size; i++) { + if (h->objects[i] != NULL) c++; + } + return c; +} + +void freeHeap (Heap* h) { + for (int i = 0; i < h->size; i++) { + if (h->objects[i] != NULL) { + free(h->objects[i]); + } + } + free(h->objects); + free(h); +} + +Object* allocate(int val, Heap* h) { + Object* p = NULL; + for (int i = 0; i < h->size; i++) { + if (h->objects[i] == NULL && p == NULL) { + p = malloc(sizeof(Object)); + *p = (Object){val, FIELDS_SIZE, 0, NULL}; + h->objects[i] = p; + } + } + return p; +} + +void mark(Heap* h, Roots* roots, Worklist* w) { + while (isEmpty(w) == 0) { + Object *ref = pop(w); + for (int i = 0; i < ref->field_size; i++) { + Object* child = ref->fields[i]; + if (child != NULL && child->isMarked != 1) { + child->isMarked = 1; + push(w, child); + } + } + } +} + +void markFromRoots(Heap* h, Roots* roots) { + Worklist worklist; + worklist.current = -1; + + for (int i = 0; i < roots->size; i++) { + Object* ref = roots->objects[i]; + if (ref != NULL && ref->isMarked != 1) { + ref->isMarked = 1; + push(&worklist, ref); + mark(h, roots, &worklist); + } + } +} + +void sweep(Heap *h) { + for (int i = 0; i < h->size; i++) { + if (h->objects[i] != NULL) { + if (h->objects[i]->isMarked == 1) { + h->objects[i]->isMarked = 0; + } else { + free(h->objects[i]); + h->objects[i] = NULL; + } + } + } +} + +void collect(Heap* h, Roots* roots) { + markFromRoots(h, roots); + sweep(h); +} + +Object* new(int val, Heap* h, Roots* roots) { + Object* ref = allocate(val, h); + if (ref == NULL) { + printf("Running collect"); + collect(h, roots); + ref = allocate(val, h); + if (ref == NULL) { + printf("Out of memory\n"); + exit(0); + } + } + return ref; +} + +int main() { + Heap* h = mkHeap(); + Roots roots; + roots.size = ROOTS_SIZE; + for (int i = 0; i < roots.size; i++) { + roots.objects[i] = NULL; + } + + // mutator + roots.objects[0] = new(7, h, &roots); + roots.objects[0] = new(5, h, &roots); + + roots.objects[0]->fields[0] = new(8, h, &roots); + + printf("heap size before collect: %d\n", heapObjectsNumber(h)); + printf("heap third obj value: %d\n", h->objects[2]->val); + + collect(h, &roots); + + printf("heap second obj value: %d\n", h->objects[1]->val); + + printf("heap size after collect: %d\n", heapObjectsNumber(h)); + + freeHeap(h); + return 0; +}