--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+// 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;
+}