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 | 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 | } |
swissChili | 9e57da4 | 2021-06-15 22:22:46 -0700 | [diff] [blame] | 46 | } |
swissChili | 6d6525e | 2021-06-15 21:20:53 -0700 | [diff] [blame] | 47 | } |
| 48 | |
swissChili | e9fec8b | 2021-06-22 13:59:33 -0700 | [diff] [blame^] | 49 | value_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 | |
swissChili | 6d6525e | 2021-06-15 21:20:53 -0700 | [diff] [blame] | 55 | void _sweep() |
| 56 | { |
swissChili | e9fec8b | 2021-06-22 13:59:33 -0700 | [diff] [blame^] | 57 | 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 | } |
swissChili | 6d6525e | 2021-06-15 21:20:53 -0700 | [diff] [blame] | 62 | } |
| 63 | |
| 64 | void _do_gc(unsigned int esp, unsigned int ebp) |
| 65 | { |
swissChili | 9e57da4 | 2021-06-15 22:22:46 -0700 | [diff] [blame] | 66 | value_t *esp_p = (value_t *)esp, |
| 67 | *ebp_p = (value_t *)ebp; |
swissChili | 6d6525e | 2021-06-15 21:20:53 -0700 | [diff] [blame] | 68 | |
swissChili | e9fec8b | 2021-06-22 13:59:33 -0700 | [diff] [blame^] | 69 | 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); |
swissChili | 9e57da4 | 2021-06-15 22:22:46 -0700 | [diff] [blame] | 74 | |
| 75 | // For every stack frame until the base of the stack |
| 76 | while (esp_p < gc_base) |
swissChili | 6d6525e | 2021-06-15 21:20:53 -0700 | [diff] [blame] | 77 | { |
swissChili | 9e57da4 | 2021-06-15 22:22:46 -0700 | [diff] [blame] | 78 | // 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 | { |
swissChili | e9fec8b | 2021-06-22 13:59:33 -0700 | [diff] [blame^] | 83 | _mark(*esp_p, &num_marked); |
swissChili | 9e57da4 | 2021-06-15 22:22:46 -0700 | [diff] [blame] | 84 | } |
| 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; |
swissChili | 6d6525e | 2021-06-15 21:20:53 -0700 | [diff] [blame] | 92 | } |
swissChili | 9e57da4 | 2021-06-15 22:22:46 -0700 | [diff] [blame] | 93 | |
| 94 | fprintf(stderr, "Marked %d\n", num_marked); |
swissChili | e9fec8b | 2021-06-22 13:59:33 -0700 | [diff] [blame^] | 95 | |
| 96 | _sweep(); |
swissChili | 6d6525e | 2021-06-15 21:20:53 -0700 | [diff] [blame] | 97 | } |