From 58edb63607561be7265a001288e1806cd0ff58d2 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Thu, 11 May 2017 21:30:18 -0400 Subject: [PATCH] More work on serilaization --- core/compile.c | 21 ++++++++---------- core/serialize.c | 54 +++++++++++++++++++++++----------------------- core/stl.c | 5 ++++- core/vm.c | 27 +++++++++++++---------- libs/serialize.gst | 18 ++++++++++++++++ 5 files changed, 74 insertions(+), 51 deletions(-) create mode 100644 libs/serialize.gst diff --git a/core/compile.c b/core/compile.c index ad4e75f2..2d73af1f 100644 --- a/core/compile.c +++ b/core/compile.c @@ -481,19 +481,16 @@ static Slot compile_symbol(GstCompiler *c, FormOptions opts, GstValue sym) { /* We have a named literal */ return compile_literal(c, opts, lit); } else if (level > 0) { - /* We have an upvalue */ - if (level > 1) { - /* We have an upvalue from a parent function. Make - * sure that the chain of functions up to the upvalue keep - * their parent references */ - uint32_t i = level; - GstScope *scope = c->tail; - for (i = level; i > 1; --i) { - scope->touchParent = 1; - scope = scope->parent; - } - scope->touchEnv = 1; + /* We have an upvalue from a parent function. Make + * sure that the chain of functions up to the upvalue keep + * their parent references */ + uint32_t i = level; + GstScope *scope = c->tail; + for (i = level; i > 1; --i) { + scope->touchParent = 1; + scope = scope->parent; } + scope->touchEnv = 1; ret = compiler_get_target(c, opts); gst_buffer_push_u16(c->vm, buffer, GST_OP_UPV); gst_buffer_push_u16(c->vm, buffer, ret.index); diff --git a/core/serialize.c b/core/serialize.c index 825fc28a..27f4462a 100644 --- a/core/serialize.c +++ b/core/serialize.c @@ -240,7 +240,8 @@ static const char *gst_deserialize_impl( uint16_t prevsize = 0; uint8_t statusbyte; t = gst_thread(vm, gst_wrap_nil(), 64); - gst_array_push(vm, visited, gst_wrap_thread(t)); + ret = gst_wrap_thread(t); + gst_array_push(vm, visited, ret); err = gst_deserialize_impl(vm, data, end, &data, visited, &ret); if (err != NULL) return err; if (ret.type == GST_NIL) { @@ -250,30 +251,26 @@ static const char *gst_deserialize_impl( } else { return "expected thread parent to thread"; } - ret = gst_wrap_thread(t); deser_assert(data < end, UEB); statusbyte = *data++; read_u32(length); - /* Check for empty thread - TODO check for valid state */ - if (length == 0) - break; /* Set status */ - if (statusbyte == 0) t->status = GST_THREAD_PENDING; - else if (statusbyte == 1) t->status = GST_THREAD_ALIVE; - else t->status = GST_THREAD_DEAD; + t->status = statusbyte % 4; /* Add frames */ for (i = 0; i < length; ++i) { GstValue callee, env; uint32_t pcoffset; uint16_t ret, args, size, j; - /* Create a new frame */ - if (i > 0) - gst_thread_beginframe(vm, t, gst_wrap_nil(), 0); /* Read the stack */ err = gst_deserialize_impl(vm, data, end, &data, visited, &callee); if (err != NULL) return err; err = gst_deserialize_impl(vm, data, end, &data, visited, &env); if (err != NULL) return err; + if (env.type != GST_FUNCENV && env.type != GST_NIL) + return "expected funcenv in stackframe"; + /* Create a new frame */ + if (i > 0) + gst_thread_beginframe(vm, t, gst_wrap_nil(), 0); read_u32(pcoffset); read_u32(ret); read_u32(args); @@ -282,15 +279,16 @@ static const char *gst_deserialize_impl( stack = gst_thread_stack(t); if (callee.type == GST_FUNCTION) { gst_frame_pc(stack) = callee.data.function->def->byteCode + pcoffset; - if (env.type == GST_FUNCENV) - gst_frame_env(stack) = env.data.env; - else - gst_frame_env(stack) = NULL; } gst_frame_ret(stack) = ret; gst_frame_args(stack) = args; gst_frame_size(stack) = size; gst_frame_prevsize(stack) = prevsize; + gst_frame_callee(stack) = callee; + if (env.type == GST_NIL) + gst_frame_env(stack) = NULL; + else + gst_frame_env(stack) = env.data.env; prevsize = size; /* Push stack args */ for (j = 0; j < size; ++j) { @@ -333,6 +331,8 @@ static const char *gst_deserialize_impl( def->literalsLen = literalsLen; if (literalsLen > 0) { def->literals = gst_alloc(vm, literalsLen * sizeof(GstValue)); + } else { + def->literals = NULL; } for (i = 0; i < literalsLen; ++i) { err = gst_deserialize_impl(vm, data, end, &data, visited, def->literals + i); @@ -385,6 +385,9 @@ static const char *gst_deserialize_impl( if (err != NULL) return err; err = gst_deserialize_impl(vm, data, end, &data, visited, &env); if (err != NULL) return err; + printf("parent: %s\n", (const char *)gst_to_string(vm, parent)); + printf("def: %s\n", (const char *)gst_to_string(vm, def)); + printf("env: %s\n", (const char *)gst_to_string(vm, env)); if (parent.type == GST_NIL) { ret.data.function->parent = NULL; } else if (parent.type == GST_FUNCTION) { @@ -472,6 +475,7 @@ const char *gst_serialize_impl( #define write_u16(b) gst_buffer_push_u16(vm, buffer, (b)) #define write_dbl(b) gst_buffer_push_real(vm, buffer, (b)) #define write_int(b) gst_buffer_push_integer(vm, buffer, (b)) + /*printf("Type: %d\n", x.type);*/ /* Check non reference types - if successful, return NULL */ switch (x.type) { @@ -613,9 +617,7 @@ const char *gst_serialize_impl( err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_nil()); if (err != NULL) return err; /* Write the status byte */ - if (t->status == GST_THREAD_PENDING) write_byte(0); - else if (t->status == GST_THREAD_ALIVE) write_byte(1); - else write_byte(2); + write_byte(t->status); /* Write number of stack frames */ write_u32(framecount); /* Write stack frames */ @@ -689,19 +691,17 @@ const char *gst_serialize_impl( case GST_FUNCTION: /* Function */ { + GstValue pv, ev, dv; GstFunction *fn = x.data.function; write_byte(214); - if (fn->parent) - err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_function(fn->parent)); - else - err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_nil()); + pv = fn->parent ? gst_wrap_function(fn->parent) : gst_wrap_nil(); + dv = gst_wrap_funcdef(fn->def); + ev = fn->env ? gst_wrap_funcenv(fn->env) : gst_wrap_nil(); + err = gst_serialize_impl(vm, buffer, visited, nextId, pv); if (err != NULL) return err; - err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_funcdef(fn->def)); + err = gst_serialize_impl(vm, buffer, visited, nextId, dv); if (err != NULL) return err; - if (fn->env == NULL) - err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_nil()); - else - err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_funcenv(fn->env)); + err = gst_serialize_impl(vm, buffer, visited, nextId, ev); if (err != NULL) return err; } break; diff --git a/core/stl.c b/core/stl.c index af12ad9b..342d3d07 100644 --- a/core/stl.c +++ b/core/stl.c @@ -648,7 +648,10 @@ int gst_stl_funcenv(Gst *vm) { GstFunction *fn; if (!gst_check_function(vm, 0, &fn)) gst_c_throwc(vm, "expected function"); - gst_c_return(vm, gst_wrap_funcenv(fn->env)); + if (fn->env) + gst_c_return(vm, gst_wrap_funcenv(fn->env)); + else + return GST_RETURN_OK; } int gst_stl_funcdef(Gst *vm) { diff --git a/core/vm.c b/core/vm.c index 1ea1303f..4eae93c4 100644 --- a/core/vm.c +++ b/core/vm.c @@ -161,16 +161,6 @@ int gst_continue(Gst *vm) { { GstFunction *fn; v1 = gst_frame_callee(stack); - if (v1.type != GST_FUNCTION) - gst_error(vm, GST_EXPECTED_FUNCTION); - if (gst_frame_env(stack) == NULL) { - gst_frame_env(stack) = gst_alloc(vm, sizeof(GstFuncEnv)); - gst_frame_env(stack)->thread = vm->thread; - gst_frame_env(stack)->stackOffset = vm->thread->count; - gst_frame_env(stack)->values = NULL; - } - if (pc[2] > v1.data.function->def->literalsLen) - gst_error(vm, GST_NO_UPVALUE); temp = v1.data.function->def->literals[pc[2]]; if (temp.type != GST_FUNCDEF) gst_error(vm, "cannot create closure from non-funcdef"); @@ -180,7 +170,20 @@ int gst_continue(Gst *vm) { fn->parent = v1.data.function; else fn->parent = NULL; - fn->env = gst_frame_env(stack); + if (v1.type != GST_FUNCTION) + gst_error(vm, GST_EXPECTED_FUNCTION); + if (gst_frame_env(stack) == NULL && (fn->def->flags & GST_FUNCDEF_FLAG_NEEDSENV)) { + gst_frame_env(stack) = gst_alloc(vm, sizeof(GstFuncEnv)); + gst_frame_env(stack)->thread = vm->thread; + gst_frame_env(stack)->stackOffset = vm->thread->count; + gst_frame_env(stack)->values = NULL; + } + if (pc[2] > v1.data.function->def->literalsLen) + gst_error(vm, GST_NO_UPVALUE); + if (fn->def->flags & GST_FUNCDEF_FLAG_NEEDSENV) + fn->env = gst_frame_env(stack); + else + fn->env = NULL; temp.type = GST_FUNCTION; temp.data.function = fn; stack[pc[1]] = temp; @@ -365,6 +368,8 @@ int gst_continue(Gst *vm) { temp.data.thread->status = GST_THREAD_ALIVE; vm->thread = temp.data.thread; stack = gst_thread_stack(temp.data.thread); + if (gst_frame_callee(stack).type != GST_FUNCTION) + goto vm_return; stack[gst_frame_ret(stack)] = v1; pc = gst_frame_pc(stack); continue; diff --git a/libs/serialize.gst b/libs/serialize.gst new file mode 100644 index 00000000..103b324f --- /dev/null +++ b/libs/serialize.gst @@ -0,0 +1,18 @@ +(export! "scheck" (fn [x] + (: dat (serialize x)) + (: deser (deserialize dat)) + (print (debugp deser)) + deser +)) + +(scheck 1) +(scheck true) +(scheck nil) +(scheck "asdasdasd") +(scheck (struct 1 2 3 4)) +(scheck (tuple 1 2 3)) +(scheck 123412.12) +(scheck (funcdef (fn [] 1))) +(scheck (funcenv (fn [] 1))) +(scheck (funcenv ((fn [a] (fn [] a)) 1))) +(scheck (fn [] 1))