modules: fixes to working condition

This commit is contained in:
ProgramSnail 2025-01-11 23:51:50 +03:00
parent eb1ddfa447
commit 19c99bc7e5
16 changed files with 197 additions and 121 deletions

View file

@ -4,4 +4,4 @@ extern "C" {
#include "utils.h" #include "utils.h"
} }
void analyze(Bytefile *bf); void analyze(uint32_t mod_id);

View file

@ -1,12 +1,13 @@
#pragma once #pragma once
#include "utils.h" #include "utils.h"
#include <stdbool.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_init(size_t *stack);
void run_mod_rec(uint mod_id, int argc, char **argv); void run_mod_rec(uint mod_id, int argc, char **argv, bool do_verification);
void run_prepare_exec(int argc, char **argv); void run_prepare_exec(int argc, char **argv);

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "utils.h" #include "utils.h"
@ -12,12 +13,14 @@ struct ModSearchResult {
void mod_add_search_path(const char *path); void mod_add_search_path(const char *path);
const char *mod_get_name(uint32_t id);
Bytefile *mod_get(uint32_t id); Bytefile *mod_get(uint32_t id);
int32_t find_mod_loaded(const char *name); // < 0 => not found int32_t find_mod_loaded(const char *name); // < 0 => not found
int32_t mod_load(const char *name); // < 0 => not found int32_t mod_load(const char *name, bool do_verification); // < 0 => not found
uint32_t mod_add(Bytefile *module); uint32_t mod_add(Bytefile *module, bool do_verification);
struct ModSearchResult mod_search_pub_symbol(const char *name); struct ModSearchResult mod_search_pub_symbol(const char *name);

View file

@ -162,7 +162,6 @@ static inline void s_enter_f(char *rp, aint ret_module_id, bool is_closure_call,
printf("-> %i locals sz\n", locals_sz); printf("-> %i locals sz\n", locals_sz);
#endif #endif
// TODO: move checks to BEGIN/CBEGIN
// check that params count is valid // check that params count is valid
if ((void **)__gc_stack_top + (aint)args_sz - (is_closure_call ? 0 : 1) >= if ((void **)__gc_stack_top + (aint)args_sz - (is_closure_call ? 0 : 1) >=
s_top()) { s_top()) {
@ -231,12 +230,13 @@ static inline void s_exit_f() {
s.current_module_id = UNBOX(frame.ret_module_box); s.current_module_id = UNBOX(frame.ret_module_box);
s.bf = mod_get(s.current_module_id); s.bf = mod_get(s.current_module_id);
// TODO: return to ret_module
} }
static inline void print_stack() { static inline void print_stack(struct State *state) {
printf("stack (%i) is\n[", s.stack + STACK_SIZE - (void **)__gc_stack_top); printf("stack (%li) is\n[",
for (void **x = s.stack + STACK_SIZE - 1; x >= (void **)__gc_stack_top; --x) { state->stack + STACK_SIZE - (void **)__gc_stack_top);
for (void **x = state->stack + STACK_SIZE - 1; x >= (void **)__gc_stack_top;
--x) {
printf("%li ", (long)UNBOX(*x)); printf("%li ", (long)UNBOX(*x));
} }
printf("]\n"); printf("]\n");

View file

@ -2,6 +2,7 @@
#include "../../runtime/runtime.h" #include "../../runtime/runtime.h"
#include "../../runtime/runtime_common.h" #include "../../runtime/runtime_common.h"
#include "module_manager.h"
#include "parser.h" #include "parser.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@ -74,18 +75,20 @@ void init_mod_state(uint mod_id, struct State *s);
void init_mod_state_globals(struct State *s); void init_mod_state_globals(struct State *s);
void cleanup_state(struct State *state); void cleanup_state(struct State *state);
// TODO: print current mod id
static inline void s_failure(struct State *s, const char *msg) { static inline void s_failure(struct State *s, const char *msg) {
exec_failure(read_cmd(s->instr_ip, s->bf), s->current_line, exec_failure(read_cmd(s->instr_ip, s->bf), mod_get_name(s->current_module_id),
s->instr_ip - s->bf->code_ptr, msg); s->current_line, s->instr_ip - s->bf->code_ptr, msg);
} }
static inline void ip_failure(char *ip, Bytefile *bf, const char *msg) { static inline void ip_failure(char *ip, uint32_t mod_id, const char *msg) {
exec_failure(read_cmd(ip, bf), 0, ip - bf->code_ptr, msg); Bytefile *bf = mod_get(mod_id);
exec_failure(read_cmd(ip, bf), mod_get_name(mod_id), 0, ip - bf->code_ptr,
msg);
} }
static inline void ip_safe_failure(char *ip, Bytefile *bf, const char *msg) { static inline void ip_safe_failure(char *ip, uint32_t mod_id, const char *msg) {
exec_failure("_UNDEF_", 0, ip - bf->code_ptr, msg); Bytefile *bf = mod_get(mod_id);
exec_failure("_UNDEF_", mod_get_name(mod_id), 0, ip - bf->code_ptr, msg);
} }
// ------ VarCategory ------ // ------ VarCategory ------

View file

@ -22,10 +22,10 @@ typedef struct {
char buffer[0]; char buffer[0];
} Bytefile; } Bytefile;
static inline void exec_failure(const char *cmd, int line, aint offset, static inline void exec_failure(const char *cmd, const char *module_name,
const char *msg) { int line, aint offset, const char *msg) {
failure("*** RUNTIME ERROR: %i(0x%.8x):%s error: %s\n", line, offset, cmd, failure("*** RUNTIME ERROR: %s:%i(0x%.8x):%s error: %s\n", module_name, line,
msg); offset, cmd, msg);
} }
// --- unsafe versions // --- unsafe versions

View file

@ -2,19 +2,26 @@
dune build > /dev/null dune build > /dev/null
echo "Interpreter:" compiler=../_build/default/src/Driver.exe
time echo '0' | lamac -i ../performance/Sort.lama > /dev/null
echo "Used compiler path:"
echo $compiler
# echo "Interpreter:"
# time echo '0' | $compiler -i ../performance/Sort.lama
echo "Stack Machine:" echo "Stack Machine:"
time echo '0' | lamac -s ../performance/Sort.lama > /dev/null time echo '0' | $compiler -s ../performance/Sort.lama > /dev/null
$compiler -b ../performance/Sort.lama
lamac -b ../performance/Sort.lama > /dev/null
# ./byterun.exe -p Sort.bc # ./byterun.exe -p Sort.bc
echo "Old Byterun:" # echo "Old Byterun:"
time ./old_byterun.exe -i Sort.bc > /dev/null # time ./old_byterun.exe -i Sort.bc > /dev/null
echo "Code:"
time ./byterun.exe -p Sort.bc > /dev/null
echo "Byterun:" echo "Byterun:"
time ./byterun.exe -vi Sort.bc > /dev/null time ./byterun.exe -vi Sort.bc > /dev/null
@ -27,3 +34,4 @@ time ./byterun.exe -i Sort.bc > /dev/null
rm Sort.* rm Sort.*
rm *.o rm *.o
rm *.a

View file

@ -7,7 +7,7 @@ suffix=".lama"
for test in ../regression/*.lama; do for test in ../regression/*.lama; do
echo $test echo $test
lamac -b $test > /dev/null ../_build/default/src/Driver.exe -b $test > /dev/null
test_file="${test%.*}" test_file="${test%.*}"
echo $test_file echo $test_file
cat $test_file.input | ./byterun.exe -vi test*.bc > /dev/null cat $test_file.input | ./byterun.exe -vi test*.bc > /dev/null

View file

@ -9,7 +9,9 @@ extern "C" {
#include <vector> #include <vector>
void analyze(Bytefile *bf) { void analyze(uint32_t mod_id) {
Bytefile *bf = mod_get(mod_id);
static constexpr const int NOT_VISITED = -1; static constexpr const int NOT_VISITED = -1;
std::vector<int> visited(bf->code_size, NOT_VISITED); // store stack depth std::vector<int> visited(bf->code_size, NOT_VISITED); // store stack depth
@ -28,56 +30,58 @@ void analyze(Bytefile *bf) {
char *current_ip = ip; char *current_ip = ip;
char *saved_current_ip = current_ip; char *saved_current_ip = current_ip;
auto const jmp_to_visit_push = [&saved_current_ip, &bf, &visited, auto const jmp_to_visit_push = [&saved_current_ip, mod_id, &visited,
&current_stack_depth, &current_stack_depth,
&to_visit_jmp](size_t offset) { &to_visit_jmp](size_t offset) {
if (visited[offset] == NOT_VISITED) { if (visited[offset] == NOT_VISITED) {
visited[offset] = current_stack_depth; visited[offset] = current_stack_depth;
to_visit_jmp.push_back(offset); to_visit_jmp.push_back(offset);
} else if (visited[offset] != current_stack_depth) { } else if (visited[offset] != current_stack_depth) {
ip_failure(saved_current_ip, bf, ip_failure(saved_current_ip, mod_id,
"different stack depth on same point is not allowed"); "different stack depth on same point is not allowed");
} }
}; };
auto const func_to_visit_push = [&saved_current_ip, &bf, &visited, auto const func_to_visit_push = [&saved_current_ip, mod_id, &visited,
&current_stack_depth, &current_stack_depth,
&to_visit_func](size_t offset) { &to_visit_func](size_t offset) {
if (visited[offset] == NOT_VISITED) { if (visited[offset] == NOT_VISITED) {
visited[offset] = 0; visited[offset] = 0;
to_visit_func.push_back(offset); to_visit_func.push_back(offset);
} else if (visited[offset] != 0) { } else if (visited[offset] != 0) {
ip_failure(saved_current_ip, bf, ip_failure(saved_current_ip, mod_id,
"different stack depth on same point is not allowed"); "different stack depth on same point is not allowed");
} }
}; };
auto const check_correct_var = [&saved_current_ip, &bf, &globals_count, auto const check_correct_var = [&saved_current_ip, mod_id, &globals_count,
&current_locals_count, &current_args_count, &current_locals_count, &current_args_count,
&is_in_closure](uint8_t l, uint id) { &is_in_closure](uint8_t l, uint id) {
if (l > 3) { if (l > 3) {
ip_failure(saved_current_ip, bf, "unexpected variable category"); ip_failure(saved_current_ip, mod_id, "unexpected variable category");
} }
VarCategory category = to_var_category(l); VarCategory category = to_var_category(l);
switch (category) { switch (category) {
case VAR_GLOBAL: case VAR_GLOBAL:
if (id >= globals_count) { if (id >= globals_count) {
ip_failure(saved_current_ip, bf, "global var index is out of range"); ip_failure(saved_current_ip, mod_id,
"global var index is out of range");
} }
break; break;
case VAR_LOCAL: case VAR_LOCAL:
if (id >= current_locals_count) { if (id >= current_locals_count) {
ip_failure(saved_current_ip, bf, "local var index is out of range"); ip_failure(saved_current_ip, mod_id, "local var index is out of range");
} }
break; break;
case VAR_ARGUMENT: case VAR_ARGUMENT:
if (id >= current_args_count) { if (id >= current_args_count) {
ip_failure(saved_current_ip, bf, "argument var index is out of range"); ip_failure(saved_current_ip, mod_id,
"argument var index is out of range");
} }
break; break;
case VAR_CLOSURE: case VAR_CLOSURE:
if (!is_in_closure) { if (!is_in_closure) {
ip_failure(saved_current_ip, bf, ip_failure(saved_current_ip, mod_id,
"can't access closure vars outside of closure"); "can't access closure vars outside of closure");
} }
// NOTE: impossible to properly check bounds there // NOTE: impossible to properly check bounds there
@ -118,11 +122,12 @@ void analyze(Bytefile *bf) {
} }
if (ip >= bf->code_ptr + bf->code_size) { if (ip >= bf->code_ptr + bf->code_size) {
ip_safe_failure(ip, bf, "instruction pointer is out of range (>= size)"); ip_safe_failure(ip, mod_id,
"instruction pointer is out of range (>= size)");
} }
if (ip < bf->code_ptr) { if (ip < bf->code_ptr) {
ip_safe_failure(ip, bf, "instruction pointer is out of range (< 0)"); ip_safe_failure(ip, mod_id, "instruction pointer is out of range (< 0)");
} }
current_ip = ip; current_ip = ip;
@ -136,11 +141,12 @@ void analyze(Bytefile *bf) {
if (current_begin_counter == nullptr && cmd != Cmd::BEGIN && if (current_begin_counter == nullptr && cmd != Cmd::BEGIN &&
cmd != Cmd::CBEGIN) { cmd != Cmd::CBEGIN) {
ip_failure(saved_current_ip, bf, "function does not start with begin"); ip_failure(saved_current_ip, mod_id,
"function does not start with begin");
} }
if (visited[current_ip - bf->code_ptr] == NOT_VISITED) { if (visited[current_ip - bf->code_ptr] == NOT_VISITED) {
ip_failure(saved_current_ip, bf, "not visited command"); ip_failure(saved_current_ip, mod_id, "not visited command");
} }
current_stack_depth = visited[current_ip - bf->code_ptr]; current_stack_depth = visited[current_ip - bf->code_ptr];
@ -156,7 +162,7 @@ void analyze(Bytefile *bf) {
case Cmd::BINOP: case Cmd::BINOP:
current_stack_depth -= 2; current_stack_depth -= 2;
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
break; break;
@ -170,21 +176,21 @@ void analyze(Bytefile *bf) {
ip_read_string_unsafe(&current_ip, bf); ip_read_string_unsafe(&current_ip, bf);
current_stack_depth -= ip_read_int_unsafe(&current_ip); current_stack_depth -= ip_read_int_unsafe(&current_ip);
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
break; break;
case Cmd::STI: case Cmd::STI:
current_stack_depth -= 2; current_stack_depth -= 2;
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
break; break;
case Cmd::STA: case Cmd::STA:
current_stack_depth -= 3; current_stack_depth -= 3;
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
break; break;
@ -202,19 +208,19 @@ void analyze(Bytefile *bf) {
break; break;
case Cmd::DUP: case Cmd::DUP:
if (current_stack_depth < 1) { if (current_stack_depth < 1) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
break; break;
case Cmd::SWAP: case Cmd::SWAP:
if (current_stack_depth < 2) { if (current_stack_depth < 2) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
} }
break; break;
case Cmd::ELEM: case Cmd::ELEM:
current_stack_depth -= 2; current_stack_depth -= 2;
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
break; break;
@ -229,7 +235,7 @@ void analyze(Bytefile *bf) {
case Cmd::ST: case Cmd::ST:
check_correct_var(l, ip_read_int_unsafe(&current_ip)); check_correct_var(l, ip_read_int_unsafe(&current_ip));
if (current_stack_depth < 1) { if (current_stack_depth < 1) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
} }
break; break;
case Cmd::CJMPz: case Cmd::CJMPz:
@ -239,13 +245,13 @@ void analyze(Bytefile *bf) {
case Cmd::BEGIN: case Cmd::BEGIN:
case Cmd::CBEGIN: case Cmd::CBEGIN:
if (current_begin_counter != nullptr) { if (current_begin_counter != nullptr) {
ip_failure(saved_current_ip, bf, "unexpected function beginning"); ip_failure(saved_current_ip, mod_id, "unexpected function beginning");
} }
current_args_count = ip_read_int_unsafe(&current_ip); current_args_count = ip_read_int_unsafe(&current_ip);
current_begin_counter = (uint16_t *)(current_ip + sizeof(uint16_t)); current_begin_counter = (uint16_t *)(current_ip + sizeof(uint16_t));
current_locals_count = ip_read_int_unsafe(&current_ip); current_locals_count = ip_read_int_unsafe(&current_ip);
if (current_locals_count >= std::numeric_limits<uint16_t>::max()) { if (current_locals_count >= std::numeric_limits<uint16_t>::max()) {
ip_failure(saved_current_ip, bf, "too many locals in functions"); ip_failure(saved_current_ip, mod_id, "too many locals in functions");
} }
(*(uint16_t *)(current_ip - sizeof(uint16_t))) = current_locals_count; (*(uint16_t *)(current_ip - sizeof(uint16_t))) = current_locals_count;
*current_begin_counter = 0; *current_begin_counter = 0;
@ -263,19 +269,20 @@ void analyze(Bytefile *bf) {
++current_stack_depth; ++current_stack_depth;
// if (closure_offset >= bf->code_size) { // if (closure_offset >= bf->code_size) {
// ip_failure(saved_current_ip, bf, "jump/call out of file"); // ip_failure(saved_current_ip, mod_id, "jump/call out of file");
// } // }
// NOTE: is not always true // NOTE: is not always true
// if (!is_command_name(bf->code_ptr + closure_offset, bf, Cmd::CBEGIN)) { // if (!is_command_name(bf->code_ptr + closure_offset, bf, Cmd::CBEGIN)) {
// ip_failure(saved_current_ip, bf, "closure should point to cbegin"); // ip_failure(saved_current_ip, mod_id, "closure should point to
// cbegin");
// } // }
} break; } break;
case Cmd::CALLC: { case Cmd::CALLC: {
uint args_count = ip_read_int_unsafe(&current_ip); uint args_count = ip_read_int_unsafe(&current_ip);
current_stack_depth -= args_count + 1; // + closure itself current_stack_depth -= args_count + 1; // + closure itself
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
// NOTE: can't check args == cbegin args // NOTE: can't check args == cbegin args
@ -285,29 +292,29 @@ void analyze(Bytefile *bf) {
uint args_count = ip_read_int_unsafe(&current_ip); uint args_count = ip_read_int_unsafe(&current_ip);
current_stack_depth -= args_count; current_stack_depth -= args_count;
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
if (call_offset >= bf->code_size) { if (call_offset >= bf->code_size) {
ip_failure(saved_current_ip, bf, "jump/call out of file"); ip_failure(saved_current_ip, mod_id, "jump/call out of file");
} }
if (!is_command_name(bf->code_ptr + call_offset, bf, Cmd::BEGIN)) { if (!is_command_name(bf->code_ptr + call_offset, bf, Cmd::BEGIN)) {
ip_failure(saved_current_ip, bf, "call should point to begin"); ip_failure(saved_current_ip, mod_id, "call should point to begin");
} }
if (args_count != *(uint *)(bf->code_ptr + call_offset + 1)) { if (args_count != *(uint *)(bf->code_ptr + call_offset + 1)) {
ip_failure(saved_current_ip, bf, "wrong call argument count"); ip_failure(saved_current_ip, mod_id, "wrong call argument count");
} }
} break; } break;
case Cmd::TAG: case Cmd::TAG:
if (current_stack_depth < 1) { if (current_stack_depth < 1) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
} }
break; break;
case Cmd::ARRAY: case Cmd::ARRAY:
if (current_stack_depth < 1) { if (current_stack_depth < 1) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
} }
break; break;
case Cmd::FAIL: case Cmd::FAIL:
@ -315,16 +322,25 @@ void analyze(Bytefile *bf) {
break; break;
case Cmd::LINE: case Cmd::LINE:
break; break;
case Cmd::CALLF: // FIXME TODO case Cmd::CALLF: {
ip_failure(saved_current_ip, bf, "CALLF analysis is not implemented yet"); // TODO: find link to real function and replace call (need to save all
break; // modules in one space)
ip_read_int_unsafe(&current_ip); // function name (str)
uint args_count = ip_read_int_unsafe(&current_ip);
current_stack_depth -= args_count;
if (current_stack_depth < 0) {
ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
}
++current_stack_depth;
} break;
case Cmd::PATT: case Cmd::PATT:
--current_stack_depth; --current_stack_depth;
if (l == CMD_PATT_STR) { if (l == CMD_PATT_STR) {
--current_stack_depth; --current_stack_depth;
} }
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
break; break;
@ -335,31 +351,32 @@ void analyze(Bytefile *bf) {
case Cmd::Llength: case Cmd::Llength:
case Cmd::Lstring: case Cmd::Lstring:
if (current_stack_depth < 1) { if (current_stack_depth < 1) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
} }
break; break;
case Cmd::Barray: case Cmd::Barray:
current_stack_depth -= ip_read_int_unsafe(&current_ip); // elem count current_stack_depth -= ip_read_int_unsafe(&current_ip); // elem count
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
break; break;
case Cmd::EXIT: case Cmd::EXIT:
ip_failure(saved_current_ip, bf, ip_failure(saved_current_ip, mod_id,
"exit should be unreachable"); // NOTE: not sure "exit should be unreachable"); // NOTE: not sure
break; break;
case Cmd::_UNDEF_: case Cmd::_UNDEF_:
ip_failure(saved_current_ip, bf, "undefined command"); ip_failure(saved_current_ip, mod_id, "undefined command");
break; break;
} }
if (current_begin_counter == nullptr) { if (current_begin_counter == nullptr) {
ip_failure(saved_current_ip, bf, "function does not start with begin"); ip_failure(saved_current_ip, mod_id,
"function does not start with begin");
} }
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
} }
*current_begin_counter = *current_begin_counter =
@ -386,7 +403,7 @@ void analyze(Bytefile *bf) {
uint jmp_p = ip_read_int_unsafe(&current_ip); uint jmp_p = ip_read_int_unsafe(&current_ip);
if (jmp_p >= bf->code_size) { if (jmp_p >= bf->code_size) {
// NOTE: maybe also should check that > begin (?) // NOTE: maybe also should check that > begin (?)
ip_failure(saved_current_ip, bf, "jump/call out of file"); ip_failure(saved_current_ip, mod_id, "jump/call out of file");
} }
if (is_call) { if (is_call) {
func_to_visit_push(jmp_p); func_to_visit_push(jmp_p);
@ -397,7 +414,7 @@ void analyze(Bytefile *bf) {
} }
case Cmd::_UNDEF_: case Cmd::_UNDEF_:
ip_failure(saved_current_ip, bf, "undefined command"); ip_failure(saved_current_ip, mod_id, "undefined command");
break; break;
default: default:

View file

@ -41,27 +41,40 @@ int main(int argc, char **argv) {
failure("no file name provided"); failure("no file name provided");
} }
#ifdef DEBUG_VERSION
std::cerr << "- read code file" << std::endl;
#endif
Bytefile *f = read_file(argv[2]); Bytefile *f = read_file(argv[2]);
if (do_print) { if (do_print) {
#ifdef DEBUG_VERSION
std::cerr << "- print code file" << std::endl;
#endif
print_file(*f, std::cout); print_file(*f, std::cout);
} }
if (do_verification) { if (do_verification || do_interpretation) {
analyze(f); #ifdef DEBUG_VERSION
} std::cerr << "- init stack" << std::endl;
if (do_interpretation) { #endif
// TODO FIXME: add all loaded modules verification
size_t stack[STACK_SIZE]; size_t stack[STACK_SIZE];
run_init(stack); run_init(stack);
uint main_mod_id = mod_add(f); #ifdef DEBUG_VERSION
std::cerr << "- add main module" << std::endl;
#endif
run_mod_rec(main_mod_id, argc - 1, argv + 1); uint main_mod_id = mod_add(f, do_verification);
if (do_interpretation) {
#ifdef DEBUG_VERSION
std::cerr << "- start interpretation" << std::endl;
#endif
run_mod_rec(main_mod_id, argc - 2, argv + 2, do_verification);
}
} }
// TODO: remove, before modules
// // NOTE: not used for now
// // free(f->global_ptr);
// free(f);
return 0; return 0;
} }

1
byterun/src/compiler.cpp Normal file
View file

@ -0,0 +1 @@

View file

@ -60,25 +60,35 @@ void run_init(size_t *stack) {
void run_prepare_exec(int argc, char **argv) { void run_prepare_exec(int argc, char **argv) {
s_push_i(BOX(argc)); s_push_i(BOX(argc));
#ifdef DEBUG_VERSION
printf("- argc: %i\n", argc);
#endif
for (size_t i = 0; i < argc; ++i) { for (size_t i = 0; i < argc; ++i) {
#ifdef DEBUG_VERSION
printf("- arg: %s\n", argv[argc - i - 1]);
#endif
s_push(Bstring((aint *)&argv[argc - i - 1])); s_push(Bstring((aint *)&argv[argc - i - 1]));
} }
s_push(Barray((aint *)s_peek(), argc)); s_push(Barray((aint *)s_peek(), argc));
void *argv_elem = s_pop(); void *argv_elem = s_pop();
s_popn(argc); s_popn(argc);
s_push(argv_elem); s_push(argv_elem);
#ifdef DEBUG_VERSION
print_stack(s);
printf("- state init done\n");
#endif
} }
// TODO: use unsafe, move checks to verifier (?) void run_mod_rec(uint mod_id, int argc, char **argv, bool do_verification) {
void run_mod_rec(uint mod_id, int argc, char **argv) { Bytefile* mod = mod_get(mod_id);
Bytefile* mod = mod_get(mod_id); // TODO: pass as param ??
for (size_t i = 0; i < mod->imports_number; ++i) { 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 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)); int32_t import_mod = mod_load(get_import_safe(mod, i), do_verification);
if (import_mod < 0) { if (import_mod < 0) {
failure("module %s not found\n", get_import_safe(mod, i)); failure("module %s not found\n", get_import_safe(mod, i));
} }
run_mod_rec(mod_id, argc, argv); run_mod_rec(mod_id, argc, argv, do_verification);
} }
} }
@ -455,7 +465,6 @@ void run_mod(uint mod_id, int argc, char **argv) {
const char *call_func_name = ip_read_string(&s.ip); const char *call_func_name = ip_read_string(&s.ip);
ip_read_int(&s.ip); // args count 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); struct ModSearchResult func = mod_search_pub_symbol(call_func_name);
if (func.mod_file == NULL) { if (func.mod_file == NULL) {
s_failure(&s, "external function not found"); s_failure(&s, "external function not found");

View file

@ -3,6 +3,7 @@ extern "C" {
#include "utils.h" #include "utils.h"
} }
#include "analyzer.hpp"
#include "parser.hpp" #include "parser.hpp"
#include <filesystem> #include <filesystem>
@ -16,24 +17,29 @@ struct ModSymbolPos {
size_t offset; size_t offset;
}; };
struct Module {
std::string name;
Bytefile *bf;
};
struct ModuleManager { struct ModuleManager {
std::unordered_map<std::string, uint32_t> loaded_modules; std::unordered_map<std::string, uint32_t> loaded_modules;
std::unordered_map<std::string, ModSymbolPos> public_symbols_mods; std::unordered_map<std::string, ModSymbolPos> public_symbols_mods;
std::vector<Bytefile *> modules; std::vector<Module> modules;
std::vector<std::filesystem::path> search_paths; std::vector<std::filesystem::path> search_paths;
}; };
static ModuleManager manager; static ModuleManager manager;
uint32_t mod_add_impl(Bytefile *module, uint32_t mod_add_impl(Bytefile *bf, bool do_verification,
std::optional<const char *> name = std::nullopt) { std::optional<const char *> name = std::nullopt) {
uint32_t id = manager.modules.size(); uint32_t id = manager.modules.size();
manager.modules.push_back(module); manager.modules.push_back({.name = name ? *name : "", .bf = bf});
for (size_t i = 0; i < module->public_symbols_number; ++i) { for (size_t i = 0; i < bf->public_symbols_number; ++i) {
if (!manager.public_symbols_mods if (!manager.public_symbols_mods
.insert({ .insert({
get_public_name_safe(module, i), get_public_name_safe(bf, i),
{.mod_id = id, .offset = get_public_offset_safe(module, i)}, {.mod_id = id, .offset = get_public_offset_safe(bf, i)},
}) })
.second) { .second) {
failure("public symbol loaded more then once\n"); failure("public symbol loaded more then once\n");
@ -42,10 +48,14 @@ uint32_t mod_add_impl(Bytefile *module,
if (name) { if (name) {
manager.loaded_modules.insert({*name, id}); manager.loaded_modules.insert({*name, id});
} }
if (do_verification) {
analyze(id);
}
return id; return id;
} }
uint32_t path_mod_load(const char *name, std::filesystem::path &&path) { uint32_t path_mod_load(const char *name, std::filesystem::path &&path,
bool do_verification) {
Bytefile *module = read_file(path.c_str()); Bytefile *module = read_file(path.c_str());
return mod_add_impl(module, name); return mod_add_impl(module, name);
} }
@ -55,11 +65,18 @@ void mod_add_search_path(const char *path) {
manager.search_paths.emplace_back(path); manager.search_paths.emplace_back(path);
} }
const char *mod_get_name(uint32_t id) {
if (id > manager.modules.size()) {
failure("module id is out of range\n");
}
return manager.modules[id].name.c_str();
}
Bytefile *mod_get(uint32_t id) { Bytefile *mod_get(uint32_t id) {
if (id > manager.modules.size()) { if (id > manager.modules.size()) {
failure("module id is out of range\n"); failure("module id is out of range\n");
} }
return manager.modules[id]; return manager.modules[id].bf;
} }
int32_t find_mod_loaded(const char *name) { int32_t find_mod_loaded(const char *name) {
@ -73,7 +90,7 @@ int32_t find_mod_loaded(const char *name) {
return -1; return -1;
} }
int32_t mod_load(const char *name) { int32_t mod_load(const char *name, bool do_verification) {
std::string full_name = std::string{name} + ".bc"; std::string full_name = std::string{name} + ".bc";
auto it = manager.loaded_modules.find(name); auto it = manager.loaded_modules.find(name);
@ -84,19 +101,21 @@ int32_t mod_load(const char *name) {
} }
if (std::filesystem::exists(full_name)) { if (std::filesystem::exists(full_name)) {
return path_mod_load(name, full_name); return path_mod_load(name, full_name, do_verification);
} }
for (const auto &dir_path : manager.search_paths) { for (const auto &dir_path : manager.search_paths) {
auto path = dir_path / full_name; auto path = dir_path / full_name;
if (std::filesystem::exists(path)) { if (std::filesystem::exists(path)) {
return path_mod_load(name, std::move(path)); return path_mod_load(name, std::move(path), do_verification);
} }
} }
return -1; return -1;
} }
uint32_t mod_add(Bytefile *module) { return mod_add_impl(module); } uint32_t mod_add(Bytefile *module, bool do_verification) {
return mod_add_impl(module, do_verification);
}
ModSearchResult mod_search_pub_symbol(const char *name) { ModSearchResult mod_search_pub_symbol(const char *name) {
auto it = manager.public_symbols_mods.find(name); auto it = manager.public_symbols_mods.find(name);

View file

@ -77,8 +77,7 @@ Bytefile *read_file(const char *fname) {
if (file->buffer + strings_buffer_offset >= file_end) { if (file->buffer + strings_buffer_offset >= file_end) {
failure("public symbols are out of the file size\n"); failure("public symbols are out of the file size\n");
} }
file->string_ptr = file->string_ptr = file->buffer + strings_buffer_offset;
&file->buffer[strings_buffer_offset]; // TODO: check that should be there
if (file->string_ptr + file->stringtab_size > file_end) { if (file->string_ptr + file->stringtab_size > file_end) {
failure("strings table is out of the file size\n"); failure("strings table is out of the file size\n");
} }
@ -86,6 +85,8 @@ Bytefile *read_file(const char *fname) {
// file->string_ptr[file->stringtab_size - 1] != 0) { // file->string_ptr[file->stringtab_size - 1] != 0) {
// failure("strings table is not zero-ended\n"); // failure("strings table is not zero-ended\n");
// } // }
file->code_size = size - strings_buffer_offset - file->stringtab_size;
if (file->code_size < 0 || public_symbols_size < 0 || if (file->code_size < 0 || public_symbols_size < 0 ||
file->stringtab_size < 0) { file->stringtab_size < 0) {
failure("file zones sizes should be >= 0\n"); failure("file zones sizes should be >= 0\n");
@ -93,12 +94,10 @@ Bytefile *read_file(const char *fname) {
file->imports_ptr = (int *)file->buffer; file->imports_ptr = (int *)file->buffer;
file->public_ptr = (int *)(file->buffer + imports_size); file->public_ptr = (int *)(file->buffer + imports_size);
// is allocated on module run on stack file->global_ptr = NULL; // is allocated on module run on stack
file->global_ptr = NULL; file->code_ptr = file->string_ptr + file->stringtab_size;
// file->global_ptr = (int*) calloc (file->global_area_size, sizeof (int)); // file->global_ptr = (int*) calloc (file->global_area_size, sizeof (int));
file->code_size = size - strings_buffer_offset - file->stringtab_size;
return file; return file;
} }
@ -606,18 +605,17 @@ void print_file_info(const Bytefile &bf, std::ostream &out) {
out << "Global area size : " << bf.global_area_size << '\n'; out << "Global area size : " << bf.global_area_size << '\n';
out << "Number of imports : " << bf.imports_number << '\n'; out << "Number of imports : " << bf.imports_number << '\n';
out << "Number of public symbols: " << bf.public_symbols_number << '\n'; out << "Number of public symbols: " << bf.public_symbols_number << '\n';
out << "Imports :\n";
out << "Imports :\n";
for (size_t i = 0; i < bf.imports_number; i++) { for (size_t i = 0; i < bf.imports_number; i++) {
out << " %s\n" << get_import_safe(&bf, i); out << " " << get_import_safe(&bf, i) << '\n';
} }
out << "Public symbols :\n"; out << "Public symbols :\n";
for (size_t i = 0; i < bf.public_symbols_number; i++) { for (size_t i = 0; i < bf.public_symbols_number; i++) {
out << " " << std::setfill('0') << std::setw(8) << std::hex out << " " << std::setfill('0') << std::setw(8) << std::hex
<< get_public_offset_safe(&bf, i) << ": " << std::dec << get_public_offset_safe(&bf, i) << ": " << std::dec
<< get_public_name_safe(&bf, i); << get_public_name_safe(&bf, i) << '\n';
} }
} }
@ -628,7 +626,7 @@ void print_file_code(const Bytefile &bf, std::ostream &out) {
out << " " << std::setfill('0') << std::setw(8) << std::hex out << " " << std::setfill('0') << std::setw(8) << std::hex
<< ip - bf.code_ptr << ": " << std::dec; << ip - bf.code_ptr << ": " << std::dec;
const auto [cmd, l] = parse_command(&ip, &bf, out); const auto [cmd, l] = parse_command(&ip, &bf, out);
out << '\n'; out << std::endl;
if (cmd == Cmd::EXIT) { if (cmd == Cmd::EXIT) {
break; break;
@ -640,8 +638,8 @@ void print_file(const Bytefile &bf, std::ostream &out) {
print_file_info(bf, out); print_file_info(bf, out);
out << "Code:\n"; out << "Code:\n";
print_file_code(bf, out); print_file_code(bf, out);
out << "code end\n";
} }
extern "C" { extern "C" {

View file

@ -12,13 +12,15 @@ extern size_t __gc_stack_top, __gc_stack_bottom;
// --- State --- // --- State ---
void init_state(struct State* s, void** stack) { void init_state(struct State* s, void** stack) {
__init();
s->stack = stack; s->stack = stack;
s->bf = NULL; s->bf = NULL;
s->is_closure_call = false; s->is_closure_call = false;
s->current_module_id = 0; s->current_module_id = 0;
s->call_module_id = 0; s->call_module_id = 0;
s->ip = s->bf->code_ptr; s->ip = NULL; //s->bf->code_ptr;
s->instr_ip = s->bf->code_ptr; s->instr_ip = NULL; //s->bf->code_ptr;
s->call_ip = NULL; s->call_ip = NULL;
s->current_line = 0; s->current_line = 0;
@ -52,6 +54,9 @@ void init_mod_state(uint mod_id, struct State* s) {
s->fp = NULL; s->fp = NULL;
s->ip = s->bf->code_ptr;
s->instr_ip = s->bf->code_ptr;
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
print_stack(s); print_stack(s);
printf("- mod state init done\n"); printf("- mod state init done\n");

View file

@ -307,7 +307,7 @@ module ByteCode = struct
(* 0x56 l:32 n:32 *) (* 0x56 l:32 n:32 *)
| CALL (fn, n, _) -> | CALL (fn, n, _) ->
(add_bytes [ (5 * 16) + 6 ]; (add_bytes [ (5 * 16) + 6 ];
(* TODO: 1 -> sizeof byte ?? *) (* 1 = sizeof byte *)
add_func_fixup (Buffer.length code - 1) fn; add_func_fixup (Buffer.length code - 1) fn;
add_ints [ 0; n ]) add_ints [ 0; n ])
(* 0x57 s:32 n:32 *) (* 0x57 s:32 n:32 *)
@ -333,7 +333,6 @@ module ByteCode = struct
(* TODO: put externs in string table (?), or check that all external funtions are externs *) (* TODO: put externs in string table (?), or check that all external funtions are externs *)
| PUBLIC s -> add_public s | PUBLIC s -> add_public s
| IMPORT s -> add_import s | IMPORT s -> add_import s
(* TODO: add imports table before publics *)
| _ -> | _ ->
failwith failwith
(Printf.sprintf "Unexpected pattern: %s: %d" __FILE__ __LINE__) (Printf.sprintf "Unexpected pattern: %s: %d" __FILE__ __LINE__)
@ -359,7 +358,7 @@ module ByteCode = struct
with Not_found -> with Not_found ->
failwith (Printf.sprintf "ERROR: undefined label '%s'" l))) failwith (Printf.sprintf "ERROR: undefined label '%s'" l)))
!fixups; !fixups;
let imports = (* TODO: check *) let imports =
List.map (fun l -> List.map (fun l ->
(Int32.of_int @@ StringTab.add st l)) (Int32.of_int @@ StringTab.add st l))
@@ S.elements !imports @@ S.elements !imports