From ca67450776cb6c2cf361a7156f66bd868624f5cc Mon Sep 17 00:00:00 2001 From: Shaw Summa Date: Wed, 15 May 2024 07:10:13 -0400 Subject: [PATCH] save system --- .vscode/settings.json | 13 +--- vm/lua/repl.c | 25 +++++--- vm/save/read.c | 142 ++++++++++++++++++++++++++++++++++++++++-- vm/save/save.h | 3 +- vm/save/write.c | 94 ++++++++++++++++------------ 5 files changed, 212 insertions(+), 65 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 42e719f4..f5909b64 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,17 +2,6 @@ "files.associations": { "*.inc": "c", "*.c": "c", - "*.h": "c", - "compare": "c", - "cstdint": "c", - "*.tcc": "c", - "optional": "c", - "system_error": "c", - "array": "c", - "functional": "c", - "tuple": "c", - "type_traits": "c", - "utility": "c", - "cstddef": "c" + "*.h": "c" } } \ No newline at end of file diff --git a/vm/lua/repl.c b/vm/lua/repl.c index 18ee53fc..529a423b 100644 --- a/vm/lua/repl.c +++ b/vm/lua/repl.c @@ -236,13 +236,17 @@ void vm_lang_lua_repl(vm_config_t *config, vm_table_t *std, vm_blocks_t *blocks) .std = std, }; - vm_save_t save = vm_save_value((vm_std_value_t) {.tag = VM_TAG_TAB, .value.table = std}); - std = vm_load_value(save).value.table; - // FILE *f = fopen("out.bin", "wb"); - // if (f != NULL) { - // fwrite(save.buf, 1, save.len, f); - // fclose(f); - // } + { + FILE *f = fopen("out.bin", "rb"); + if (f != NULL) { + vm_save_t save = vm_save_load(f); + fclose(f); + vm_std_value_t val = vm_load_value(save); + if (val.tag == VM_TAG_TAB) { + std = val.value.table; + } + } + } // #if defined(EMSCRIPTEN) // setvbuf(stdin, NULL, _IONBF, 0); @@ -306,5 +310,12 @@ void vm_lang_lua_repl(vm_config_t *config, vm_table_t *std, vm_blocks_t *blocks) printf("took: %.3fms\n", diff); } + + vm_save_t save = vm_save_value((vm_std_value_t) {.tag = VM_TAG_TAB, .value.table = std}); + FILE *f = fopen("out.bin", "wb"); + if (f != NULL) { + fwrite(save.buf, 1, save.len, f); + fclose(f); + } } } \ No newline at end of file diff --git a/vm/save/read.c b/vm/save/read.c index 6620788d..ab40f33c 100644 --- a/vm/save/read.c +++ b/vm/save/read.c @@ -4,10 +4,18 @@ struct vm_save_read_t; typedef struct vm_save_read_t vm_save_read_t; +struct vm_save_value_t; +typedef struct vm_save_value_t vm_save_value_t; + +struct vm_save_value_t { + size_t start; + vm_std_value_t value; +}; + struct vm_save_read_t { struct { size_t len; - vm_std_value_t *ptr; + vm_save_value_t *ptr; size_t alloc; } values; @@ -61,16 +69,138 @@ vm_std_value_t vm_load_value(vm_save_t arg) { .buf.len = arg.len, .buf.bytes = arg.buf, .buf.read = 0, + .values.len = 0, + .values.ptr = NULL, + .values.alloc = 0, }; while (!vm_save_read_is_done(&read)) { - vm_tag_t type = (vm_tag_t) vm_save_read_byte(&read); - vm_value_t val; - switch (type) { + size_t start = read.buf.read; + vm_tag_t tag = (vm_tag_t) vm_save_read_byte(&read); + vm_value_t value; + switch (tag) { + case VM_TAG_UNK: { + break; + } + case VM_TAG_NIL: { + value.all = NULL; + break; + } + case VM_TAG_BOOL: { + value.b = vm_save_read_byte(&read) != 0; + break; + } + case VM_TAG_I8: { + value.i8 = (int8_t) vm_save_read_sleb(&read); + break; + } + case VM_TAG_I16: { + value.i16 = (int16_t) vm_save_read_sleb(&read); + break; + } + case VM_TAG_FUN: + case VM_TAG_I32: { + value.i32 = (int32_t) vm_save_read_sleb(&read); + break; + } + case VM_TAG_I64: { + value.i64 = (int64_t) vm_save_read_sleb(&read); + break; + } + case VM_TAG_F32: { + uint32_t n = (uint32_t) vm_save_read_uleb(&read); + value.f32 = *(float *)&n; + break; + } + case VM_TAG_F64: { + uint64_t n = vm_save_read_uleb(&read); + value.f64 = *(double *)&n; + break; + } + case VM_TAG_ERROR: + case VM_TAG_STR: { + uint64_t len = vm_save_read_uleb(&read); + char *buf = vm_malloc(sizeof(char) * len); + for (size_t i = 0; i < len; i++) { + buf[i] = vm_save_read_byte(&read); + } + value.str = buf; + break; + } + case VM_TAG_FFI: { + value.all = (void *) (size_t) vm_save_read_uleb(&read); + break; + } + case VM_TAG_CLOSURE: { + uint64_t len = vm_save_read_uleb(&read); + vm_std_value_t *closure = vm_malloc(sizeof(vm_std_value_t) * (len + 1)); + closure[0] = (vm_std_value_t) { + .tag = VM_TAG_I32, + .value.i32 = (int32_t) (uint32_t) len, + }; + closure += 1; + for (size_t i = 0; i < len; i++) { + vm_save_read_uleb(&read); + } + value.closure = closure; + } + case VM_TAG_TAB: { + uint64_t real = vm_save_read_uleb(&read); + vm_table_t *table = vm_table_new(); + for (size_t i = 0; i < real; i++) { + vm_save_read_uleb(&read); + vm_save_read_uleb(&read); + } + value.table = table; + break; + } + default: { + fprintf(stderr, "unhandled object #%zu at [%zu]: type %zu\n", read.values.len, start, (size_t) tag); + goto error; + } + } + if (read.values.len + 1 >= read.values.alloc) { + read.values.alloc = (read.values.len + 1) * 2; + read.values.ptr = vm_realloc(read.values.ptr, sizeof(vm_save_value_t) * read.values.alloc); + } + read.values.ptr[read.values.len++] = (vm_save_value_t) { + .start = start, + .value = (vm_std_value_t) { + .tag = tag, + .value = value, + }, + }; + } + for (size_t i = 0; i < read.values.len; i++) { + vm_save_value_t save = read.values.ptr[i]; + vm_value_t value = save.value.value; + read.buf.read = save.start; + vm_tag_t tag = (vm_tag_t) vm_save_read_byte(&read); + switch (tag) { + case VM_TAG_CLOSURE: { + uint64_t len = vm_save_read_uleb(&read); + vm_std_value_t *closure = value.closure; + for (uint64_t i = 0; i < len; i++) { + size_t value_index = vm_save_read_uleb(&read); + closure[i] = read.values.ptr[value_index].value; + } + break; + } + case VM_TAG_TAB: { + uint64_t real = vm_save_read_uleb(&read); + vm_table_t *table = value.table; + for (size_t i = 0; i < real; i++) { + size_t key_index = vm_save_read_uleb(&read); + size_t value_index = vm_save_read_uleb(&read); + VM_TABLE_SET_VALUE(table, read.values.ptr[key_index].value, read.values.ptr[value_index].value); + } + break; + } default: { - fprintf("unhandled object %zu at %zu\n", read.values.len, read.buf.read); break; } } } - return read.values.ptr[0]; + return read.values.ptr[0].value; +error:; + return (vm_std_value_t) {.tag = VM_TAG_NIL}; } diff --git a/vm/save/save.h b/vm/save/save.h index 3012c240..3c9a4bf1 100644 --- a/vm/save/save.h +++ b/vm/save/save.h @@ -12,7 +12,8 @@ struct vm_save_t { uint8_t *buf; }; -vm_save_t vm_save_value(vm_std_value_t arg); +vm_save_t vm_save_load(FILE *file); vm_std_value_t vm_load_value(vm_save_t arg); +vm_save_t vm_save_value(vm_std_value_t arg); #endif diff --git a/vm/save/write.c b/vm/save/write.c index f2d63290..0e8c0369 100644 --- a/vm/save/write.c +++ b/vm/save/write.c @@ -5,18 +5,18 @@ struct vm_save_write_t; typedef struct vm_save_write_t vm_save_write_t; struct vm_save_write_t { + struct { + size_t len; + uint8_t *bytes; + size_t alloc; + } buf; + struct { size_t read; size_t write; vm_std_value_t *buf; size_t alloc; } values; - - struct { - size_t len; - uint8_t *bytes; - size_t alloc; - } buf; }; static size_t vm_save_write_push(vm_save_write_t *write, vm_std_value_t value) { @@ -51,7 +51,7 @@ static void vm_save_write_byte(vm_save_write_t *write, uint8_t value) { write->buf.bytes[index] = value; } -void vm_save_write_uint(vm_save_write_t *write, uint64_t value) { +void vm_save_write_uleb(vm_save_write_t *write, uint64_t value) { do { uint8_t byte = value & 0x7F; value >>= 7; @@ -62,17 +62,17 @@ void vm_save_write_uint(vm_save_write_t *write, uint64_t value) { } while (value != 0); } -void vm_save_write_sint(vm_save_write_t *write, int64_t value) { +void vm_save_write_sleb(vm_save_write_t *write, int64_t value) { size_t len = 0; uint8_t result[10]; while (true) { uint8_t byte = value & 0x7F; value >>= 7; if ((value == 0 && (byte & 0x40) == 0) || (value == -1 && (byte & 0x40) != 0)) { - vm_save_write_uint(write, byte); + vm_save_write_uleb(write, byte); break; } - vm_save_write_uint(write, byte | 0x80); + vm_save_write_uleb(write, byte | 0x80); } } @@ -88,7 +88,6 @@ vm_save_t vm_save_value(vm_std_value_t arg) { }; vm_save_write_push(&write, arg); while (!vm_save_write_is_done(&write)) { - printf("object %zu at %zu\n", write.values.read, write.buf.len); vm_std_value_t value = vm_save_write_shift(&write); vm_save_write_byte(&write, value.tag); switch (value.tag) { @@ -103,59 +102,54 @@ vm_save_t vm_save_value(vm_std_value_t arg) { break; } case VM_TAG_I8: { - vm_save_write_sint(&write, (int64_t) value.value.i8); + vm_save_write_sleb(&write, (int64_t) value.value.i8); break; } case VM_TAG_I16: { - vm_save_write_sint(&write, (int64_t) value.value.i16); + vm_save_write_sleb(&write, (int64_t) value.value.i16); break; } + case VM_TAG_FUN: case VM_TAG_I32: { - vm_save_write_sint(&write, (int64_t) value.value.i32); + vm_save_write_sleb(&write, (int64_t) value.value.i32); break; } case VM_TAG_I64: { - vm_save_write_sint(&write, value.value.i64); + vm_save_write_sleb(&write, value.value.i64); break; } case VM_TAG_F32: { - vm_save_write_uint(&write, (uint64_t) *(uint32_t *) &value.value.f64); + vm_save_write_uleb(&write, (uint64_t) *(uint32_t *) &value.value.f64); break; } case VM_TAG_F64: { - vm_save_write_uint(&write, *(uint64_t *) &value.value.f64); + vm_save_write_uleb(&write, *(uint64_t *) &value.value.f64); break; } + case VM_TAG_ERROR: case VM_TAG_STR: { const char *buf = value.value.str; - while (true) { - char c = *buf++; - vm_save_write_byte(&write, (uint8_t) c); - if (c == '\0') { - break; - } + size_t len = strlen(buf) + 1; + vm_save_write_uleb(&write, (uint64_t) len); + for (size_t i = 0; i < len; i++) { + vm_save_write_byte(&write, (uint8_t) buf[i]); } break; } case VM_TAG_CLOSURE: { vm_std_value_t *closure = value.value.closure; uint32_t len = closure[-1].value.i32; - vm_save_write_uint(&write, (uint64_t) len); + vm_save_write_uleb(&write, (uint64_t) len); for (uint32_t i = 0; i < len; i++) { size_t ent = vm_save_write_push(&write, closure[i]); - vm_save_write_uint(&write, (uint64_t) ent); + vm_save_write_uleb(&write, (uint64_t) ent); } break; } - case VM_TAG_FUN: { - vm_save_write_uint(&write, (uint64_t) value.value.i32); - break; - } case VM_TAG_TAB: { vm_table_t *table = value.value.table; uint32_t len = (uint32_t) 1 << table->alloc; size_t real = 0; - vm_save_write_uint(&write, (uint64_t) len); for (size_t i = 0; i < len; i++) { vm_pair_t pair = table->pairs[i]; if (pair.key_tag != VM_TAG_UNK) { @@ -164,20 +158,20 @@ vm_save_t vm_save_value(vm_std_value_t arg) { real += 1; } } - for (size_t i = 0; i < real; i++) { + vm_save_write_uleb(&write, (uint64_t) real); + for (size_t i = 0; i < len; i++) { vm_pair_t pair = table->pairs[i]; - size_t key = vm_save_write_push(&write, (vm_std_value_t) {.tag = pair.key_tag, .value = pair.key_val}); - size_t value = vm_save_write_push(&write, (vm_std_value_t) {.tag = pair.val_tag, .value = pair.val_val}); - vm_save_write_uint(&write, (uint64_t) key); - vm_save_write_uint(&write, (uint64_t) value); + if (pair.key_tag != VM_TAG_UNK) { + size_t key = vm_save_write_push(&write, (vm_std_value_t) {.tag = pair.key_tag, .value = pair.key_val}); + size_t value = vm_save_write_push(&write, (vm_std_value_t) {.tag = pair.val_tag, .value = pair.val_val}); + vm_save_write_uleb(&write, (uint64_t) key); + vm_save_write_uleb(&write, (uint64_t) value); + } } break; } case VM_TAG_FFI: { - vm_save_write_uint(&write, (uint64_t) (size_t) value.value.all); - break; - } - case VM_TAG_ERROR: { + vm_save_write_uleb(&write, (uint64_t) (size_t) value.value.all); break; } default: { @@ -193,3 +187,25 @@ vm_save_t vm_save_value(vm_std_value_t arg) { .buf = write.buf.bytes, }; } + +vm_save_t vm_save_load(FILE *in) { + size_t nalloc = 512; + uint8_t *ops = vm_malloc(sizeof(char) * nalloc); + size_t nops = 0; + size_t size; + for (;;) { + if (nops + 256 >= nalloc) { + nalloc = (nops + 256) * 2; + ops = vm_realloc(ops, sizeof(char) * nalloc); + } + size = fread(&ops[nops], 1, 256, in); + nops += size; + if (size < 256) { + break; + } + } + return (vm_save_t) { + .len = nops, + .buf = ops, + }; +}