summaryrefslogtreecommitdiff
path: root/vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'vm.c')
-rw-r--r--vm.c33
1 files changed, 25 insertions, 8 deletions
diff --git a/vm.c b/vm.c
index 500b4bf..4a65832 100644
--- a/vm.c
+++ b/vm.c
@@ -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");
}