swissChili | 6d6525e | 2021-06-15 21:20:53 -0700 | [diff] [blame] | 1 | #include "gc.h" |
| 2 | #include "lisp.h" |
swissChili | e9fec8b | 2021-06-22 13:59:33 -0700 | [diff] [blame] | 3 | #include "plat/plat.h" |
swissChili | 6d6525e | 2021-06-15 21:20:53 -0700 | [diff] [blame] | 4 | |
swissChili | 9e57da4 | 2021-06-15 22:22:46 -0700 | [diff] [blame] | 5 | value_t *gc_base; |
swissChili | e9fec8b | 2021-06-22 13:59:33 -0700 | [diff] [blame] | 6 | THREAD_LOCAL static unsigned int gc_mark; |
swissChili | 6d6525e | 2021-06-15 21:20:53 -0700 | [diff] [blame] | 7 | |
swissChili | 9e57da4 | 2021-06-15 22:22:46 -0700 | [diff] [blame] | 8 | void __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 | |
swissChili | e9fec8b | 2021-06-22 13:59:33 -0700 | [diff] [blame] | 16 | void _mark(value_t value, unsigned int *marked) |
swissChili | 9e57da4 | 2021-06-15 22:22:46 -0700 | [diff] [blame] | 17 | { |
| 18 | if (heapp(value)) |
| 19 | { |
swissChili | e9fec8b | 2021-06-22 13:59:33 -0700 | [diff] [blame] | 20 | void *pointer = (void *)(value & ~HEAP_MASK); |
| 21 | struct alloc *alloc = pointer - sizeof(struct alloc); |
swissChili | 9e57da4 | 2021-06-15 22:22:46 -0700 | [diff] [blame] | 22 | |
swissChili | e9fec8b | 2021-06-22 13:59:33 -0700 | [diff] [blame] | 23 | // 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 | } |
swissChili | ddc9754 | 2021-07-04 11:47:42 -0700 | [diff] [blame] | 42 | case CLOSURE_TAG: { |
| 43 | struct closure_alloc *closure = (void *)alloc; |
| 44 | |
| 45 | for (int i = 0; i < closure->closure.num_captured; i++) |
| 46 | { |
| 47 | _mark(closure->closure.data[i], marked); |
| 48 | } |
| 49 | |
| 50 | break; |
| 51 | } |
swissChili | e9fec8b | 2021-06-22 13:59:33 -0700 | [diff] [blame] | 52 | } |
| 53 | } |
swissChili | 9e57da4 | 2021-06-15 22:22:46 -0700 | [diff] [blame] | 54 | } |
swissChili | 6d6525e | 2021-06-15 21:20:53 -0700 | [diff] [blame] | 55 | } |
| 56 | |
swissChili | e9fec8b | 2021-06-22 13:59:33 -0700 | [diff] [blame] | 57 | value_t alloc_to_value(struct alloc *a) |
| 58 | { |
| 59 | void *val = ((void *)a) + sizeof(struct alloc); |
| 60 | return (unsigned int)val | a->type_tag; |
| 61 | } |
| 62 | |
swissChili | 6d6525e | 2021-06-15 21:20:53 -0700 | [diff] [blame] | 63 | void _sweep() |
| 64 | { |
swissChili | 5db22a0 | 2021-06-30 22:04:33 -0700 | [diff] [blame] | 65 | for (struct alloc *a = first_a; a;) |
swissChili | e9fec8b | 2021-06-22 13:59:33 -0700 | [diff] [blame] | 66 | { |
swissChili | b8fd471 | 2021-06-23 15:32:04 -0700 | [diff] [blame] | 67 | if (pool_alive(a->pool) || a->mark == gc_mark) |
| 68 | { |
| 69 | // Marked or in living pool |
swissChili | 5db22a0 | 2021-06-30 22:04:33 -0700 | [diff] [blame] | 70 | a = a->next; |
swissChili | b8fd471 | 2021-06-23 15:32:04 -0700 | [diff] [blame] | 71 | } |
| 72 | else |
| 73 | { |
swissChili | b8fd471 | 2021-06-23 15:32:04 -0700 | [diff] [blame] | 74 | // Free and remove from allocation list |
| 75 | struct alloc *p = a->prev, *n = a->next; |
| 76 | free_aligned(a); |
| 77 | |
| 78 | a = n; |
| 79 | |
| 80 | if (p) |
| 81 | p->next = n; |
| 82 | |
| 83 | if (n) |
| 84 | n->prev = p; |
| 85 | } |
swissChili | e9fec8b | 2021-06-22 13:59:33 -0700 | [diff] [blame] | 86 | } |
swissChili | 6d6525e | 2021-06-15 21:20:53 -0700 | [diff] [blame] | 87 | } |
| 88 | |
| 89 | void _do_gc(unsigned int esp, unsigned int ebp) |
| 90 | { |
swissChili | 9e57da4 | 2021-06-15 22:22:46 -0700 | [diff] [blame] | 91 | value_t *esp_p = (value_t *)esp, |
| 92 | *ebp_p = (value_t *)ebp; |
swissChili | 6d6525e | 2021-06-15 21:20:53 -0700 | [diff] [blame] | 93 | |
swissChili | e9fec8b | 2021-06-22 13:59:33 -0700 | [diff] [blame] | 94 | unsigned int num_marked = 0; |
| 95 | |
| 96 | gc_mark++; |
| 97 | |
swissChili | 9e57da4 | 2021-06-15 22:22:46 -0700 | [diff] [blame] | 98 | // For every stack frame until the base of the stack |
| 99 | while (esp_p < gc_base) |
swissChili | 6d6525e | 2021-06-15 21:20:53 -0700 | [diff] [blame] | 100 | { |
swissChili | 9e57da4 | 2021-06-15 22:22:46 -0700 | [diff] [blame] | 101 | // Walk up the stack until we reach either the frame pointer or the base |
| 102 | // of the stack. Basically walk to the top of this function's stack |
| 103 | // frame. |
| 104 | for (; esp_p < ebp_p && esp_p < gc_base; esp_p++) |
| 105 | { |
swissChili | e9fec8b | 2021-06-22 13:59:33 -0700 | [diff] [blame] | 106 | _mark(*esp_p, &num_marked); |
swissChili | 9e57da4 | 2021-06-15 22:22:46 -0700 | [diff] [blame] | 107 | } |
| 108 | |
| 109 | // Set the frame pointer to the frame pointer on the stack |
| 110 | ebp_p = (value_t *)*esp_p; |
| 111 | |
| 112 | // Step up two stack slots, one for the frame pointer and one for the |
| 113 | // return address. |
| 114 | esp_p += 2; |
swissChili | 6d6525e | 2021-06-15 21:20:53 -0700 | [diff] [blame] | 115 | } |
swissChili | 9e57da4 | 2021-06-15 22:22:46 -0700 | [diff] [blame] | 116 | |
swissChili | e9fec8b | 2021-06-22 13:59:33 -0700 | [diff] [blame] | 117 | _sweep(); |
swissChili | 6d6525e | 2021-06-15 21:20:53 -0700 | [diff] [blame] | 118 | } |
swissChili | b8fd471 | 2021-06-23 15:32:04 -0700 | [diff] [blame] | 119 | |
| 120 | void free_all() |
| 121 | { |
| 122 | for (struct alloc *a = first_a; a;) |
| 123 | { |
| 124 | struct alloc *next = a->next; |
| 125 | free_aligned(a); |
| 126 | a = next; |
| 127 | } |
| 128 | } |