1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-28 02:59:54 +00:00

Redo function call bytecode interface to be simpler and allow

for an apply like structure in the language
This commit is contained in:
Calvin Rose 2017-04-19 09:02:12 -04:00
parent f4a6f4073f
commit 01e8749f39
10 changed files with 192 additions and 269 deletions

View File

@ -42,6 +42,10 @@ int debug_compile_and_run(Gst *vm, GstValue ast, GstValue env) {
printf("Compiler error: %s\n", c.error); printf("Compiler error: %s\n", c.error);
return 1; return 1;
} }
/* Print disasm */
printf("%c[31m===== Begin Disassembly =====\n", 27);
gst_dasm_function(stdout, func.data.function);
printf("===== End Disassembly =====%c[0m\n", 27);
/* Execute function */ /* Execute function */
if (gst_run(vm, func)) { if (gst_run(vm, func)) {
if (vm->crash) { if (vm->crash) {
@ -132,7 +136,7 @@ int debug_repl(Gst *vm) {
/* Add _ to environemt */ /* Add _ to environemt */
st = gst_struct_begin(vm, 1); st = gst_struct_begin(vm, 1);
gst_struct_put(st, gst_string_cv(vm, "_"), vm->ret); gst_struct_put(st, gst_string_cv(vm, "_"), vm->ret);
if (0 == debug_compile_and_run(vm, gst_parse_consume(&p), gst_wrap_struct(gst_struct_end(vm, st)))) { if (!debug_compile_and_run(vm, gst_parse_consume(&p), gst_wrap_struct(gst_struct_end(vm, st)))) {
printf("%s\n", gst_to_string(vm, vm->ret)); printf("%s\n", gst_to_string(vm, vm->ret));
} }
} }

View File

@ -684,71 +684,6 @@ static Slot compile_if(GstCompiler *c, FormOptions opts, const GstValue *form) {
return condition; return condition;
} }
/* Try catch special */
static Slot compile_try(GstCompiler *c, FormOptions opts, const GstValue *form) {
GstScope *scope = c->tail;
GstBuffer *buffer = c->buffer;
Slot body;
uint16_t errorIndex;
uint32_t countAtTry, countTemp, countAtJump;
countAtJump = 0;
/* Check argument count */
if (gst_tuple_length(form) < 3 || gst_tuple_length(form) > 4)
c_error(c, "try takes either 2 or 3 arguments");
/* Check for symbol to bind error to */
if (form[1].type != GST_STRING)
c_error(c, "expected string at start of try");
/* Add subscope for error variable */
GstScope *subScope = compiler_push_scope(c, 1);
errorIndex = compiler_declare_symbol(c, subScope, form[1]);
/* Leave space for try instruction */
countAtTry = buffer->count;
buffer->count += sizeof(uint32_t) + 2 * sizeof(uint16_t);
/* Compile the body */
body = compile_value(c, opts, form[2]);
if (opts.isTail) {
compiler_return(c, body);
} else {
/* If we need to jump over the catch, do so */
if (gst_tuple_length(form) == 4) {
countAtJump = buffer->count;
buffer->count += sizeof(int32_t) + sizeof(uint16_t);
}
}
/* Reinsert try jump with correct index */
countTemp = buffer->count;
buffer->count = countAtTry;
gst_buffer_push_u16(c->vm, buffer, GST_OP_TRY);
gst_buffer_push_u16(c->vm, buffer, errorIndex);
gst_buffer_push_i32(c->vm, buffer, (countTemp - countAtTry) / 2);
buffer->count = countTemp;
/* Compile catch path */
if (gst_tuple_length(form) == 4) {
Slot catch;
countAtJump = buffer->count;
catch = compile_value(c, opts, form[3]);
if (opts.isTail) compiler_return(c, catch);
compiler_drop_slot(c, scope, catch);
} else if (opts.isTail) {
compiler_return(c, nil_slot());
}
/* Reset the second jump length */
if (!opts.isTail && gst_tuple_length(form) == 4) {
countTemp = buffer->count;
buffer->count = countAtJump;
gst_buffer_push_u16(c->vm, buffer, GST_OP_JMP);
gst_buffer_push_i32(c->vm, buffer, (countTemp - countAtJump) / 2);
buffer->count = countTemp;
}
/* Untry */
gst_buffer_push_u16(c->vm, buffer, GST_OP_UTY);
/* Pop the error scope */
compiler_pop_scope(c);
if (opts.isTail)
body.hasReturned = 1;
return body;
}
/* While special */ /* While special */
static Slot compile_while(GstCompiler *c, FormOptions opts, const GstValue *form) { static Slot compile_while(GstCompiler *c, FormOptions opts, const GstValue *form) {
Slot cond; Slot cond;
@ -885,14 +820,6 @@ static SpecialFormHelper get_special(const GstValue *form) {
} }
} }
break; break;
case 't':
{
if (gst_string_length(name) == 3 &&
name[1] == 'r' &&
name[2] == 'y') {
return compile_try;
}
}
case 'w': case 'w':
{ {
if (gst_string_length(name) == 5 && if (gst_string_length(name) == 5 &&
@ -991,11 +918,15 @@ static Slot compile_form(GstCompiler *c, FormOptions opts, const GstValue *form)
/* Free up some slots */ /* Free up some slots */
compiler_drop_slot(c, scope, callee); compiler_drop_slot(c, scope, callee);
compiler_tracker_free(c, scope, &tracker); compiler_tracker_free(c, scope, &tracker);
/* Prepare next stack frame */
gst_buffer_push_u16(c->vm, buffer, GST_OP_PSK);
gst_buffer_push_u16(c->vm, buffer, gst_tuple_length(form) - 1);
/* Write the location of all of the arguments */
compiler_tracker_write(c, &tracker, 0);
/* If this is in tail position do a tail call. */ /* If this is in tail position do a tail call. */
if (opts.isTail) { if (opts.isTail) {
gst_buffer_push_u16(c->vm, buffer, GST_OP_TCL); gst_buffer_push_u16(c->vm, buffer, GST_OP_TCL);
gst_buffer_push_u16(c->vm, buffer, callee.index); gst_buffer_push_u16(c->vm, buffer, callee.index);
gst_buffer_push_u16(c->vm, buffer, gst_tuple_length(form) - 1);
ret.hasReturned = 1; ret.hasReturned = 1;
ret.isNil = 1; ret.isNil = 1;
} else { } else {
@ -1003,10 +934,7 @@ static Slot compile_form(GstCompiler *c, FormOptions opts, const GstValue *form)
gst_buffer_push_u16(c->vm, buffer, GST_OP_CAL); gst_buffer_push_u16(c->vm, buffer, GST_OP_CAL);
gst_buffer_push_u16(c->vm, buffer, callee.index); gst_buffer_push_u16(c->vm, buffer, callee.index);
gst_buffer_push_u16(c->vm, buffer, ret.index); gst_buffer_push_u16(c->vm, buffer, ret.index);
gst_buffer_push_u16(c->vm, buffer, gst_tuple_length(form) - 1);
} }
/* Write the location of all of the arguments */
compiler_tracker_write(c, &tracker, 0);
return ret; return ret;
} }
} }

View File

@ -191,29 +191,23 @@ void gst_dasm(FILE * out, uint16_t *byteCode, uint32_t len) {
case GST_OP_TUP: case GST_OP_TUP:
current += dasm_varg_op(out, current, "tuple", 1); current += dasm_varg_op(out, current, "tuple", 1);
break; break;
case GST_OP_ERR:
current += dasm_fixed_op(out, current, "error", 1);
break;
case GST_OP_TRY:
dasm_print_arg(out, "try");
dasm_print_slot(out, current[1]);
dasm_print_i32(out, *(int32_t *)(current + 2));
current += 4;
break;
case GST_OP_UTY:
current += dasm_fixed_op(out, current, "untry", 0);
break;
case GST_OP_RET: case GST_OP_RET:
current += dasm_fixed_op(out, current, "return", 1); current += dasm_fixed_op(out, current, "return", 1);
break; break;
case GST_OP_RTN: case GST_OP_RTN:
current += dasm_fixed_op(out, current, "returnNil", 0); current += dasm_fixed_op(out, current, "returnNil", 0);
break; break;
case GST_OP_PSK:
current += dasm_varg_op(out, current, "pushArgs", 0);
break;
case GST_OP_PAR:
current += dasm_fixed_op(out, current, "pushSeq", 1);
break;
case GST_OP_CAL: case GST_OP_CAL:
current += dasm_varg_op(out, current, "call", 2); current += dasm_fixed_op(out, current, "call", 2);
break; break;
case GST_OP_TCL: case GST_OP_TCL:
current += dasm_varg_op(out, current, "tailCall", 1); current += dasm_fixed_op(out, current, "tailCall", 1);
break; break;
} }
fprintf(out, "\n"); fprintf(out, "\n");

View File

@ -267,7 +267,9 @@ void gst_collect(Gst *vm) {
/* Thread can be null */ /* Thread can be null */
if (vm->thread) if (vm->thread)
gst_mark_value(vm, gst_wrap_thread(vm->thread)); gst_mark_value(vm, gst_wrap_thread(vm->thread));
if (vm->modules)
gst_mark_value(vm, gst_wrap_object(vm->modules)); gst_mark_value(vm, gst_wrap_object(vm->modules));
if (vm->registry)
gst_mark_value(vm, gst_wrap_object(vm->registry)); gst_mark_value(vm, gst_wrap_object(vm->registry));
gst_mark_value(vm, vm->ret); gst_mark_value(vm, vm->ret);
if (vm->scratch) if (vm->scratch)

View File

@ -39,7 +39,7 @@
* Byte 208: Array - [u32 length]*[value... elements] * Byte 208: Array - [u32 length]*[value... elements]
* Byte 209: Tuple - [u32 length]*[value... elements] * Byte 209: Tuple - [u32 length]*[value... elements]
* Byte 210: Thread - [u8 state][u32 frames]*[[value callee][value env] * Byte 210: Thread - [u8 state][u32 frames]*[[value callee][value env]
* [u32 pcoffset][u32 erroffset][u16 ret][u16 errloc][u16 size]*[value ...stack] * [u32 pcoffset][u16 ret][u16 args][u16 size]*[value ...stack]
* Byte 211: Object - [value parent][u32 length]*2*[value... kvs] * Byte 211: Object - [value parent][u32 length]*2*[value... kvs]
* Byte 212: FuncDef - [u32 locals][u32 arity][u32 flags][u32 literallen]*[value... * Byte 212: FuncDef - [u32 locals][u32 arity][u32 flags][u32 literallen]*[value...
* literals][u32 bytecodelen]*[u16... bytecode] * literals][u32 bytecodelen]*[u16... bytecode]
@ -242,8 +242,8 @@ static const char *gst_deserialize_impl(
/* Add frames */ /* Add frames */
for (i = 0; i < length; ++i) { for (i = 0; i < length; ++i) {
GstValue callee, env; GstValue callee, env;
uint32_t pcoffset, erroffset; uint32_t pcoffset;
uint16_t ret, errloc, size, j; uint16_t ret, args, size, j;
/* Create a new frame */ /* Create a new frame */
if (i > 0) if (i > 0)
gst_thread_beginframe(vm, t, nil, 0); gst_thread_beginframe(vm, t, nil, 0);
@ -253,20 +253,18 @@ static const char *gst_deserialize_impl(
err = gst_deserialize_impl(vm, data, end, &data, visited, &env); err = gst_deserialize_impl(vm, data, end, &data, visited, &env);
if (err != NULL) return err; if (err != NULL) return err;
read_u32(pcoffset); read_u32(pcoffset);
read_u32(erroffset);
read_u16(ret); read_u16(ret);
read_u16(errloc); read_u16(args);
read_u16(size); read_u16(size);
/* Set up the stack */ /* Set up the stack */
stack = gst_thread_stack(t); stack = gst_thread_stack(t);
if (callee.type == GST_FUNCTION) { if (callee.type == GST_FUNCTION) {
gst_frame_pc(stack) = callee.data.function->def->byteCode + pcoffset; gst_frame_pc(stack) = callee.data.function->def->byteCode + pcoffset;
gst_frame_errjmp(stack) = callee.data.function->def->byteCode + erroffset;
if (env.type == GST_FUNCENV) if (env.type == GST_FUNCENV)
gst_frame_env(stack) = env.data.env; gst_frame_env(stack) = env.data.env;
} }
gst_frame_ret(stack) = ret; gst_frame_ret(stack) = ret;
gst_frame_errloc(stack) = errloc; gst_frame_args(stack) = args;
gst_frame_size(stack) = size; gst_frame_size(stack) = size;
gst_frame_prevsize(stack) = prevsize; gst_frame_prevsize(stack) = prevsize;
prevsize = size; prevsize = size;

View File

@ -249,7 +249,7 @@ int gst_stl_object(Gst *vm) {
GstObject *object; GstObject *object;
if (count % 2 != 0) if (count % 2 != 0)
gst_c_throwc(vm, "expected even number of arguments"); gst_c_throwc(vm, "expected even number of arguments");
object = gst_object(vm, count * 2); object = gst_object(vm, 4 * count);
for (i = 0; i < count; i += 2) for (i = 0; i < count; i += 2)
gst_object_put(vm, object, gst_arg(vm, i), gst_arg(vm, i + 1)); gst_object_put(vm, object, gst_arg(vm, i), gst_arg(vm, i + 1));
gst_c_return(vm, gst_wrap_object(object)); gst_c_return(vm, gst_wrap_object(object));
@ -457,6 +457,7 @@ static const GstModuleItem const std_module[] = {
{"exit", gst_stl_exit}, {"exit", gst_stl_exit},
{"rawget", gst_stl_rawget}, {"rawget", gst_stl_rawget},
{"rawset", gst_stl_rawset}, {"rawset", gst_stl_rawset},
{"next", gst_stl_next},
{"error", gst_stl_error}, {"error", gst_stl_error},
{"serialize", gst_stl_serialize}, {"serialize", gst_stl_serialize},
{"open", gst_stl_open}, {"open", gst_stl_open},

View File

@ -36,10 +36,9 @@ GstThread *gst_thread(Gst *vm, GstValue callee, uint32_t capacity) {
gst_frame_size(stack) = 0; gst_frame_size(stack) = 0;
gst_frame_prevsize(stack) = 0; gst_frame_prevsize(stack) = 0;
gst_frame_ret(stack) = 0; gst_frame_ret(stack) = 0;
gst_frame_errloc(stack) = 0; gst_frame_args(stack) = 0;
gst_frame_pc(stack) = NULL; gst_frame_pc(stack) = NULL;
gst_frame_env(stack) = NULL; gst_frame_env(stack) = NULL;
gst_frame_errjmp(stack) = NULL;
gst_frame_callee(stack) = callee; gst_frame_callee(stack) = callee;
gst_thread_endframe(vm, thread); gst_thread_endframe(vm, thread);
thread->parent = NULL; thread->parent = NULL;
@ -115,7 +114,6 @@ GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uin
newStack = oldStack + frameOffset; newStack = oldStack + frameOffset;
gst_frame_prevsize(newStack) = gst_frame_size(oldStack); gst_frame_prevsize(newStack) = gst_frame_size(oldStack);
gst_frame_env(newStack) = NULL; gst_frame_env(newStack) = NULL;
gst_frame_errjmp(newStack) = NULL;
gst_frame_size(newStack) = 0; gst_frame_size(newStack) = 0;
gst_frame_callee(newStack) = callee; gst_frame_callee(newStack) = callee;
thread->count += frameOffset; thread->count += frameOffset;
@ -144,6 +142,8 @@ void gst_thread_endframe(Gst *vm, GstThread *thread) {
gst_thread_pushnil(vm, thread, locals - gst_frame_size(stack)); gst_thread_pushnil(vm, thread, locals - gst_frame_size(stack));
} }
} }
stack = thread->data + thread->count;
gst_frame_args(stack) = gst_frame_size(stack) + GST_FRAME_SIZE;
} }
} }
@ -173,44 +173,3 @@ GstValue *gst_thread_popframe(Gst *vm, GstThread *thread) {
else else
return NULL; return NULL;
} }
/* Move the current stack frame over its parent stack frame, allowing
* for primitive tail calls. */
GstValue *gst_thread_tail(Gst *vm, GstThread *thread) {
GstFuncEnv *env;
GstValue *stack = thread->data + thread->count;
GstValue *nextStack = gst_thread_popframe(vm, thread);
uint32_t i;
if (nextStack == NULL) return NULL;
env = gst_frame_env(nextStack);
/* Check for old closures */
if (env != NULL) {
uint32_t size = gst_frame_size(stack);
env->thread = NULL;
env->stackOffset = size;
env->values = gst_alloc(vm, sizeof(GstValue) * size);
gst_memcpy(env->values, stack, sizeof(GstValue) * size);
}
/* Modify new closure */
env = gst_frame_env(stack);
if (env != NULL) {
env->stackOffset = thread->count;
}
/* Copy over (some of) stack frame. Leave ret and prevsize untouched. */
gst_frame_env(nextStack) = env;
gst_frame_size(nextStack) = gst_frame_size(stack);
gst_frame_pc(nextStack) = gst_frame_pc(stack);
gst_frame_errjmp(nextStack) = gst_frame_errjmp(stack);
gst_frame_errloc(nextStack) = gst_frame_errloc(stack);
gst_frame_callee(nextStack) = gst_frame_callee(stack);
/* Copy stack arguments */
for (i = 0; i < gst_frame_size(nextStack); ++i)
nextStack[i] = stack[i];
return nextStack;
}

207
core/vm.c
View File

@ -22,33 +22,23 @@
#include <gst/gst.h> #include <gst/gst.h>
/* Macros for errors in the vm */
/* Exit from the VM normally */
#define gst_exit(vm, r) return ((vm)->ret = (r), GST_RETURN_OK)
/* Bail from the VM with an error string. */
#define gst_error(vm, e) do { (vm)->ret = gst_string_cv((vm), (e)); goto vm_error; } while (0)
/* Crash. Not catchable, unlike error. */
#define gst_crash(vm, e) return ((vm)->crash = (e), GST_RETURN_CRASH)
/* Error if the condition is false */
#define gst_assert(vm, cond, e) do {if (!(cond)){gst_error((vm), (e));}} while (0)
static const char GST_NO_UPVALUE[] = "no upvalue"; static const char GST_NO_UPVALUE[] = "no upvalue";
static const char GST_EXPECTED_FUNCTION[] = "expected function"; static const char GST_EXPECTED_FUNCTION[] = "expected function";
static const char GST_EXPECTED_NUMBER_ROP[] = "expected right operand to be number"; static const char GST_EXPECTED_NUMBER_ROP[] = "expected right operand to be number";
static const char GST_EXPECTED_NUMBER_LOP[] = "expected left operand to be number"; static const char GST_EXPECTED_NUMBER_LOP[] = "expected left operand to be number";
/* Start running the VM from where it left off. Continue running /* Start running the VM from where it left off. */
* until the stack size is smaller than minStackSize. */ int gst_continue(Gst *vm) {
static int gst_continue_size(Gst *vm, uint32_t stackBase) {
/* VM state */ /* VM state */
GstValue *stack; GstValue *stack;
GstValue temp, v1, v2; GstValue temp, v1, v2;
uint16_t *pc; uint16_t *pc;
#define gst_exit(vm, r) return ((vm)->ret = (r), GST_RETURN_OK)
#define gst_error(vm, e) do { (vm)->ret = gst_string_cv((vm), (e)); goto vm_error; } while (0)
#define gst_crash(vm, e) return ((vm)->crash = (e), GST_RETURN_CRASH)
#define gst_assert(vm, cond, e) do {if (!(cond)){gst_error((vm), (e));}} while (0)
/* Intialize local state */ /* Intialize local state */
stack = vm->thread->data + vm->thread->count; stack = vm->thread->data + vm->thread->count;
pc = gst_frame_pc(stack); pc = gst_frame_pc(stack);
@ -188,20 +178,9 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
} }
break; break;
case GST_OP_TRY: /* Begin try block */
gst_frame_errloc(stack) = pc[1];
gst_frame_errjmp(stack) = pc + *(uint32_t *)(pc + 2);
pc += 4;
continue;
case GST_OP_UTY: /* End try block */
gst_frame_errjmp(stack) = NULL;
pc++;
continue;
case GST_OP_RTN: /* Return nil */ case GST_OP_RTN: /* Return nil */
stack = gst_thread_popframe(vm, vm->thread); stack = gst_thread_popframe(vm, vm->thread);
if (vm->thread->count < stackBase) { if (vm->thread->count < GST_FRAME_SIZE) {
vm->ret.type = GST_NIL; vm->ret.type = GST_NIL;
return GST_RETURN_OK; return GST_RETURN_OK;
} }
@ -212,7 +191,7 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
case GST_OP_RET: /* Return */ case GST_OP_RET: /* Return */
temp = stack[pc[1]]; temp = stack[pc[1]];
stack = gst_thread_popframe(vm, vm->thread); stack = gst_thread_popframe(vm, vm->thread);
if (vm->thread->count < stackBase) { if (vm->thread->count < GST_FRAME_SIZE) {
vm->ret = temp; vm->ret = temp;
return GST_RETURN_OK; return GST_RETURN_OK;
} }
@ -220,71 +199,132 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
stack[gst_frame_ret(stack)] = temp; stack[gst_frame_ret(stack)] = temp;
continue; continue;
case GST_OP_PSK: /* Push stack */
{
uint16_t arity = pc[1];
uint16_t i;
uint16_t newBase = gst_frame_size(stack) + GST_FRAME_SIZE;
gst_frame_args(stack) = newBase;
gst_thread_ensure_extra(vm, vm->thread, GST_FRAME_SIZE + arity);
stack = gst_thread_stack(vm->thread);
gst_frame_size(stack) += GST_FRAME_SIZE + arity;
/* Nil stuff */
for (i = 0; i < GST_FRAME_SIZE; ++i)
stack[newBase + i - GST_FRAME_SIZE].type = GST_NIL;
/* Write arguments */
for (i = 0; i < arity; ++i)
stack[newBase + i] = stack[pc[2 + i]];
pc += 2 + arity;
}
break;
case GST_OP_PAR: /* Push array or tuple */
{
uint32_t count, i, oldsize;
const GstValue *data;
temp = stack[pc[1]];
if (temp.type == GST_TUPLE) {
count = gst_tuple_length(temp.data.tuple);
data = temp.data.tuple;
} else if (temp.type == GST_ARRAY){
count = temp.data.array->count;
data = temp.data.array->data;
} else {
gst_error(vm, "expected array or tuple");
}
oldsize = gst_frame_size(stack);
gst_thread_pushnil(vm, vm->thread, count);
stack = gst_thread_stack(vm->thread);
for (i = 0; i < count; ++i)
stack[oldsize + i] = data[i];
pc += 2;
}
break;
case GST_OP_CAL: /* Call */ case GST_OP_CAL: /* Call */
{
uint16_t newStackIndex = gst_frame_args(stack);
uint16_t size = gst_frame_size(stack);
temp = stack[pc[1]];
gst_frame_ret(stack) = pc[2];
gst_frame_pc(stack) = pc + 3;
if (newStackIndex < GST_FRAME_SIZE)
gst_error(vm, "invalid call instruction");
vm->thread->count += newStackIndex;
stack = gst_thread_stack(vm->thread);
gst_frame_size(stack) = size - newStackIndex;
gst_frame_prevsize(stack) = newStackIndex;
gst_frame_callee(stack) = temp;
}
goto common_function_call;
case GST_OP_TCL: /* Tail call */ case GST_OP_TCL: /* Tail call */
{ {
GstValue *oldStack; uint16_t newStackIndex = gst_frame_args(stack);
uint16_t size = gst_frame_size(stack);
uint16_t i;
temp = stack[pc[1]]; temp = stack[pc[1]];
int isTCall = *pc == GST_OP_TCL; /* Check for closures */
uint32_t i, arity, offset, size; if (gst_frame_env(stack)) {
uint16_t ret = pc[2]; GstFuncEnv *env = gst_frame_env(stack);
offset = isTCall ? 3 : 4; env->thread = NULL;
arity = pc[offset - 1]; env->stackOffset = size;
/* Push new frame */ env->values = gst_alloc(vm, sizeof(GstValue) * size);
if (temp.type != GST_FUNCTION && temp.type != GST_CFUNCTION) gst_memcpy(env->values, stack, sizeof(GstValue) * size);
gst_error(vm, GST_EXPECTED_FUNCTION);
stack = gst_thread_beginframe(vm, vm->thread, temp, arity);
oldStack = stack - GST_FRAME_SIZE - gst_frame_prevsize(stack);
/* Write arguments */
size = gst_frame_size(stack);
for (i = 0; i < arity; ++i)
stack[i + size - arity] = oldStack[pc[offset + i]];
/* Finish new frame */
gst_thread_endframe(vm, vm->thread);
/* Check tail call - if so, replace frame. */
if (isTCall) {
stack = gst_thread_tail(vm, vm->thread);
} else {
gst_frame_ret(oldStack) = ret;
} }
/* Call function */ if (newStackIndex)
for (i = 0; i < size - newStackIndex; ++i)
stack[i] = stack[newStackIndex + i];
gst_frame_size(stack) = size - newStackIndex;
gst_frame_callee(stack) = temp;
}
goto common_function_call;
/* Code common to all function calls */
common_function_call:
gst_frame_args(stack) = 0;
gst_frame_env(stack) = NULL;
gst_thread_endframe(vm, vm->thread);
stack = vm->thread->data + vm->thread->count;
gst_frame_args(stack) = 0;
temp = gst_frame_callee(stack); temp = gst_frame_callee(stack);
if (temp.type == GST_FUNCTION) { if (temp.type == GST_FUNCTION) {
/* Save pc and set new pc */
if (!isTCall)
gst_frame_pc(oldStack) = pc + offset + arity;
pc = temp.data.function->def->byteCode; pc = temp.data.function->def->byteCode;
} else { } else if (temp.type == GST_CFUNCTION) {
int status; int status;
gst_frame_pc(stack) = pc;
vm->ret.type = GST_NIL; vm->ret.type = GST_NIL;
status = temp.data.cfunction(vm); status = temp.data.cfunction(vm);
stack = gst_thread_popframe(vm, vm->thread); stack = gst_thread_popframe(vm, vm->thread);
if (status == GST_RETURN_OK) { if (status == GST_RETURN_OK) {
if (vm->thread->count < stackBase) { if (vm->thread->count < GST_FRAME_SIZE) {
return status; return status;
} else { } else {
stack[gst_frame_ret(stack)] = vm->ret; stack[gst_frame_ret(stack)] = vm->ret;
if (isTCall)
pc = gst_frame_pc(stack); pc = gst_frame_pc(stack);
else
pc += offset + arity;
} }
} else { } else {
goto vm_error; goto vm_error;
} }
} } else {
gst_error(vm, GST_EXPECTED_FUNCTION);
} }
break; break;
case GST_OP_YLD: /* Yield to new thread */
temp = stack[pc[1]];
v1 = stack[pc[2]];
gst_assert(vm, v1.type == GST_THREAD, "expected thread");
gst_assert(vm, v1.data.thread->status != GST_THREAD_DEAD, "cannot rejoin dead thread");
gst_frame_pc(stack) = pc + 3;
vm->thread = v1.data.thread;
stack = vm->thread->data + vm->thread->count;
pc = gst_frame_pc(stack);
continue;
/* Faster implementations of standard functions /* Faster implementations of standard functions
* These opcodes are nto strictlyre required and can * These opcodes are nto strictlyre required and can
* be reimplemented with stanard library functions */ * be reimplemented with stanard library functions */
case GST_OP_ERR: /* Throw error */
vm->ret = stack[pc[1]];
goto vm_error;
#define OP_BINARY_MATH(op) \ #define OP_BINARY_MATH(op) \
v1 = stack[pc[2]]; \ v1 = stack[pc[2]]; \
v2 = stack[pc[3]]; \ v2 = stack[pc[3]]; \
@ -375,7 +415,7 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
{ {
uint32_t i = 3; uint32_t i = 3;
uint32_t kvs = pc[2]; uint32_t kvs = pc[2];
GstObject *o = gst_object(vm, 2 * kvs + 2); GstObject *o = gst_object(vm, 2 * kvs);
kvs = kvs + 3; kvs = kvs + 3;
while (i < kvs) { while (i < kvs) {
v1 = stack[pc[i++]]; v1 = stack[pc[i++]];
@ -403,30 +443,16 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
} }
break; break;
case GST_OP_YLD: /* Yield from function */
temp = stack[pc[1]];
if (vm->thread->parent == NULL) {
vm->ret = temp;
return GST_RETURN_OK;
}
gst_frame_pc(stack) = pc + 2;
vm->thread = vm->thread->parent;
stack = vm->thread->data + vm->thread->count;
pc = gst_frame_pc(stack);
break;
/* Handle errors from c functions and vm opcodes */ /* Handle errors from c functions and vm opcodes */
vm_error: vm_error:
if (stack == NULL) if (stack == NULL || vm->thread->parent == NULL)
return GST_RETURN_ERROR; return GST_RETURN_ERROR;
while (gst_frame_errjmp(stack) == NULL) { vm->thread->status = GST_THREAD_DEAD;
stack = gst_thread_popframe(vm, vm->thread); vm->thread = vm->thread->parent;
if (vm->thread->count < stackBase) stack = vm->thread->data + vm->thread->count;
return GST_RETURN_ERROR; pc = gst_frame_pc(stack);
} continue;
pc = gst_frame_errjmp(stack);
stack[gst_frame_errloc(stack)] = vm->ret;
break;
} /* end switch */ } /* end switch */
@ -439,11 +465,6 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
} }
/* Continue running the VM after it has stopped */
int gst_continue(Gst *vm) {
return gst_continue_size(vm, vm->thread->count);
}
/* Run the vm with a given function. This function is /* Run the vm with a given function. This function is
* called to start the vm. */ * called to start the vm. */
int gst_run(Gst *vm, GstValue callee) { int gst_run(Gst *vm, GstValue callee) {

View File

@ -79,17 +79,16 @@
/* Stack frame manipulation */ /* Stack frame manipulation */
/* Size of stack frame in number of values */ /* Size of stack frame in number of values */
#define GST_FRAME_SIZE 5 #define GST_FRAME_SIZE 4
/* Macros for referencing a stack frame given a stack */ /* Macros for referencing a stack frame given a stack */
#define gst_frame_callee(s) (*(s - 1)) #define gst_frame_callee(s) (*(s - 1))
#define gst_frame_size(s) ((s - 2)->data.hws[0]) #define gst_frame_size(s) ((s - 2)->data.hws[0])
#define gst_frame_prevsize(s) ((s - 2)->data.hws[1]) #define gst_frame_prevsize(s) ((s - 2)->data.hws[1])
#define gst_frame_errloc(s) ((s - 2)->data.hws[2]) #define gst_frame_args(s) ((s - 2)->data.hws[2])
#define gst_frame_ret(s) ((s - 2)->data.hws[3]) #define gst_frame_ret(s) ((s - 2)->data.hws[3])
#define gst_frame_pc(s) ((s - 3)->data.u16p) #define gst_frame_pc(s) ((s - 3)->data.u16p)
#define gst_frame_errjmp(s) ((s - 4)->data.u16p) #define gst_frame_env(s) ((s - 4)->data.env)
#define gst_frame_env(s) ((s - 5)->data.env)
/* C function helpers */ /* C function helpers */
@ -109,7 +108,7 @@
#ifndef GST_OUT_OF_MEMORY #ifndef GST_OUT_OF_MEMORY
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#define GST_OUT_OF_MEMORY do { printf("out of memory.\n"); exit(1); } while (0) #define GST_OUT_OF_MEMORY do { printf("out of memory\n"); exit(1); } while (0)
#endif #endif
/* Max search depth for classes. */ /* Max search depth for classes. */
@ -196,7 +195,7 @@ struct GstValue {
}; };
/* A lightweight thread in gst. Does not correspond to /* A lightweight thread in gst. Does not correspond to
* operating system threads. Used in coroutines. */ * operating system threads. Used in coroutines and continuations. */
struct GstThread { struct GstThread {
uint32_t count; uint32_t count;
uint32_t capacity; uint32_t capacity;
@ -292,7 +291,7 @@ struct Gst {
GstObject *registry; GstObject *registry;
/* Return state */ /* Return state */
const char *crash; const char *crash;
GstValue ret; /* Returned value from gst_start. Also holds errors. */ GstValue ret; /* Returned value from gst_start. */
}; };
/* Bytecode */ /* Bytecode */
@ -323,11 +322,10 @@ enum GstOpCode {
GST_OP_ARR, /* Create array */ GST_OP_ARR, /* Create array */
GST_OP_DIC, /* Create object */ GST_OP_DIC, /* Create object */
GST_OP_TUP, /* Create tuple */ GST_OP_TUP, /* Create tuple */
GST_OP_ERR, /* Throw error */
GST_OP_TRY, /* Begin try block */
GST_OP_UTY, /* End try block */
GST_OP_RET, /* Return from function */ GST_OP_RET, /* Return from function */
GST_OP_RTN, /* Return nil */ GST_OP_RTN, /* Return nil */
GST_OP_PSK, /* Push stack */
GST_OP_PAR, /* Push array or tuple */
GST_OP_CAL, /* Call function */ GST_OP_CAL, /* Call function */
GST_OP_TCL, /* Tail call */ GST_OP_TCL, /* Tail call */
GST_OP_YLD /* Yield from function */ GST_OP_YLD /* Yield from function */
@ -419,8 +417,6 @@ void gst_thread_tuplepack(Gst *vm, GstThread *thread, uint32_t n);
GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uint32_t arity); GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uint32_t arity);
void gst_thread_endframe(Gst *vm, GstThread *thread); void gst_thread_endframe(Gst *vm, GstThread *thread);
GstValue *gst_thread_popframe(Gst *vm, GstThread *thread); GstValue *gst_thread_popframe(Gst *vm, GstThread *thread);
GstValue *gst_thread_tail(Gst *vm, GstThread *thread);
/****/ /****/
/* Value manipulation */ /* Value manipulation */

20
libs/pp.gst Normal file
View File

@ -0,0 +1,20 @@
# Pretty print
# Reindent a function to be more deeply indented
(: reindent (fn [x] x))
(: handler {
"number" tostring
"nil" tostring
"boolean" tostring
"userdata" tostring
"cfunction" tostring
"function" tostring
"string" tostring # change to unquote string
"buffer" tostring
"array" tostring
"tuple" tostring
"object" tostring
"struct" tostring
"thread" tostring
})