blob: b9e95749d7f4b8bc900810df90bf3e00c4ded4bb [file] [log] [blame]
swissChili6d6525e2021-06-15 21:20:53 -07001#include "gc.h"
2#include "lisp.h"
swissChilie9fec8b2021-06-22 13:59:33 -07003#include "plat/plat.h"
swissChili6d6525e2021-06-15 21:20:53 -07004
swissChili9e57da42021-06-15 22:22:46 -07005value_t *gc_base;
swissChilie9fec8b2021-06-22 13:59:33 -07006THREAD_LOCAL static unsigned int gc_mark;
swissChili6d6525e2021-06-15 21:20:53 -07007
swissChili9e57da42021-06-15 22:22:46 -07008void __attribute__((noinline)) gc_set_base_here()
9{
10 // Move the current stack top address to gc_base. This works nicely because
11 // it means that when another (presumably lisp) function is called right
12 // after this, the stack top for it will be the same as for this function.
13 asm("movl %%esp, %0" : "=g"(gc_base));
14}
15
swissChilie9fec8b2021-06-22 13:59:33 -070016void _mark(value_t value, unsigned int *marked)
swissChili9e57da42021-06-15 22:22:46 -070017{
18 if (heapp(value))
19 {
swissChilie9fec8b2021-06-22 13:59:33 -070020 void *pointer = (void *)(value & ~HEAP_MASK);
21 struct alloc *alloc = pointer - sizeof(struct alloc);
swissChili9e57da42021-06-15 22:22:46 -070022
swissChilie9fec8b2021-06-22 13:59:33 -070023 fprintf(stderr, "[ GC ] Marking 0x%p\n", pointer);
24
25 // Only recursively mark if this hasn't been marked yet. i.e. prevent
26 // marking circular references twice
27 if (alloc->mark != gc_mark)
28 {
29 ++*marked;
30
31 alloc->mark = gc_mark;
32
33 // printf("[ GC ] val =");
34 // printval(alloc_to_value(alloc), 2);
35
36 switch (alloc->type_tag)
37 {
38 case CONS_TAG: {
39 struct cons_alloc *cons = (struct cons_alloc *)alloc;
40 _mark(cons->cons.car, marked);
41 _mark(cons->cons.cdr, marked);
42 break;
43 }
44 }
45 }
swissChili9e57da42021-06-15 22:22:46 -070046 }
swissChili6d6525e2021-06-15 21:20:53 -070047}
48
swissChilie9fec8b2021-06-22 13:59:33 -070049value_t alloc_to_value(struct alloc *a)
50{
51 void *val = ((void *)a) + sizeof(struct alloc);
52 return (unsigned int)val | a->type_tag;
53}
54
swissChili6d6525e2021-06-15 21:20:53 -070055void _sweep()
56{
swissChilie9fec8b2021-06-22 13:59:33 -070057 for (struct alloc *a = first_a; a; a = a->next)
58 {
swissChilib8fd4712021-06-23 15:32:04 -070059 if (pool_alive(a->pool) || a->mark == gc_mark)
60 {
61 // Marked or in living pool
62 }
63 else
64 {
65 printf("Freeing:\n");
66 printval(alloc_to_value(a), 2);
67
68 // Free and remove from allocation list
69 struct alloc *p = a->prev, *n = a->next;
70 free_aligned(a);
71
72 a = n;
73
74 if (p)
75 p->next = n;
76
77 if (n)
78 n->prev = p;
79 }
swissChilie9fec8b2021-06-22 13:59:33 -070080 }
swissChili6d6525e2021-06-15 21:20:53 -070081}
82
83void _do_gc(unsigned int esp, unsigned int ebp)
84{
swissChili9e57da42021-06-15 22:22:46 -070085 value_t *esp_p = (value_t *)esp,
86 *ebp_p = (value_t *)ebp;
swissChili6d6525e2021-06-15 21:20:53 -070087
swissChilie9fec8b2021-06-22 13:59:33 -070088 unsigned int num_marked = 0;
89
90 gc_mark++;
91
92 fprintf(stderr, "[ GC ] %d (esp 0x%p, ebp 0x%p)\n", gc_mark, esp_p, ebp_p);
swissChili9e57da42021-06-15 22:22:46 -070093
94 // For every stack frame until the base of the stack
95 while (esp_p < gc_base)
swissChili6d6525e2021-06-15 21:20:53 -070096 {
swissChili9e57da42021-06-15 22:22:46 -070097 // Walk up the stack until we reach either the frame pointer or the base
98 // of the stack. Basically walk to the top of this function's stack
99 // frame.
100 for (; esp_p < ebp_p && esp_p < gc_base; esp_p++)
101 {
swissChilie9fec8b2021-06-22 13:59:33 -0700102 _mark(*esp_p, &num_marked);
swissChili9e57da42021-06-15 22:22:46 -0700103 }
104
105 // Set the frame pointer to the frame pointer on the stack
106 ebp_p = (value_t *)*esp_p;
107
108 // Step up two stack slots, one for the frame pointer and one for the
109 // return address.
110 esp_p += 2;
swissChili6d6525e2021-06-15 21:20:53 -0700111 }
swissChili9e57da42021-06-15 22:22:46 -0700112
113 fprintf(stderr, "Marked %d\n", num_marked);
swissChilie9fec8b2021-06-22 13:59:33 -0700114
115 _sweep();
swissChili6d6525e2021-06-15 21:20:53 -0700116}
swissChilib8fd4712021-06-23 15:32:04 -0700117
118void free_all()
119{
120 for (struct alloc *a = first_a; a;)
121 {
122 struct alloc *next = a->next;
123 free_aligned(a);
124 a = next;
125 }
126}