From 18aaf9480b27211de5d61aeb8b4fa5baeff2f033 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Wed, 8 Mar 2017 16:03:14 -0500 Subject: [PATCH] Add initial untested support for varargs in vm --- compile.c | 3 ++- datatypes.h | 6 ++++- vm.c | 66 ++++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 62 insertions(+), 13 deletions(-) diff --git a/compile.c b/compile.c index c4fb10d4..a204f90b 100644 --- a/compile.c +++ b/compile.c @@ -723,10 +723,11 @@ static GstFuncDef *compiler_gen_funcdef(GstCompiler *c, uint32_t lastNBytes, uin /* Initialize the new FuncDef */ def->locals = scope->frameSize; def->arity = arity; + def->flags = 0; return def; } -/* Compile a function from a function literal */ +/* Compile a function from a function literal source form */ static Slot compile_function(GstCompiler *c, FormOptions opts, GstValue *form) { GstScope *scope = c->tail; GstBuffer *buffer = c->buffer; diff --git a/datatypes.h b/datatypes.h index 3c1bf815..0ff43317 100644 --- a/datatypes.h +++ b/datatypes.h @@ -107,12 +107,16 @@ struct GstObject { GstValue meta; }; +/* Some function defintion flags */ +#define GST_FUNCDEF_FLAG_VARARG 1 + /* A function defintion. Contains information need to instatiate closures. */ struct GstFuncDef { uint32_t locals; - uint32_t arity; + uint32_t arity; /* Not including varargs */ uint32_t literalsLen; uint32_t byteCodeLen; + uint32_t flags; GstValue *literals; /* Contains strings, FuncDefs, etc. */ uint16_t *byteCode; }; diff --git a/vm.c b/vm.c index dce4ff18..1bcd9a09 100644 --- a/vm.c +++ b/vm.c @@ -202,6 +202,9 @@ int gst_start(Gst *vm, GstValue func) { case GST_OP_CAL: /* Call */ { + int varArgs; + uint32_t expectedArity; + uint32_t normalArity; temp = stack[pc[1]]; uint32_t arity = pc[3]; uint32_t oldCount = thread.count; @@ -217,8 +220,15 @@ int gst_start(Gst *vm, GstValue func) { if (temp.type == GST_FUNCTION) { GstFunction *fn = temp.data.function; locals = fn->def->locals; + varArgs = fn->def->flags & GST_FUNCDEF_FLAG_VARARG; + expectedArity = fn->def->arity; + if (arity > expectedArity) + normalArity = expectedArity; + else + normalArity = arity; } else if (temp.type == GST_CFUNCTION) { - locals = arity; + locals = normalArity = expectedArity = arity; + varArgs = 0; } else { gst_error(vm, GST_EXPECTED_FUNCTION); } @@ -254,9 +264,24 @@ int gst_start(Gst *vm, GstValue func) { oldBase = thread.data + oldCount; /* Write arguments to new stack */ - for (i = 0; i < arity; ++i) + for (i = 0; i < normalArity; ++i) stack[i] = oldBase[pc[4 + i]]; + /* Clear stack */ + for (; i < locals; ++i) + stack[i].type = GST_NIL; + + /* Check for varargs and put them in a tuple */ + if (varArgs) { + GstValue *tuple; + uint32_t j; + tuple = gst_tuple(vm, arity - expectedArity); + for (j = expectedArity; j < arity; ++j) + tuple[j - expectedArity] = stack[j]; + stack[expectedArity].type = GST_TUPLE; + stack[expectedArity].data.tuple = tuple; + } + /* Call the function */ if (temp.type == GST_CFUNCTION) { /* Save current state to vm thread */ @@ -265,14 +290,12 @@ int gst_start(Gst *vm, GstValue func) { *vm->thread = thread; vm->ret.type = GST_NIL; status = temp.data.cfunction(vm); - v1 = vm->ret; + v2 = vm->ret; if (status == GST_RETURN_OK) goto ret; else goto vm_error; } else { - for (; i < locals; ++i) - stack[i].type = GST_NIL; pc = temp.data.function->def->byteCode; } } @@ -407,6 +430,9 @@ int gst_start(Gst *vm, GstValue func) { case GST_OP_TCL: /* Tail call */ { + int varArgs; + uint32_t expectedArity; + uint32_t normalArity; temp = stack[pc[1]]; uint32_t arity = pc[2]; uint16_t locals; @@ -425,14 +451,21 @@ int gst_start(Gst *vm, GstValue func) { /* Get size of new stack frame */ if (temp.type == GST_CFUNCTION) { - locals = arity; + locals = normalArity = expectedArity = arity; + varArgs = 0; } else if (temp.type == GST_FUNCTION) { locals = temp.data.function->def->locals; + varArgs = temp.data.function->def->flags & GST_FUNCDEF_FLAG_VARARG; + expectedArity = temp.data.function->def->arity; + if (arity > expectedArity) + normalArity = expectedArity; + else + normalArity = arity; } else { gst_error(vm, GST_EXPECTED_FUNCTION); } - /* Get enough space for manipulating args */ + /* Get enough space for manipulating args - at least twice current frame size */ if (arity > frame.size) { workspace = arity; } else { @@ -451,20 +484,31 @@ int gst_start(Gst *vm, GstValue func) { } /* Copy the arguments into the extra space */ - for (i = 0; i < arity; ++i) + for (i = 0; i < normalArity; ++i) stack[workspace + i] = stack[pc[3 + i]]; /* Copy the end of the stack to the parameter position */ - gst_memcpy(stack, stack + workspace, arity * sizeof(GstValue)); + gst_memcpy(stack, stack + workspace, normalArity * sizeof(GstValue)); /* Update the stack frame */ frame.callee = temp; frame.size = locals; /* Nil the non argument part of the stack for gc */ - for (i = arity; i < frame.size; ++i) + for (i = normalArity; i < frame.size; ++i) stack[i].type = GST_NIL; + /* Check for varargs and put them in a tuple */ + if (varArgs) { + GstValue *tuple; + uint32_t j; + tuple = gst_tuple(vm, arity - expectedArity); + for (j = expectedArity; j < arity; ++j) + tuple[j - expectedArity] = stack[workspace + j]; + stack[expectedArity].type = GST_TUPLE; + stack[expectedArity].data.tuple = tuple; + } + /* Call the function */ if (temp.type == GST_CFUNCTION) { /* Save current state to vm thread */ @@ -473,7 +517,7 @@ int gst_start(Gst *vm, GstValue func) { *vm->thread = thread; vm->ret.type = GST_NIL; status = temp.data.cfunction(vm); - v1 = vm->ret; + v2 = vm->ret; if (status == GST_RETURN_OK) goto ret; else