repos / gcs.git


Evgenii Akentev  ·  2024-09-14

mark_sweep.c

  1#include <stdio.h>
  2#include <stdlib.h>
  3
  4// To simplify things sizes are statically defined
  5#define FIELDS_SIZE 4
  6#define HEAP_SIZE 8
  7#define ROOTS_SIZE 4
  8#define WORKLIST_SIZE 100
  9
 10struct Object;
 11
 12typedef struct Object {
 13  int val;
 14  int field_size;
 15  int isMarked;
 16  struct Object* fields[FIELDS_SIZE];
 17} Object;
 18
 19typedef struct {
 20  int size;
 21  Object** objects;
 22} Heap;
 23
 24typedef struct {
 25  int size;
 26  Object* objects[ROOTS_SIZE];
 27} Roots;
 28
 29typedef struct {
 30  int current;
 31  Object* objects[WORKLIST_SIZE];
 32} Worklist;
 33
 34void push(Worklist* w, Object* o) {
 35  w->current += 1;
 36  w->objects[w->current] = o;
 37}
 38
 39int isEmpty(Worklist *w) {
 40  if (w->current == -1) return 1;
 41
 42  return 0;
 43}
 44
 45Object* pop(Worklist *w) {
 46  Object* item = w->objects[w->current];
 47  w->current -= 1;
 48  return item;
 49}
 50
 51Heap* mkHeap () {
 52  Heap* h = malloc(sizeof(Heap));
 53  h->size = HEAP_SIZE;
 54  h->objects = calloc(h->size, sizeof(Object*));
 55  return h;
 56}
 57
 58int heapObjectsNumber(Heap* h) {
 59  int c = 0;
 60  for (int i = 0; i < h->size; i++) {
 61    if (h->objects[i] != NULL) c++;
 62  }
 63  return c;
 64}
 65
 66void freeHeap (Heap* h) {
 67  for (int i = 0; i < h->size; i++) {
 68    if (h->objects[i] != NULL) {
 69      free(h->objects[i]);
 70    }
 71  }
 72  free(h->objects);
 73  free(h);
 74}
 75
 76Object* allocate(int val, Heap* h) {
 77  Object* p = NULL;
 78  for (int i = 0; i < h->size; i++) {
 79    if (h->objects[i] == NULL && p == NULL) {
 80      p = malloc(sizeof(Object));
 81      *p = (Object){val, FIELDS_SIZE, 0, NULL};
 82      h->objects[i] = p;
 83    }
 84  }
 85  return p;
 86}
 87
 88void mark(Heap* h, Roots* roots, Worklist* w) {
 89  while (isEmpty(w) == 0) {
 90    Object *ref = pop(w);
 91    for (int i = 0; i < ref->field_size; i++) {
 92       Object* child = ref->fields[i];
 93      if (child != NULL && child->isMarked != 1) {
 94        child->isMarked = 1;
 95        push(w, child);
 96      }
 97    }
 98  }
 99}
100
101void markFromRoots(Heap* h, Roots* roots) {
102  Worklist worklist;
103  worklist.current = -1;
104
105  for (int i = 0; i < roots->size; i++) {
106    Object* ref = roots->objects[i];
107    if (ref != NULL && ref->isMarked != 1) {
108      ref->isMarked = 1;
109      push(&worklist, ref);
110      mark(h, roots, &worklist);
111    }
112  }
113}
114
115void sweep(Heap *h) {
116  for (int i = 0; i < h->size; i++) {
117    if (h->objects[i] != NULL) {
118      if (h->objects[i]->isMarked == 1) {
119        h->objects[i]->isMarked = 0; 
120      } else {
121        free(h->objects[i]);
122        h->objects[i] = NULL;
123      }
124    }
125  }
126}
127
128void collect(Heap* h, Roots* roots) {
129  markFromRoots(h, roots);
130  sweep(h);
131}
132
133Object* new(int val, Heap* h, Roots* roots) {
134  Object* ref = allocate(val, h);
135  if (ref == NULL) {
136    printf("Running collect");
137    collect(h, roots);
138    ref = allocate(val, h);
139    if (ref == NULL) {
140      printf("Out of memory\n");
141      exit(0);
142    }
143  }
144  return ref;
145}
146
147int main() {
148  Heap* h = mkHeap();
149  Roots roots;
150  roots.size = ROOTS_SIZE;
151  for (int i = 0; i < roots.size; i++) {
152    roots.objects[i] = NULL;
153  }
154
155  // mutator
156  roots.objects[0] = new(7, h, &roots);
157  roots.objects[0] = new(5, h, &roots);
158
159  roots.objects[0]->fields[0] = new(8, h, &roots);
160
161  printf("heap size before collect: %d\n", heapObjectsNumber(h));
162  printf("heap third obj value: %d\n", h->objects[2]->val);
163
164  collect(h, &roots);
165
166  printf("heap second obj value: %d\n", h->objects[1]->val);
167
168  printf("heap size after collect: %d\n", heapObjectsNumber(h));
169
170  freeHeap(h);
171  return 0;
172}