diff --git a/byterun/dune b/byterun/dune index 6329b01cc..cdf26d2e8 100644 --- a/byterun/dune +++ b/byterun/dune @@ -5,26 +5,13 @@ (:main src/cli.cpp) (:parser src/parser.cpp) (:analyzer src/analyzer.cpp) + (:module_manager module_manager.o) (:obj types.o interpreter.o) (:runtime ../runtime/runtime.a)) (mode (promote (until-clean))) (action - (run g++ -std=c++20 -DWITH_CHECK -Iinclude/ %{main} %{parser} %{analyzer} %{runtime} %{obj} -o %{target}))) - -(rule - (target old_byterun.exe) - (deps - (:include (source_tree include)) - (:main src/cli.cpp) - (:parser src/parser.cpp) - (:analyzer src/analyzer.cpp) - (:obj old_types.o old_interpreter.o) - (:runtime ../runtime/runtime.a)) - (mode - (promote (until-clean))) - (action - (run g++ -std=c++20 -Iinclude/ %{main} %{parser} %{analyzer} %{runtime} %{obj} -o %{target}))) + (run g++ -std=c++20 -DWITH_CHECK -Iinclude/ %{main} %{parser} %{analyzer} %{module_manager} %{runtime} %{obj} -o %{target}))) (rule (target types.o) @@ -49,23 +36,12 @@ (run gcc -Iinclude/ -DWITH_CHECK -c %{src} -o %{target}))) (rule - (target old_types.o) - (deps - (:include (source_tree include)) - (:src src/types.c) - (:runtime ../runtime/runtime.a)) - (mode - (promote (until-clean))) - (action - (run gcc -Iinclude/ -c %{src} -o %{target}))) - -(rule - (target old_interpreter.o) - (deps - (:include (source_tree include)) - (:src src/interpreter.c) - (:runtime ../runtime/runtime.a)) - (mode - (promote (until-clean))) - (action - (run gcc -Iinclude/ -c %{src} -o %{target}))) +(target module_manager.o) +(deps + (:include (source_tree include)) + (:src src/module_manager.cpp) + (:runtime ../runtime/runtime.a)) + (mode + (promote (until-clean))) + (action + (run g++ -Iinclude/ -c %{src} -o %{target}))) diff --git a/byterun/include/interpreter.h b/byterun/include/interpreter.h index 6c7e4a7f4..a3b934239 100644 --- a/byterun/include/interpreter.h +++ b/byterun/include/interpreter.h @@ -2,4 +2,14 @@ #include "utils.h" -void run(Bytefile *bf, int argc, char **argv); +// void run(Bytefile *bf, int argc, char **argv); + +void run_init(size_t *stack); + +void run_mod_rec(uint mod_id, int argc, char **argv); + +void run_prepare_exec(int argc, char **argv); + +void run_mod(uint mod_id, int argc, char **argv); + +void run_cleanup(); diff --git a/byterun/include/module_manager.h b/byterun/include/module_manager.h new file mode 100644 index 000000000..f53be3333 --- /dev/null +++ b/byterun/include/module_manager.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include "utils.h" + +struct ModSearchResult { + size_t symbol_offset; + uint32_t mod_id; + Bytefile *mod_file; // = NULL => not found +}; + +void mod_add_search_path(const char *path); + +Bytefile *mod_get(uint32_t id); + +int32_t find_mod_loaded(const char *name); // < 0 => not found + +int32_t mod_load(const char *name); // < 0 => not found + +uint32_t mod_add(Bytefile *module); + +struct ModSearchResult mod_search_pub_symbol(const char *name); diff --git a/byterun/include/parser.hpp b/byterun/include/parser.hpp index 5b8f8b3b3..afefe0029 100644 --- a/byterun/include/parser.hpp +++ b/byterun/include/parser.hpp @@ -35,6 +35,7 @@ enum class Cmd : int8_t { ARRAY, FAIL, LINE, + CALLF, PATT, Lread, Lwrite, diff --git a/byterun/include/stack.h b/byterun/include/stack.h index 246c855de..2c541b9b9 100644 --- a/byterun/include/stack.h +++ b/byterun/include/stack.h @@ -1,6 +1,7 @@ #pragma once #include "../../runtime/gc.h" +#include "module_manager.h" #include "runtime_externs.h" #include "types.h" #include "utils.h" @@ -148,14 +149,14 @@ static inline void s_rotate_n(size_t n) { // ------ functions ------ -// |> param_0 ... param_n | frame[ ret rp prev_fp ¶ms &locals &end +// |> param_0 ... param_n | frame[ ret rp prev_fp ... ¶ms &locals &end // ] // |> local_0 ... local_m |> | ... // // where |> defines corresponding frame pointer, | is stack pointer // location before / after new frame added -static inline void s_enter_f(char *rp, bool is_closure_call, auint args_sz, - auint locals_sz) { +static inline void s_enter_f(char *rp, aint ret_module_id, bool is_closure_call, + auint args_sz, auint locals_sz) { #ifdef DEBUG_VERSION printf("-> %i args sz\n", args_sz); printf("-> %i locals sz\n", locals_sz); @@ -186,6 +187,7 @@ static inline void s_enter_f(char *rp, bool is_closure_call, auint args_sz, .ret = NULL, // field in frame itself .rp = rp, .prev_fp = (void **)s.fp, + .ret_module_box = BOX(ret_module_id), .args_sz_box = BOX(args_sz), .locals_sz_box = BOX(locals_sz), }; @@ -226,6 +228,10 @@ static inline void s_exit_f() { } s.ip = frame.rp; + + s.current_module_id = UNBOX(frame.ret_module_box); + s.bf = mod_get(s.current_module_id); + // TODO: return to ret_module } static inline void print_stack() { diff --git a/byterun/include/types.h b/byterun/include/types.h index 9ef10daf7..43d8b4dd7 100644 --- a/byterun/include/types.h +++ b/byterun/include/types.h @@ -22,13 +22,14 @@ static const size_t MAX_ARRAY_SIZE = 0x11111110; // ------ Frame ------ struct Frame { - void *closure; // where closure value stored if needed - void *ret; // store returned value [gc pointer] - char *rp; // ret instruction pointer [not gc pointer] - void **prev_fp; // ret function frame pointer [boxed value, not gc - // pointer] - aint args_sz_box; // store arguments [boxed value, not gc pointer] - aint locals_sz_box; // store locals [boxed value, not gc pointer] + void *closure; // where closure value stored if needed + void *ret; // store returned value [gc pointer] + char *rp; // ret instruction pointer [not gc pointer] + void **prev_fp; // ret function frame pointer [boxed value, not gc + // pointer] + aint ret_module_box; // module to return [boxed value, not gc pointer] + aint args_sz_box; // store arguments [boxed value, not gc pointer] + aint locals_sz_box; // store locals [boxed value, not gc pointer] }; // NOTE: stack is [top -> bottom] @@ -60,14 +61,20 @@ struct State { bool is_closure_call; + uint current_module_id; + uint call_module_id; + char *ip; // instruction pointer char *instr_ip; // poiter to current instruction char *call_ip; // prev instruction pointer (to remember jmp locations) }; -void construct_state(Bytefile *bf, struct State *s, void **stack); +void init_state(struct State *s, void **stack); +void init_mod_state(uint mod_id, struct State *s); +void init_mod_state_globals(struct State *s); void cleanup_state(struct State *state); +// TODO: print current mod id static inline void s_failure(struct State *s, const char *msg) { exec_failure(read_cmd(s->instr_ip, s->bf), s->current_line, s->instr_ip - s->bf->code_ptr, msg); @@ -154,6 +161,7 @@ enum CMD_CTRLS { CMD_CTRL_ARRAY, CMD_CTRL_FAIL, CMD_CTRL_LINE, + CMD_CTRL_CALLF, }; enum CMD_PATTS { diff --git a/byterun/include/utils.h b/byterun/include/utils.h index 60ee30956..82ab95dd2 100644 --- a/byterun/include/utils.h +++ b/byterun/include/utils.h @@ -10,13 +10,15 @@ /* The unpacked representation of bytecode file */ typedef struct { char *string_ptr; /* A pointer to the beginning of the string table */ + int *imports_ptr; /* A pointer to the beginning of imports table */ int *public_ptr; /* A pointer to the beginning of publics table */ char *code_ptr; /* A pointer to the bytecode itself */ int *global_ptr; /* A pointer to the global area */ int code_size; /* The size (in bytes) of code */ uint stringtab_size; /* The size (in bytes) of the string table */ uint global_area_size; /* The size (in words) of global area */ - uint public_symbols_number; /* The number of public symbols */ + uint imports_number; /* The number of imports */ + uint public_symbols_number; /* The number of public symbols */ char buffer[0]; } Bytefile; @@ -35,6 +37,14 @@ static inline const char *get_string_unsafe(const Bytefile *bf, size_t pos) { return &bf->string_ptr[pos]; } +/* Gets import */ +static inline const char *get_import_unsafe(const Bytefile *f, size_t i) { + if (i >= f->imports_number) { + failure("import pos is out of range: %zu >= %i\n", i, f->imports_number); + } + return get_string_unsafe(f, f->imports_ptr[i]); +} + /* Gets a name offset for a public symbol */ static inline size_t get_public_name_offset_unsafe(const Bytefile *bf, size_t i) { @@ -80,6 +90,14 @@ static inline const char *get_string_safe(const Bytefile *f, size_t pos) { return get_string_unsafe(f, pos); } +/* Gets import */ +static inline const char *get_import_safe(const Bytefile *f, size_t i) { + if (i >= f->imports_number) { + failure("import pos is out of range: %zu >= %i\n", i, f->imports_number); + } + return get_string_safe(f, f->imports_ptr[i]); +} + /* Gets a name offset for a public symbol */ static inline size_t get_public_name_offset_safe(const Bytefile *f, size_t i) { if (i >= f->public_symbols_number) { diff --git a/byterun/src/analyzer.cpp b/byterun/src/analyzer.cpp index a437f62aa..c7fa7d934 100644 --- a/byterun/src/analyzer.cpp +++ b/byterun/src/analyzer.cpp @@ -315,6 +315,9 @@ void analyze(Bytefile *bf) { break; case Cmd::LINE: break; + case Cmd::CALLF: // FIXME TODO + ip_failure(saved_current_ip, bf, "CALLF analysis is not implemented yet"); + break; case Cmd::PATT: --current_stack_depth; if (l == CMD_PATT_STR) { diff --git a/byterun/src/cli.cpp b/byterun/src/cli.cpp index 638562165..cbf80c97f 100644 --- a/byterun/src/cli.cpp +++ b/byterun/src/cli.cpp @@ -6,7 +6,9 @@ extern "C" { #include "../../runtime/runtime.h" #include "interpreter.h" +#include "module_manager.h" #include "parser.h" +#include "types.h" #include "utils.h" } @@ -40,9 +42,6 @@ int main(int argc, char **argv) { } Bytefile *f = read_file(argv[2]); -#ifdef DEBUG_VERSION - dump_file(stdout, f); -#endif if (do_print) { print_file(*f, std::cout); } @@ -50,12 +49,19 @@ int main(int argc, char **argv) { analyze(f); } if (do_interpretation) { - run(f, argc - 2, argv + 2); + // TODO FIXME: add all loaded modules verification + size_t stack[STACK_SIZE]; + run_init(stack); + + uint main_mod_id = mod_add(f); + + run_mod_rec(main_mod_id, argc - 1, argv + 1); } + // TODO: remove, before modules // // NOTE: not used for now // // free(f->global_ptr); - free(f); + // free(f); return 0; } diff --git a/byterun/src/interpreter.c b/byterun/src/interpreter.c index 8008fb3b2..89dfeb8a8 100644 --- a/byterun/src/interpreter.c +++ b/byterun/src/interpreter.c @@ -3,6 +3,7 @@ #include "../../runtime/gc.h" #include "../../runtime/runtime.h" +#include "module_manager.h" #include "runtime_externs.h" #include "stack.h" #include "types.h" @@ -53,17 +54,11 @@ static inline const char *ip_read_string(char **ip) { const size_t BUFFER_SIZE = 1000; -void run(Bytefile *bf, int argc, char **argv) { - size_t stack[STACK_SIZE]; - void *buffer[BUFFER_SIZE]; - construct_state(bf, &s, (void **)stack); +void run_init(size_t *stack) { + init_state(&s, (void**)stack); +} -#ifdef DEBUG_VERSION - printf("--- interpreter run ---\n"); -#endif - - // argc, argv - { +void run_prepare_exec(int argc, char **argv) { s_push_i(BOX(argc)); for (size_t i = 0; i < argc; ++i) { s_push(Bstring((aint *)&argv[argc - i - 1])); @@ -72,21 +67,50 @@ void run(Bytefile *bf, int argc, char **argv) { void *argv_elem = s_pop(); s_popn(argc); s_push(argv_elem); +} + +// TODO: use unsafe, move checks to verifier (?) +void run_mod_rec(uint mod_id, int argc, char **argv) { + Bytefile* mod = mod_get(mod_id); // TODO: pass as param ?? + for (size_t i = 0; i < mod->imports_number; ++i) { + if (find_mod_loaded(get_import_safe(mod, i)) < 0 && strcmp(get_import_safe(mod, i), "Std") != 0) { // not loaded + int32_t import_mod = mod_load(get_import_safe(mod, i)); + if (import_mod < 0) { + failure("module %s not found\n", get_import_safe(mod, i)); + } + run_mod_rec(mod_id, argc, argv); + } } + init_mod_state(mod_id, &s); + init_mod_state_globals(&s); + + run_prepare_exec(argc, argv); // args for module main + run_mod(mod_id, argc, argv); +} + +void run_mod(uint mod_id, int argc, char **argv) { #ifdef DEBUG_VERSION - printf("- loop start\n"); + printf("--- module init state ---\n"); +#endif + + init_mod_state(mod_id, &s); + + void *buffer[BUFFER_SIZE]; + +#ifdef DEBUG_VERSION + printf("--- module run begin ---\n"); #endif do { bool call_happened = false; #ifndef WITH_CHECK - if (s.ip >= bf->code_ptr + bf->code_size) { + if (s.ip >= s.bf->code_ptr + s.bf->code_size) { s_failure(&s, "instruction pointer is out of range (>= size)"); } - if (s.ip < bf->code_ptr) { + if (s.ip < s.bf->code_ptr) { s_failure(&s, "instruction pointer is out of range (< 0)"); } #endif @@ -94,9 +118,9 @@ void run(Bytefile *bf, int argc, char **argv) { s.instr_ip = s.ip; uint8_t x = ip_read_byte(&s.ip), h = (x & 0xF0) >> 4, l = x & 0x0F; -// #ifdef DEBUG_VERSION - printf("0x%.8x: %s\n", s.ip - bf->code_ptr - 1, read_cmd(s.ip - 1, s.bf)); -// #endif +#ifdef DEBUG_VERSION + printf("0x%.8x: %s\n", s.ip - s.bf->code_ptr - 1, read_cmd(s.ip - 1, s.bf)); +#endif switch (h) { case CMD_EXIT: @@ -193,11 +217,11 @@ void run(Bytefile *bf, int argc, char **argv) { uint jmp_p = ip_read_int(&s.ip); #ifndef WITH_CHECK - if (jmp_p >= bf->code_size) { + if (jmp_p >= s.bf->code_size) { s_failure(&s, "jump out of file"); } #endif - s.ip = bf->code_ptr + jmp_p; + s.ip = s.bf->code_ptr + jmp_p; break; } @@ -270,12 +294,12 @@ void run(Bytefile *bf, int argc, char **argv) { uint jmp_p = ip_read_int(&s.ip); #ifndef WITH_CHECK - if (jmp_p >= bf->code_size) { + if (jmp_p >= s.bf->code_size) { s_failure(&s, "jump out of file"); } #endif if (UNBOX(s_pop_i()) == 0) { - s.ip = bf->code_ptr + jmp_p; + s.ip = s.bf->code_ptr + jmp_p; } break; } @@ -284,12 +308,12 @@ void run(Bytefile *bf, int argc, char **argv) { uint jmp_p = ip_read_int(&s.ip); #ifndef WITH_CHECK - if (jmp_p >= bf->code_size) { + if (jmp_p >= s.bf->code_size) { s_failure(&s, "jump out of file"); } #endif if (UNBOX(s_pop_i()) != 0) { - s.ip = bf->code_ptr + jmp_p; + s.ip = s.bf->code_ptr + jmp_p; } break; } @@ -307,8 +331,8 @@ void run(Bytefile *bf, int argc, char **argv) { s_failure(&s, "begin should only be called after call"); } #endif - s_enter_f(s.call_ip /*ip from call*/, s.is_closure_call, args_sz, - locals_sz); + s_enter_f(s.call_ip /*ip from call*/, s.call_module_id, + s.is_closure_call, args_sz, locals_sz); #ifndef WITH_CHECK if ((void **)__gc_stack_top + (aint)max_additional_stack_sz - 1 <= s.stack) { s_failure(&s, "stack owerflow"); @@ -331,8 +355,8 @@ void run(Bytefile *bf, int argc, char **argv) { s_failure(&s, "begin should only be called after call"); } #endif - s_enter_f(s.call_ip /*ip from call*/, s.is_closure_call, args_sz, - locals_sz); + s_enter_f(s.call_ip /*ip from call*/, s.call_module_id, + s.is_closure_call, args_sz, locals_sz); #ifdef WITH_CHECK if ((void **)__gc_stack_top + (aint)max_additional_stack_sz - 1 <= s.stack) { s_failure(&s, "stack owerflow"); @@ -354,11 +378,11 @@ void run(Bytefile *bf, int argc, char **argv) { s_push(*var_ptr); } #ifndef WITH_CHECK - if (call_offset >= bf->code_size) { + if (call_offset >= s.bf->code_size) { s_failure(&s, "jump out of file"); } #endif - s_push(bf->code_ptr + call_offset); + s_push(s.bf->code_ptr + call_offset); void *closure = Bclosure((aint *)__gc_stack_top, BOX(args_count)); // printf("args is %li, count is %li\n", args_count, get_len(TO_DATA(closure))); @@ -374,6 +398,7 @@ void run(Bytefile *bf, int argc, char **argv) { call_happened = true; s.is_closure_call = true; s.call_ip = s.ip; + s.call_module_id = s.current_module_id; s.ip = (char*)Belem(*s_nth(args_count), BOX(0)); // use offset instead ?? break; @@ -386,13 +411,14 @@ void run(Bytefile *bf, int argc, char **argv) { call_happened = true; s.is_closure_call = false; s.call_ip = s.ip; + s.call_module_id = s.current_module_id; #ifndef WITH_CHECK - if (call_p >= bf->code_size) { + if (call_p >= s.bf->code_size) { s_failure(&s, "jump out of file"); } #endif - s.ip = bf->code_ptr + call_p; + s.ip = s.bf->code_ptr + call_p; break; } @@ -425,6 +451,31 @@ void run(Bytefile *bf, int argc, char **argv) { // maybe some metainfo should be collected break; + case CMD_CTRL_CALLF: { // CALLF %s %d // call external function + const char *call_func_name = ip_read_string(&s.ip); + ip_read_int(&s.ip); // args count + + // TODO: jump to other module, save ret module + struct ModSearchResult func = mod_search_pub_symbol(call_func_name); + if (func.mod_file == NULL) { + s_failure(&s, "external function not found"); + } + + call_happened = true; + s.is_closure_call = false; + s.call_ip = s.ip; + s.call_module_id = s.current_module_id; + + s.current_module_id = func.mod_id; + s.bf = func.mod_file; + + if (func.symbol_offset >= s.bf->code_size) { + s_failure(&s, "jump out of file"); + } + s.ip = s.bf->code_ptr + func.symbol_offset; + break; + } + default: s_failure(&s, "invalid opcode"); // %d-%d\n", h, l); } @@ -493,7 +544,7 @@ void run(Bytefile *bf, int argc, char **argv) { // s_rotate_n(elem_count); void *array = Barray((aint *)opr_buffer, - BOX(elem_count)); // NOTE: not shure if elems should be + BOX(elem_count)); // NOTE: not sure if elems should be // added // void *array = Barray((aint *)s_peek(), BOX(elem_count)); @@ -513,6 +564,7 @@ void run(Bytefile *bf, int argc, char **argv) { if (!call_happened) { s.is_closure_call = false; s.call_ip = NULL; + s.call_module_id = 0; } if (s.fp == NULL) { @@ -524,7 +576,8 @@ void run(Bytefile *bf, int argc, char **argv) { } while (1); stop:; #ifdef DEBUG_VERSION - printf("--- run end ---\n"); + printf("--- module run end ---\n"); #endif - cleanup_state(&s); } + +void run_cleanup() { cleanup_state(&s); } diff --git a/byterun/src/module_manager.cpp b/byterun/src/module_manager.cpp new file mode 100644 index 000000000..44004e2e3 --- /dev/null +++ b/byterun/src/module_manager.cpp @@ -0,0 +1,113 @@ +extern "C" { +#include "module_manager.h" +#include "utils.h" +} + +#include "parser.hpp" + +#include +#include +#include +#include +#include + +struct ModSymbolPos { + uint32_t mod_id; + size_t offset; +}; + +struct ModuleManager { + std::unordered_map loaded_modules; + std::unordered_map public_symbols_mods; + std::vector modules; + std::vector search_paths; +}; + +static ModuleManager manager; + +uint32_t mod_add_impl(Bytefile *module, + std::optional name = std::nullopt) { + uint32_t id = manager.modules.size(); + manager.modules.push_back(module); + for (size_t i = 0; i < module->public_symbols_number; ++i) { + if (!manager.public_symbols_mods + .insert({ + get_public_name_safe(module, i), + {.mod_id = id, .offset = get_public_offset_safe(module, i)}, + }) + .second) { + failure("public symbol loaded more then once\n"); + } + } + if (name) { + manager.loaded_modules.insert({*name, id}); + } + return id; +} + +uint32_t path_mod_load(const char *name, std::filesystem::path &&path) { + Bytefile *module = read_file(path.c_str()); + return mod_add_impl(module, name); +} +extern "C" { + +void mod_add_search_path(const char *path) { + manager.search_paths.emplace_back(path); +} + +Bytefile *mod_get(uint32_t id) { + if (id > manager.modules.size()) { + failure("module id is out of range\n"); + } + return manager.modules[id]; +} + +int32_t find_mod_loaded(const char *name) { + auto it = manager.loaded_modules.find(name); + + // module already loaded + if (it != manager.loaded_modules.end()) { + return it->second; + } + + return -1; +} + +int32_t mod_load(const char *name) { + std::string full_name = std::string{name} + ".bc"; + + auto it = manager.loaded_modules.find(name); + + // module already loaded + if (it != manager.loaded_modules.end()) { + return it->second; + } + + if (std::filesystem::exists(full_name)) { + return path_mod_load(name, full_name); + } + for (const auto &dir_path : manager.search_paths) { + auto path = dir_path / full_name; + if (std::filesystem::exists(path)) { + return path_mod_load(name, std::move(path)); + } + } + + return -1; +} + +uint32_t mod_add(Bytefile *module) { return mod_add_impl(module); } + +ModSearchResult mod_search_pub_symbol(const char *name) { + auto it = manager.public_symbols_mods.find(name); + if (it == manager.public_symbols_mods.end()) { + return {.symbol_offset = 0, .mod_id = 0, .mod_file = NULL}; + } + + return { + .symbol_offset = it->second.offset, + .mod_id = it->second.mod_id, + .mod_file = mod_get(it->second.mod_id), + }; +} +} diff --git a/byterun/src/parser.cpp b/byterun/src/parser.cpp index 918747759..f5ed6a425 100644 --- a/byterun/src/parser.cpp +++ b/byterun/src/parser.cpp @@ -52,7 +52,7 @@ Bytefile *read_file(const char *fname) { } long size = ftell(f); - long additional_size = sizeof(void *) * 4 + sizeof(int); + long additional_size = sizeof(void *) * 5 + sizeof(int); file = (Bytefile *)malloc(size + additional_size); // file itself + additional data @@ -71,10 +71,14 @@ Bytefile *read_file(const char *fname) { fclose(f); + long imports_size = file->imports_number * sizeof(int); long public_symbols_size = file->public_symbols_number * 2 * sizeof(int); - if (file->buffer + public_symbols_size >= file_end) { + long strings_buffer_offset = public_symbols_size + imports_size; + if (file->buffer + strings_buffer_offset >= file_end) { failure("public symbols are out of the file size\n"); } + file->string_ptr = + &file->buffer[strings_buffer_offset]; // TODO: check that should be there if (file->string_ptr + file->stringtab_size > file_end) { failure("strings table is out of the file size\n"); } @@ -87,14 +91,13 @@ Bytefile *read_file(const char *fname) { failure("file zones sizes should be >= 0\n"); } - file->string_ptr = &file->buffer[public_symbols_size]; - file->public_ptr = (int *)file->buffer; - file->code_ptr = &file->string_ptr[file->stringtab_size]; - // NOTE: not used for now - // file->global_ptr = (int *)calloc(file->global_area_size, sizeof(int)); - file->global_ptr = nullptr; + file->imports_ptr = (int *)file->buffer; + file->public_ptr = (int *)(file->buffer + imports_size); + // is allocated on module run on stack + file->global_ptr = NULL; + // file->global_ptr = (int*) calloc (file->global_area_size, sizeof (int)); - file->code_size = size - public_symbols_size - file->stringtab_size; + file->code_size = size - strings_buffer_offset - file->stringtab_size; return file; } @@ -202,6 +205,8 @@ const char *command_name(Cmd cmd, int8_t l) { return "FAIL"; case Cmd::LINE: return "LINE"; + case Cmd::CALLF: + return "CALLF"; case Cmd::PATT: if (l >= sizeof(pats) / sizeof(char *)) { return "_UNDEF_PATT_"; @@ -520,6 +525,11 @@ std::pair parse_command_impl(char **ip, const Bytefile &bf, read_print_cmd_seq_opt(cmd, l, ip, bf, out); break; + case CMD_CTRL_CALLF: // CALLF %s %d + cmd = Cmd::CALLF; + read_print_cmd_seq_opt( + cmd, l, ip, bf, out); + break; default: failure("invalid opcode"); @@ -591,12 +601,32 @@ bool is_command_name(char *ip, const Bytefile *bf, Cmd cmd) { return parse_command_name(&ip, bf).first == cmd; } -void print_file(const Bytefile &bf, std::ostream &out) { +void print_file_info(const Bytefile &bf, std::ostream &out) { + out << "String table size : " << bf.stringtab_size << '\n'; + out << "Global area size : " << bf.global_area_size << '\n'; + out << "Number of imports : " << bf.imports_number << '\n'; + out << "Number of public symbols: " << bf.public_symbols_number << '\n'; + out << "Imports :\n"; + + for (size_t i = 0; i < bf.imports_number; i++) { + out << " %s\n" << get_import_safe(&bf, i); + } + + out << "Public symbols :\n"; + + for (size_t i = 0; i < bf.public_symbols_number; i++) { + out << " " << std::setfill('0') << std::setw(8) << std::hex + << get_public_offset_safe(&bf, i) << ": " << std::dec + << get_public_name_safe(&bf, i); + } +} + +void print_file_code(const Bytefile &bf, std::ostream &out) { char *ip = bf.code_ptr; while (true) { - out << std::setfill('0') << std::setw(8) << std::hex << ip - bf.code_ptr - << ": " << std::dec; + out << " " << std::setfill('0') << std::setw(8) << std::hex + << ip - bf.code_ptr << ": " << std::dec; const auto [cmd, l] = parse_command(&ip, &bf, out); out << '\n'; @@ -606,6 +636,14 @@ void print_file(const Bytefile &bf, std::ostream &out) { } } +void print_file(const Bytefile &bf, std::ostream &out) { + print_file_info(bf, out); + + out << "Code:\n"; + + print_file_code(bf, out); +} + extern "C" { const char *read_cmd(char *ip, const Bytefile *bf) { const auto [cmd, l] = parse_command_impl(&ip, *bf, std::clog); diff --git a/byterun/src/types.c b/byterun/src/types.c index f42025240..5fda5817e 100644 --- a/byterun/src/types.c +++ b/byterun/src/types.c @@ -11,12 +11,14 @@ extern size_t __gc_stack_top, __gc_stack_bottom; // --- State --- -static void init_state(Bytefile *bf, struct State* s, void** stack) { +void init_state(struct State* s, void** stack) { s->stack = stack; - s->bf = bf; + s->bf = NULL; s->is_closure_call = false; - s->ip = bf->code_ptr; - s->instr_ip = bf->code_ptr; + s->current_module_id = 0; + s->call_module_id = 0; + s->ip = s->bf->code_ptr; + s->instr_ip = s->bf->code_ptr; s->call_ip = NULL; s->current_line = 0; @@ -24,26 +26,48 @@ static void init_state(Bytefile *bf, struct State* s, void** stack) { s->stack[i] = NULL; } - // printf("%p:%zu - %zu", s->stack, (size_t)s->stack, (size_t)s->stack & 0xF); - - // s->sp = s->stack + STACK_SIZE; // [top -> bottom] stack s->fp = NULL; -} -void construct_state(Bytefile *bf, struct State* s, void** stack) { - __init(); - init_state(bf, s, stack); __gc_stack_bottom = (size_t)(s->stack + STACK_SIZE); __gc_stack_top = __gc_stack_bottom; - s_pushn_nil(bf->global_area_size); - #ifdef DEBUG_VERSION print_stack(s); printf("- state init done\n"); #endif } +void init_mod_state(uint mod_id, struct State* s) { + // init module data + s->bf = mod_get(mod_id); + s->current_module_id = mod_id; + + // clearup from previous executions + + s->is_closure_call = false; + s->current_module_id = 0; + s->call_module_id = 0; + s->call_ip = NULL; + s->current_line = 0; + + s->fp = NULL; + +#ifdef DEBUG_VERSION + print_stack(s); + printf("- mod state init done\n"); +#endif +} + +void init_mod_state_globals(struct State *s) { + s_pushn_nil(s->bf->global_area_size); + s->bf->global_ptr = (void*)__gc_stack_top; + +#ifdef DEBUG_VERSION + print_stack(s); + printf("- state globals init done\n"); +#endif +} + static void destruct_state(struct State* state) { // free(state->stack); diff --git a/src/SM.ml b/src/SM.ml index d43ea9b67..126f7d229 100644 --- a/src/SM.ml +++ b/src/SM.ml @@ -172,15 +172,19 @@ module ByteCode = struct let code = Buffer.create 256 in let st = StringTab.create () in let lmap = Stdlib.ref M.empty in + let externs = Stdlib.ref S.empty in let pubs = Stdlib.ref S.empty in let imports = Stdlib.ref S.empty in let globals = Stdlib.ref M.empty in let glob_count = Stdlib.ref 0 in let fixups = Stdlib.ref [] in + let func_fixups = Stdlib.ref [] in let add_lab l = lmap := M.add l (Buffer.length code) !lmap in + let add_extern l = externs := S.add l !externs in let add_public l = pubs := S.add l !pubs in let add_import l = imports := S.add l !imports in let add_fixup l = fixups := (Buffer.length code, l) :: !fixups in + let add_func_fixup c l = func_fixups := (c, Buffer.length code, l) :: !func_fixups in let add_bytes = List.iter (fun x -> Buffer.add_char code @@ Char.chr x) in let add_ints = List.iter (fun x -> Buffer.add_int32_ne code @@ Int32.of_int x) @@ -302,9 +306,10 @@ module ByteCode = struct add_ints [ n ] (* 0x56 l:32 n:32 *) | CALL (fn, n, _) -> - add_bytes [ (5 * 16) + 6 ]; - add_fixup fn; - add_ints [ 0; n ] + (add_bytes [ (5 * 16) + 6 ]; + (* TODO: 1 -> sizeof byte ?? *) + add_func_fixup (Buffer.length code - 1) fn; + add_ints [ 0; n ]) (* 0x57 s:32 n:32 *) | TAG (s, n) -> add_bytes [ (5 * 16) + 7 ]; @@ -324,9 +329,11 @@ module ByteCode = struct add_ints [ n ] (* 0x6p *) | PATT p -> add_bytes [ (6 * 16) + enum patt p ] - | EXTERN _ -> () + | EXTERN s -> add_extern s + (* TODO: put externs in string table (?), or check that all external funtions are externs *) | PUBLIC s -> add_public s | IMPORT s -> add_import s + (* TODO: add imports table before publics *) | _ -> failwith (Printf.sprintf "Unexpected pattern: %s: %d" __FILE__ __LINE__) @@ -334,6 +341,15 @@ module ByteCode = struct List.iter insn_code insns; add_bytes [ 255 ]; let code = Buffer.to_bytes code in + List.iter + (fun (cmd_ofs, addr_ofs, l) -> + Bytes.set_int32_ne code addr_ofs + (Int32.of_int + @@ + try M.find l !lmap + with Not_found -> + Bytes.set_int8 code cmd_ofs ((5 * 16) + 11); StringTab.add st l)) + !func_fixups; List.iter (fun (ofs, l) -> Bytes.set_int32_ne code ofs @@ -343,6 +359,11 @@ module ByteCode = struct with Not_found -> failwith (Printf.sprintf "ERROR: undefined label '%s'" l))) !fixups; + let imports = (* TODO: check *) + List.map (fun l -> + (Int32.of_int @@ StringTab.add st l)) + @@ S.elements !imports + in let pubs = List.map (fun l -> ( Int32.of_int @@ StringTab.add st l, @@ -357,7 +378,12 @@ module ByteCode = struct let file = Buffer.create 1024 in Buffer.add_int32_ne file (Int32.of_int @@ Bytes.length st); Buffer.add_int32_ne file (Int32.of_int @@ !glob_count); + Buffer.add_int32_ne file (Int32.of_int @@ List.length imports); Buffer.add_int32_ne file (Int32.of_int @@ List.length pubs); + List.iter + (fun (n) -> + Buffer.add_int32_ne file n) + imports; List.iter (fun (n, o) -> Buffer.add_int32_ne file n;