blob: 16ec471ab49a19916845d824734008b32dc8fef0 [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 // Only recursively mark if this hasn't been marked yet. i.e. prevent
24 // marking circular references twice
25 if (alloc->mark != gc_mark)
26 {
27 ++*marked;
28
29 alloc->mark = gc_mark;
30
31 // printf("[ GC ] val =");
32 // printval(alloc_to_value(alloc), 2);
33
34 switch (alloc->type_tag)
35 {
36 case CONS_TAG: {
37 struct cons_alloc *cons = (struct cons_alloc *)alloc;
38 _mark(cons->cons.car, marked);
39 _mark(cons->cons.cdr, marked);
40 break;
41 }
42 }
43 }
swissChili9e57da42021-06-15 22:22:46 -070044 }
swissChili6d6525e2021-06-15 21:20:53 -070045}
46
swissChilie9fec8b2021-06-22 13:59:33 -070047value_t alloc_to_value(struct alloc *a)
48{
49 void *val = ((void *)a) + sizeof(struct alloc);
50 return (unsigned int)val | a->type_tag;
51}
52
swissChili6d6525e2021-06-15 21:20:53 -070053void _sweep()
54{
swissChili5db22a02021-06-30 22:04:33 -070055 for (struct alloc *a = first_a; a;)
swissChilie9fec8b2021-06-22 13:59:33 -070056 {
swissChilib8fd4712021-06-23 15:32:04 -070057 if (pool_alive(a->pool) || a->mark == gc_mark)
58 {
59 // Marked or in living pool
swissChili5db22a02021-06-30 22:04:33 -070060 a = a->next;
swissChilib8fd4712021-06-23 15:32:04 -070061 }
62 else
63 {
swissChilib8fd4712021-06-23 15:32:04 -070064 // Free and remove from allocation list
65 struct alloc *p = a->prev, *n = a->next;
66 free_aligned(a);
67
68 a = n;
69
70 if (p)
71 p->next = n;
72
73 if (n)
74 n->prev = p;
75 }
swissChilie9fec8b2021-06-22 13:59:33 -070076 }
swissChili6d6525e2021-06-15 21:20:53 -070077}
78
79void _do_gc(unsigned int esp, unsigned int ebp)
80{
swissChili9e57da42021-06-15 22:22:46 -070081 value_t *esp_p = (value_t *)esp,
82 *ebp_p = (value_t *)ebp;
swissChili6d6525e2021-06-15 21:20:53 -070083
swissChilie9fec8b2021-06-22 13:59:33 -070084 unsigned int num_marked = 0;
85
86 gc_mark++;
87
swissChili9e57da42021-06-15 22:22:46 -070088 // For every stack frame until the base of the stack
89 while (esp_p < gc_base)
swissChili6d6525e2021-06-15 21:20:53 -070090 {
swissChili9e57da42021-06-15 22:22:46 -070091 // Walk up the stack until we reach either the frame pointer or the base
92 // of the stack. Basically walk to the top of this function's stack
93 // frame.
94 for (; esp_p < ebp_p && esp_p < gc_base; esp_p++)
95 {
swissChilie9fec8b2021-06-22 13:59:33 -070096 _mark(*esp_p, &num_marked);
swissChili9e57da42021-06-15 22:22:46 -070097 }
98
99 // Set the frame pointer to the frame pointer on the stack
100 ebp_p = (value_t *)*esp_p;
101
102 // Step up two stack slots, one for the frame pointer and one for the
103 // return address.
104 esp_p += 2;
swissChili6d6525e2021-06-15 21:20:53 -0700105 }
swissChili9e57da42021-06-15 22:22:46 -0700106
swissChilie9fec8b2021-06-22 13:59:33 -0700107 _sweep();
swissChili6d6525e2021-06-15 21:20:53 -0700108}
swissChilib8fd4712021-06-23 15:32:04 -0700109
110void free_all()
111{
112 for (struct alloc *a = first_a; a;)
113 {
114 struct alloc *next = a->next;
115 free_aligned(a);
116 a = next;
117 }
118}