diff options
author | ubq323 <ubq323@ubq323.website> | 2024-06-29 13:12:34 +0100 |
---|---|---|
committer | ubq323 <ubq323@ubq323.website> | 2024-06-29 13:12:34 +0100 |
commit | 83382cb1b46eb17f94f16fbbf05b5e471284d797 (patch) | |
tree | 73e8124725984a8c883c158ae50e61693924df9f /vm.c | |
parent | b51136defc2898c868e4a1b60025d5bb57347662 (diff) |
add proper tail calls
Diffstat (limited to 'vm.c')
-rw-r--r-- | vm.c | 33 |
1 files changed, 25 insertions, 8 deletions
@@ -4,6 +4,7 @@ #include <stdbool.h> #include <stdio.h> #include <math.h> +#include <string.h> #include "val.h" #include "vm.h" @@ -174,6 +175,7 @@ int runvm(State *S) { case OP_TRUE: PUSH(VAL_TRUE); break; case OP_FALSE: PUSH(VAL_FALSE); break; + case OP_TAILCALL: case OP_CALL: { // nargs + 1 = function and args uint8_t len = RBYTE(); @@ -185,14 +187,27 @@ int runvm(State *S) { CHECK(nargs == func->arity, "func needs exactly %d args, but got %d",func->arity,nargs); CHECK(th->rsp < MAXDEPTH, "rstack overflow"); - StackFrame *sf = &th->rstack[th->rsp++]; - sf->ip = th->ip; - sf->ch = th->ch; - sf->fp = th->fp; - - th->ip = 0; - th->ch = &func->ch; - th->fp = th->sp - len; + if (instr != OP_TAILCALL) { + StackFrame *sf = &th->rstack[th->rsp++]; + sf->ip = th->ip; + sf->ch = th->ch; + sf->fp = th->fp; + + th->ip = 0; + th->ch = &func->ch; + th->fp = th->sp - len; + } else { + // xxx might invalidate open upvalues + memmove(&th->stack[th->fp], &th->stack[th->sp - len], len*sizeof(Val)); + th->sp = th->fp + len; + th->ip = 0; + th->ch = &func->ch; + + StackFrame *cur_sf = &th->rstack[th->rsp]; + cur_sf->ip = th->ip; + cur_sf->ch = th->ch; + cur_sf->fp = th->fp; + } } else if (IS_CFUNC(callee)) { Val *firstarg = &th->stack[th->sp - nargs]; Val res = AS_CFUNC(callee)(S, nargs, firstarg); @@ -247,6 +262,8 @@ int runvm(State *S) { objarr_append(S, arr, v); break; } + default: + ERROR("unknown opcode"); } |