--- /dev/null
+
+# Reloadable file format
+
+## Necessary sections
+
+- [ ] Header
+- [ ] Code
+- [ ] Data
+- [ ] Func Desc
+- [ ] Native Func Link
+
+### Header
+"OVMI"
+4-byte version
+
+### Code
+Raw bytes that represent the instructions.
+Array of 16-byte instructions.
+
+instr-count (32-bit LE integer) | instrs ...
+
+### Data
+Where, how-long and what the data is.
+
+entry-count (32-bit LE integer) | (offset (32-bit) | size (32-bit) | data ...) ...
+
+### Func Desc
+How many functions.
+Where they start.
+How many params each.
+How many values each.
+
+func-count | (start-instr | param-count | value-count) ...
+
+### Native Func Link
+How many native fucntions.
+The names in numerical order.
+
+func-count | (param-count | name-len-with-null (32-bit integer) | name data (null-terminated)) ...
+
};
ovm_program_t *ovm_program_new(ovm_store_t *store);
-void ovm_program_delete(ovm_program_t *program);
-void ovm_program_add_instructions(ovm_program_t *program, i32 instr_count, ovm_instr_t *instrs);
-void ovm_program_print_instructions(ovm_program_t *program, i32 start_instr, i32 instr_count);
+void ovm_program_delete(ovm_program_t *program);
+void ovm_program_add_instructions(ovm_program_t *program, i32 instr_count, ovm_instr_t *instrs);
+void ovm_program_print_instructions(ovm_program_t *program, i32 start_instr, i32 instr_count);
-void ovm_program_register_func(ovm_program_t *program, char *name, i32 instr, i32 param_count, i32 value_number_count);
-void ovm_program_begin_func(ovm_program_t *program, char *name, i32 param_count, i32 value_number_count);
-void ovm_program_register_native_func(ovm_program_t *program, void (*func)(void *, ovm_value_t *, ovm_value_t *), void *data, i32 param_count);
+void ovm_program_register_func(ovm_program_t *program, char *name, i32 instr, i32 param_count, i32 value_number_count);
+void ovm_program_begin_func(ovm_program_t *program, char *name, i32 param_count, i32 value_number_count);
+void ovm_program_register_native_func(ovm_program_t *program, char *name,
+ void (*func)(void *, ovm_value_t *, ovm_value_t *), void *data, i32 param_count);
//
// Represents the running configuration and static
void ovm_engine_delete(ovm_engine_t *engine);
void ovm_engine_memory_copy(ovm_engine_t *engine, i64 target, void *data, i64 size);
+bool ovm_program_load_from_file(ovm_program_t *program, ovm_engine_t *engine, char *filename);
+void ovm_program_link_native_funcs(ovm_program_t *program, ovm_native_func_t *funcs);
+
//
// Represents ephemeral state / execution context.
// If multiple threads are used, multiple states are needed.
void ovm_func_delete(ovm_func_t *func);
struct ovm_native_func_t {
+ char *name;
i32 param_count;
void (*native_func)(void *userdata, ovm_value_t* params, ovm_value_t* result);
void *userdata;
};
-ovm_value_t ovm_func_call(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *program, i32 func_idx, i32 param_count, ovm_value_t *params);
+ovm_value_t ovm_func_call(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *program, i32 func_idx,
+ i32 param_count, ovm_value_t *params);
void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *program);
//
ovm_program_begin_func(prog, "add", 2, 6);
ovm_program_add_instructions(prog, sizeof(func2_instrs) / sizeof(*func2_instrs), func2_instrs);
- ovm_program_register_native_func(prog, print_result, NULL, 1);
+ ovm_program_register_native_func(prog, "print_result", print_result, NULL, 1);
ovm_program_print_instructions(prog, 0, bh_arr_length(prog->code));
--- /dev/null
+#include "vm.h"
+
+//
+// I'm very lazy and silly, so this code make the drastic assumption that the
+// endianness of the machine that the file was built on and the machine the
+// VM is running on are the SAME. If this is not the case, the integers very
+// well could be f-ed up. Might be worth switching all integers to use ntohl,
+// so at least that part is consistent... -brendanfh 06/13/2022
+//
+
+//
+// I wish this didn't take the engine as a parameter... but currently the memory
+// is stored on the engine. So unless the data section elements can be aggregated
+// into an array to be applied later, this is best I got...
+bool ovm_program_load_from_file(ovm_program_t *program, ovm_engine_t *engine, char *filename) {
+ bh_file file;
+ bh_file_error error = bh_file_open(&file, filename);
+ if (error != BH_FILE_ERROR_NONE) {
+ fprintf(stderr, "Failed to open '%s' for reading.\n", filename);
+ return false;
+ }
+
+ char magic[4], version[4];
+ bh_file_read(&file, magic, 4);
+ bh_file_read(&file, version, 4);
+
+ if (strncmp(magic, "OVMI", 4) || strncmp(version, "\x00\x00\x00\x01", 4)) {
+ fprintf(stderr, "Mismatched version/magic number in '%s'.\n", filename);
+ return false;
+ }
+
+ //
+ // Code section
+ // Just copy in the bytes directly.
+ // What's validation anyway?
+ //
+ i32 entry_count;
+ bh_file_read(&file, &entry_count, sizeof(i32));
+ bh_arr_insert_end(program->code, entry_count);
+ bh_file_read(&file, &bh_arr_last(program->code), entry_count * sizeof(ovm_instr_t));
+
+ //
+ // Data section
+ //
+ bh_file_read(&file, &entry_count, sizeof(i32));
+ fori (i, 0, entry_count) {
+ i32 offset, size;
+ bh_file_read(&file, &offset, sizeof(i32));
+ bh_file_read(&file, &size, sizeof(i32));
+
+ assert(engine);
+ assert(engine->memory);
+ bh_file_read(&file, ((u8 *) engine->memory) + offset, size);
+ }
+
+ //
+ // Func section
+ //
+ bh_file_read(&file, &entry_count, sizeof(i32));
+ fori (i, 0, entry_count) {
+ i32 start_instr, param_count, value_number_count;
+ bh_file_read(&file, &start_instr, sizeof(i32));
+ bh_file_read(&file, ¶m_count, sizeof(i32));
+ bh_file_read(&file, &value_number_count, sizeof(i32));
+
+ ovm_program_register_func(program, "LOADED", start_instr, param_count, value_number_count);
+ }
+
+ //
+ // Native link section
+ //
+ bh_file_read(&file, &entry_count, sizeof(i32));
+ fori (i, 0, entry_count) {
+ i32 param_count, name_len;
+ bh_file_read(&file, ¶m_count, sizeof(i32));
+ bh_file_read(&file, &name_len, sizeof(i32));
+
+ char *name_buf = bh_alloc_array(program->store->arena_allocator, char, name_len);
+ bh_file_read(&file, name_buf, name_len);
+
+ ovm_program_register_native_func(program, name_buf, NULL, NULL, param_count);
+ }
+
+
+ return true;
+}
+
+void ovm_program_link_native_funcs(ovm_program_t *program, ovm_native_func_t *funcs) {
+ bh_arr_each(ovm_native_func_t, nf, program->native_funcs) {
+ if (nf->native_func && nf->userdata) continue;
+
+ ovm_native_func_t *func = funcs;
+ while (func->name) {
+ if (!strcmp(nf->name, func->name) && nf->param_count == func->param_count) {
+ nf->native_func = func->native_func;
+ nf->userdata = func->userdata;
+ }
+
+ func++;
+ }
+ }
+}
bh_arr_push(program->funcs, func);
}
-void ovm_program_register_native_func(ovm_program_t *program, void (*func)(void *, ovm_value_t *, ovm_value_t *), void *data, i32 param_count) {
+void ovm_program_register_native_func(ovm_program_t *program, char *name,
+ void (*func)(void *, ovm_value_t *, ovm_value_t *), void *data, i32 param_count) {
+
ovm_native_func_t native_func;
+ native_func.name = name;
native_func.param_count = param_count;
native_func.native_func = func;
native_func.userdata = data;