diff --git a/include/picrin/irep.h b/include/picrin/irep.h index 4f0ce8ba..efda468f 100644 --- a/include/picrin/irep.h +++ b/include/picrin/irep.h @@ -18,6 +18,7 @@ enum pic_opcode { OP_JMP, OP_JMPIF, OP_CALL, + OP_TAILCALL, OP_RET, OP_LAMBDA, OP_CONS, diff --git a/src/codegen.c b/src/codegen.c index 7e1eb742..02032d4b 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -744,6 +744,9 @@ print_irep(pic_state *pic, struct pic_irep *irep) case OP_CALL: printf("OP_CALL\t%d\n", irep->code[i].u.i); break; + case OP_TAILCALL: + printf("OP_TAILCALL\t%d\n", irep->code[i].u.i); + break; case OP_RET: puts("OP_RET"); break; diff --git a/src/vm.c b/src/vm.c index d6685f41..1c10700e 100644 --- a/src/vm.c +++ b/src/vm.c @@ -192,8 +192,8 @@ pic_apply(pic_state *pic, struct pic_proc *proc, pic_value argv) &&L_OP_POP, &&L_OP_PUSHNIL, &&L_OP_PUSHTRUE, &&L_OP_PUSHFALSE, &&L_OP_PUSHFLOAT, &&L_OP_PUSHINT, &&L_OP_PUSHCONST, &&L_OP_GREF, &&L_OP_GSET, &&L_OP_LREF, &&L_OP_LSET, &&L_OP_CREF, &&L_OP_CSET, &&L_OP_JMP, &&L_OP_JMPIF, &&L_OP_CALL, - &&L_OP_RET, &&L_OP_LAMBDA, &&L_OP_CONS, &&L_OP_CAR, &&L_OP_CDR, &&L_OP_NILP, - &&L_OP_ADD, &&L_OP_SUB, &&L_OP_MUL, &&L_OP_DIV, + &&L_OP_TAILCALL, &&L_OP_RET, &&L_OP_LAMBDA, &&L_OP_CONS, &&L_OP_CAR, &&L_OP_CDR, + &&L_OP_NILP, &&L_OP_ADD, &&L_OP_SUB, &&L_OP_MUL, &&L_OP_DIV, &&L_OP_EQ, &&L_OP_LT, &&L_OP_LE, &&L_OP_STOP }; #endif @@ -358,6 +358,20 @@ pic_apply(pic_state *pic, struct pic_proc *proc, pic_value argv) JUMP; } } + CASE(OP_TAILCALL) { + int argc; + pic_value *argv; + + argc = pc->u.i; + argv = pic->sp - argc; + for (i = 0; i < argc; ++i) { + pic->ci->fp[i] = argv[i]; + } + pic->sp = pic->ci->fp + argc; + pc = POPCI()->pc; + + goto L_CALL; + } CASE(OP_RET) { pic_value v; pic_callinfo *ci;