diff --git a/include/picrin.h b/include/picrin.h index 8c7cb34f..d5589726 100644 --- a/include/picrin.h +++ b/include/picrin.h @@ -22,6 +22,7 @@ struct pic_block { struct pic_block *prev; int depth; struct pic_proc *in, *out; + unsigned refcnt; }; typedef struct { diff --git a/include/picrin/cont.h b/include/picrin/cont.h index f1b9cb80..7864e320 100644 --- a/include/picrin/cont.h +++ b/include/picrin/cont.h @@ -22,4 +22,21 @@ struct pic_cont { pic_value result; }; +#define PIC_BLK_INCREF(pic,blk) do { \ + (blk)->refcnt++; \ + } while (0) + +#define PIC_BLK_DECREF(pic,blk) do { \ + struct pic_block *_a = (blk), *_b; \ + while (_a) { \ + if (! --_a->refcnt) { \ + _b = _a->prev; \ + pic_free((pic), _a); \ + _a = _b; \ + } else { \ + break; \ + } \ + } \ + } while (0) + #endif diff --git a/src/cont.c b/src/cont.c index 0f9229ef..387152c7 100644 --- a/src/cont.c +++ b/src/cont.c @@ -31,6 +31,7 @@ save_cont(pic_state *pic) cont = (struct pic_cont *)pic_obj_alloc(pic, sizeof(struct pic_cont), PIC_TT_CONT); cont->blk = pic->blk; + PIC_BLK_INCREF(pic, cont->blk); cont->stk_len = native_stack_length(pic, &pos); cont->stk_pos = pos; @@ -77,6 +78,8 @@ restore_cont(pic_state *pic, struct pic_cont *cont) if (&v > cont->stk_pos + cont->stk_len) native_stack_extend(pic, cont); } + PIC_BLK_DECREF(pic, pic->blk); + PIC_BLK_INCREF(pic, cont->blk); pic->blk = cont->blk; pic->sp = cont->sp; @@ -122,7 +125,7 @@ cont_call(pic_state *pic) cont = (struct pic_cont *)pic_ptr(proc->env->values[0]); cont->result = v; - /* execute winded handlers */ + /* execute guard handlers */ walk_to_block(pic, pic->blk, cont->blk); restore_cont(pic, cont); @@ -196,9 +199,12 @@ pic_cont_dynamic_wind(pic_state *pic) pic->blk->depth = here->depth + 1; pic->blk->in = in; pic->blk->out = out; + pic->blk->refcnt = 1; + PIC_BLK_INCREF(pic, here); v = pic_apply_argv(pic, thunk, 0); + PIC_BLK_DECREF(pic, pic->blk); pic->blk = here; } /* exit */ diff --git a/src/gc.c b/src/gc.c index 152cf061..74bdb322 100644 --- a/src/gc.c +++ b/src/gc.c @@ -142,6 +142,19 @@ gc_alloc(pic_state *pic, size_t size) } static void gc_mark(pic_state *, pic_value); +static void gc_mark_object(pic_state *pic, struct pic_object *obj); + +static void +gc_mark_block(pic_state *pic, struct pic_block *blk) +{ + while (blk) { + if (blk->in) + gc_mark_object(pic, (struct pic_object *)blk->in); + if (blk->out) + gc_mark_object(pic, (struct pic_object *)blk->out); + blk = blk->prev; + } +} static void gc_mark_object(pic_state *pic, struct pic_object *obj) @@ -198,6 +211,9 @@ gc_mark_object(pic_state *pic, struct pic_object *obj) pic_callinfo *ci; int i; + /* block */ + gc_mark_block(pic, cont->blk); + /* stack */ for (stack = cont->st_ptr; stack != cont->sp; ++stack) { gc_mark(pic, *stack); @@ -249,6 +265,9 @@ gc_mark_phase(pic_state *pic) pic_callinfo *ci; int i; + /* block */ + gc_mark_block(pic, pic->blk); + /* stack */ for (stack = pic->stbase; stack != pic->sp; ++stack) { gc_mark(pic, *stack); @@ -336,6 +355,7 @@ gc_finalize_object(pic_state *pic, struct pic_object *obj) pic_free(pic, cont->stk_ptr); pic_free(pic, cont->st_ptr); pic_free(pic, cont->ci_ptr); + PIC_BLK_DECREF(pic, cont->blk); break; } case PIC_TT_NIL: diff --git a/src/state.c b/src/state.c index fbcf99b1..9e7d1d36 100644 --- a/src/state.c +++ b/src/state.c @@ -27,6 +27,7 @@ pic_open(int argc, char *argv[], char **envp) pic->blk->prev = NULL; pic->blk->depth = 0; pic->blk->in = pic->blk->out = NULL; + pic->blk->refcnt = 1; /* prepare VM stack */ pic->stbase = pic->sp = (pic_value *)malloc(sizeof(pic_value) * PIC_STACK_SIZE);