diff --git a/include/picrin/proc.h b/include/picrin/proc.h index 0b937537..34c12654 100644 --- a/include/picrin/proc.h +++ b/include/picrin/proc.h @@ -20,6 +20,7 @@ struct pic_env { pic_value *values; int valuec; struct pic_env *up; + pic_value storage[]; }; struct pic_proc { diff --git a/src/codegen.c b/src/codegen.c index 9946fa4b..4de20f75 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -885,7 +885,7 @@ destroy_codegen_state(codegen_state *state) static void create_cv_table(pic_state *pic, codegen_context *cxt) { - size_t i; + size_t i, n; xhash *regs; pic_sym *var; size_t offset; @@ -908,7 +908,17 @@ create_cv_table(pic_state *pic, codegen_context *cxt) cxt->cv_tbl = pic_calloc(pic, cxt->captures.size, sizeof(unsigned)); for (i = 0; i < cxt->captures.size; ++i) { var = xv_get(&cxt->captures, i); - cxt->cv_tbl[i] = xh_get_int(regs, *var)->val; + if ((n = xh_get_int(regs, *var)->val) <= cxt->args.size) { + /* copy arguments to capture variable area */ + cxt->code[cxt->clen].insn = OP_LREF; + cxt->code[cxt->clen].u.i = n; + cxt->clen++; + } else { + /* otherwise, just extend the stack */ + cxt->code[cxt->clen].insn = OP_PUSHNONE; + cxt->clen++; + } + cxt->cv_tbl[i] = n; } xh_destroy(regs); @@ -939,8 +949,6 @@ push_codegen_context(codegen_state *state, pic_value args, pic_value locals, boo xv_push(&cxt->captures, &pic_sym(var)); } - create_cv_table(pic, cxt); - cxt->code = pic_calloc(pic, PIC_ISEQ_SIZE, sizeof(pic_code)); cxt->clen = 0; cxt->ccapa = PIC_ISEQ_SIZE; @@ -954,6 +962,8 @@ push_codegen_context(codegen_state *state, pic_value args, pic_value locals, boo cxt->pcapa = PIC_POOL_SIZE; state->cxt = cxt; + + create_cv_table(pic, cxt); } static struct pic_irep * diff --git a/src/gc.c b/src/gc.c index ec830474..6681b793 100644 --- a/src/gc.c +++ b/src/gc.c @@ -580,7 +580,6 @@ gc_finalize_object(pic_state *pic, struct pic_object *obj) break; } case PIC_TT_ENV: { - pic_free(pic, ((struct pic_env *)obj)->values); break; } case PIC_TT_PROC: { diff --git a/src/vm.c b/src/vm.c index 079b35c0..ca3a11b8 100644 --- a/src/vm.c +++ b/src/vm.c @@ -424,6 +424,19 @@ pic_defvar(pic_state *pic, const char *name, pic_value init) pic_define(pic, name, pic_obj_value(pic_wrap_var(pic, var))); } +static void +vm_tear_off(pic_state *pic) +{ + struct pic_env *env; + int i; + + env = pic->ci->env; + for (i = 0; i < env->valuec; ++i) { + env->storage[i] = env->values[i]; + } + env->values = env->storage; +} + pic_value pic_apply_argv(pic_state *pic, struct pic_proc *proc, size_t argc, ...) { @@ -707,13 +720,10 @@ pic_apply(pic_state *pic, struct pic_proc *proc, pic_value argv) } /* prepare env */ - ci->env = (struct pic_env *)pic_obj_alloc(pic, sizeof(struct pic_env), PIC_TT_ENV); + ci->env = (struct pic_env *)pic_obj_alloc(pic, offsetof(struct pic_env, storage) + sizeof(pic_value) * irep->capturec, PIC_TT_ENV); ci->env->up = proc->env; ci->env->valuec = irep->capturec; - ci->env->values = pic_calloc(pic, ci->env->valuec, sizeof(pic_value)); - for (i = 0; i < ci->env->valuec; ++i) { - ci->env->values[i] = ci->fp[irep->cv_tbl[i]]; - } + ci->env->values = ci->fp + irep->argc + irep->localc; pic->ip = irep->code; pic_gc_arena_restore(pic, ai); @@ -725,6 +735,8 @@ pic_apply(pic_state *pic, struct pic_proc *proc, pic_value argv) pic_value *argv; pic_callinfo *ci; + vm_tear_off(pic); + if (c.u.i == -1) { pic->sp += pic->ci[1].retc - 1; c.u.i = pic->ci[1].retc + 1; @@ -753,6 +765,8 @@ pic_apply(pic_state *pic, struct pic_proc *proc, pic_value argv) goto L_STOP; } + vm_tear_off(pic); + pic->ci->retc = c.u.i; L_RET: