93 lines
3.2 KiB
C
93 lines
3.2 KiB
C
#include "stack.h"
|
|||
|
|
|
||
|
|
#include "memory.h"
|
||
|
|
|
||
|
|
#include <assert.h>
|
||
|
|
|
||
|
|
struct LispStack the_stack;
|
||
|
|
|
||
|
|
void lisp_init_stack() {
|
||
|
|
the_stack.max_depth = DEFAULT_MAX_LISP_EVAL_DEPTH;
|
||
|
|
the_stack.depth = 0;
|
||
|
|
the_stack.first_clear_local_refs = 0;
|
||
|
|
the_stack.frames =
|
||
|
|
lisp_malloc(sizeof(struct StackFrame) * the_stack.max_depth);
|
||
|
|
for (size_t i = 0; i < the_stack.max_depth; ++i) {
|
||
|
|
the_stack.frames->local_refs.num_refs = 0;
|
||
|
|
the_stack.frames->local_refs.num_blocks = 1;
|
||
|
|
the_stack.frames->local_refs.blocks =
|
||
|
|
lisp_malloc(sizeof(struct LocalReferencesBlock *));
|
||
|
|
the_stack.frames->local_refs.blocks[0] =
|
||
|
|
lisp_malloc(sizeof(struct LocalReferencesBlock));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static ALWAYS_INLINE void init_stack_frame(struct StackFrame *frame,
|
||
|
|
LispVal *name, LispVal *args) {
|
||
|
|
frame->name = name;
|
||
|
|
frame->args = args;
|
||
|
|
frame->lexenv = Qnil;
|
||
|
|
}
|
||
|
|
|
||
|
|
void push_stack_frame(LispVal *name, LispVal *fobj, LispVal *args) {
|
||
|
|
assert(the_stack.depth < the_stack.max_depth);
|
||
|
|
struct StackFrame *frame = &the_stack.frames[the_stack.depth++];
|
||
|
|
frame->name = name;
|
||
|
|
frame->fobj = fobj;
|
||
|
|
frame->args = args;
|
||
|
|
frame->lexenv = Qnil;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void reset_local_refs(struct LocalReferences *refs) {
|
||
|
|
size_t last_block_size = refs->num_refs % LOCAL_REFERENCES_BLOCK_LENGTH;
|
||
|
|
size_t num_full_blocks = refs->num_blocks / LOCAL_REFERENCES_BLOCK_LENGTH;
|
||
|
|
for (size_t i = 0; i < num_full_blocks; ++i) {
|
||
|
|
for (size_t j = 0; j < LOCAL_REFERENCES_BLOCK_LENGTH; ++j) {
|
||
|
|
assert(OBJECTP(refs->blocks[i]->refs[j]));
|
||
|
|
--((LispObject *) refs->blocks[i]->refs[j])->gc.local_ref_count;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for (size_t i = 0; i < last_block_size; ++i) {
|
||
|
|
assert(OBJECTP(refs->blocks[num_full_blocks]->refs[i]));
|
||
|
|
--((LispObject *) refs->blocks[num_full_blocks]->refs[i])
|
||
|
|
->gc.local_ref_count;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void pop_stack_frame(void) {
|
||
|
|
assert(the_stack.depth > 0);
|
||
|
|
struct StackFrame *frame = &the_stack.frames[--the_stack.depth];
|
||
|
|
reset_local_refs(&frame->local_refs);
|
||
|
|
}
|
||
|
|
|
||
|
|
// return true if we allocated a block
|
||
|
|
static bool store_local_reference_in_frame(struct StackFrame *frame,
|
||
|
|
LispVal *obj) {
|
||
|
|
struct LocalReferences *refs = &frame->local_refs;
|
||
|
|
size_t num_full_blocks = refs->num_refs / LOCAL_REFERENCES_BLOCK_LENGTH;
|
||
|
|
if (num_full_blocks == refs->num_blocks) {
|
||
|
|
refs->blocks =
|
||
|
|
lisp_realloc(refs->blocks, sizeof(struct LocalReferencesBlock *)
|
||
|
|
* ++refs->num_blocks);
|
||
|
|
refs->blocks[refs->num_blocks - 1] =
|
||
|
|
lisp_malloc(sizeof(struct LocalReferencesBlock));
|
||
|
|
refs->blocks[refs->num_blocks - 1]->refs[0] = obj;
|
||
|
|
refs->num_refs += 1;
|
||
|
|
return true;
|
||
|
|
} else {
|
||
|
|
refs->blocks[num_full_blocks]
|
||
|
|
->refs[refs->num_refs++ % LOCAL_REFERENCES_BLOCK_LENGTH] = obj;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void add_local_reference(LispVal *obj) {
|
||
|
|
assert(the_stack.depth > 0);
|
||
|
|
if (OBJECTP(obj)) {
|
||
|
|
if (store_local_reference_in_frame(LISP_STACK_TOP(), obj)) {
|
||
|
|
the_stack.first_clear_local_refs = the_stack.depth;
|
||
|
|
}
|
||
|
|
++((LispObject *) obj)->gc.local_ref_count;
|
||
|
|
}
|
||
|
|
}
|