Add GC segments to differentiate C stack space from Lisp
diff --git a/src/lisp/gc.c b/src/lisp/gc.c
index 140bc3f..a6d88ac 100644
--- a/src/lisp/gc.c
+++ b/src/lisp/gc.c
@@ -1,8 +1,10 @@
#include "gc.h"
#include "lisp.h"
#include "plat/plat.h"
+#include <stdlib.h>
value_t *gc_base;
+struct gc_segment *gc_last_segment = NULL;
THREAD_LOCAL static unsigned int gc_mark;
THREAD_LOCAL static unsigned long gc_runs = 0;
@@ -14,6 +16,52 @@
asm("movl %%esp, %0" : "=g"(gc_base));
}
+void gc_push_segment(void *last_arg_addr, int nretained)
+{
+ // base will be the address below (at higher memory than) the ret
+ // pointer when lisp func is called.
+ struct gc_segment *seg = malloc(sizeof(struct gc_segment) + sizeof(value_t) * nretained);
+
+ if (last_arg_addr)
+ seg->seg_start = last_arg_addr + 4;
+ else
+ seg->seg_start = NULL;
+
+ seg->nretained = nretained;
+ seg->prev = gc_last_segment;
+ gc_last_segment = seg;
+
+ // remember, stack looks like this:
+ // ret
+ // old ebp <- current ebp points here
+ // ...
+ void **ebp;
+ asm("movl %%ebp, %0" : "=g"(ebp));
+ seg->old_ebp = *ebp; // could do this in one mov but whatever
+}
+
+void gc_pop_segment()
+{
+ struct gc_segment *prev = gc_last_segment->prev;
+ free(gc_last_segment);
+ gc_last_segment = prev;
+}
+
+void gc_prepare_call_(void *esp, int nargs)
+{
+ gc_last_segment->nargs = nargs;
+ // esp points to its position BEFORE the lisp function is
+ // called. So seg_end is that + return pointer + arguments.
+ gc_last_segment->seg_end = esp + 4 + sizeof(value_t) * nargs;
+}
+
+void gc_set_retained(int index, value_t retained)
+{
+ gc_last_segment->retained[index] = retained;
+}
+
+void gc_set_retained(int index, value_t retained);
+
void _mark(value_t value, unsigned int *marked)
{
if (heapp(value))
@@ -134,23 +182,47 @@
gc_mark++;
gc_runs++;
- // For every stack frame until the base of the stack
- while (esp_p < gc_base)
+ for (struct gc_segment *seg = gc_last_segment; seg && seg->seg_start; seg = seg->prev)
{
- // Walk up the stack until we reach either the frame pointer or the base
- // of the stack. Basically walk to the top of this function's stack
- // frame.
- for (; esp_p < ebp_p && esp_p < gc_base; esp_p++)
+ // For every stack frame until the base of the stack
+ while (esp_p < (value_t *)seg->seg_end)
{
- _mark(*esp_p, &num_marked);
+ // Walk up the stack until we reach either the frame pointer or the base
+ // of the stack. Basically walk to the top of this function's stack
+ // frame.
+ for (; esp_p < ebp_p && esp_p < gc_base; esp_p++)
+ {
+ _mark(*esp_p, &num_marked);
+ }
+
+ // Set the frame pointer to the frame pointer on the stack
+ ebp_p = (value_t *)*esp_p;
+
+ // Step up two stack slots, one for the frame pointer and one for the
+ // return address.
+ esp_p += 2;
}
- // Set the frame pointer to the frame pointer on the stack
- ebp_p = (value_t *)*esp_p;
+ // skip above ret pointer
+ value_t *args = seg->seg_end + 4;
+ for (int i = 0; i < seg->nargs; i++)
+ {
+ fprintf(stderr, "Marking arg %d\n", i);
- // Step up two stack slots, one for the frame pointer and one for the
- // return address.
- esp_p += 2;
+ // mark arguments
+ _mark(args[i], &num_marked);
+ }
+
+ for (int i = 0; i < seg->nretained; i++)
+ {
+ fprintf(stderr, "Marking retained %d\n", i);
+ printval(seg->retained[i], 0);
+
+ _mark(seg->retained[i], &num_marked);
+ }
+
+ esp_p = seg->seg_start;
+ ebp_p = seg->old_ebp;
}
_sweep();