blob: 84df7aacbb7dfb522f409c19dad8d9b878ffd22e [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 {
59 fprintf(stderr, "[ GC ] %s %p\n", (a->mark != gc_mark) ? "Unmarked" : "Marked", a);
60 printval(alloc_to_value(a), 2);
61 }
swissChili6d6525e2021-06-15 21:20:53 -070062}
63
64void _do_gc(unsigned int esp, unsigned int ebp)
65{
swissChili9e57da42021-06-15 22:22:46 -070066 value_t *esp_p = (value_t *)esp,
67 *ebp_p = (value_t *)ebp;
swissChili6d6525e2021-06-15 21:20:53 -070068
swissChilie9fec8b2021-06-22 13:59:33 -070069 unsigned int num_marked = 0;
70
71 gc_mark++;
72
73 fprintf(stderr, "[ GC ] %d (esp 0x%p, ebp 0x%p)\n", gc_mark, esp_p, ebp_p);
swissChili9e57da42021-06-15 22:22:46 -070074
75 // For every stack frame until the base of the stack
76 while (esp_p < gc_base)
swissChili6d6525e2021-06-15 21:20:53 -070077 {
swissChili9e57da42021-06-15 22:22:46 -070078 // Walk up the stack until we reach either the frame pointer or the base
79 // of the stack. Basically walk to the top of this function's stack
80 // frame.
81 for (; esp_p < ebp_p && esp_p < gc_base; esp_p++)
82 {
swissChilie9fec8b2021-06-22 13:59:33 -070083 _mark(*esp_p, &num_marked);
swissChili9e57da42021-06-15 22:22:46 -070084 }
85
86 // Set the frame pointer to the frame pointer on the stack
87 ebp_p = (value_t *)*esp_p;
88
89 // Step up two stack slots, one for the frame pointer and one for the
90 // return address.
91 esp_p += 2;
swissChili6d6525e2021-06-15 21:20:53 -070092 }
swissChili9e57da42021-06-15 22:22:46 -070093
94 fprintf(stderr, "Marked %d\n", num_marked);
swissChilie9fec8b2021-06-22 13:59:33 -070095
96 _sweep();
swissChili6d6525e2021-06-15 21:20:53 -070097}