diff --git a/byterun/dune b/byterun/dune index c3f6eae02..27fd457f0 100644 --- a/byterun/dune +++ b/byterun/dune @@ -9,6 +9,20 @@ (: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_parser.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}))) @@ -21,7 +35,7 @@ (mode (promote (until-clean))) (action - (run gcc -Iinclude/ -c %{src} -o %{target}))) + (run gcc -Iinclude/ -DWITH_CHECK -c %{src} -o %{target}))) (rule (target parser.o) @@ -32,10 +46,43 @@ (mode (promote (until-clean))) (action - (run gcc -Iinclude/ -c %{src} -o %{target}))) + (run gcc -Iinclude/ -DWITH_CHECK -c %{src} -o %{target}))) (rule (target interpreter.o) + (deps + (:include (source_tree include)) + (:src src/interpreter.c) + (:runtime ../runtime/runtime.a)) + (mode + (promote (until-clean))) + (action + (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_parser.o) + (deps + (:include (source_tree include)) + (:src src/parser.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) diff --git a/byterun/include/parser.hpp b/byterun/include/parser.hpp index f8288ef07..db1c7d7d2 100644 --- a/byterun/include/parser.hpp +++ b/byterun/include/parser.hpp @@ -70,3 +70,5 @@ static inline const char *ip_read_string(char **ip, const Bytefile &bf) { std::pair parse_command(char **ip, const Bytefile &bf); std::pair parse_command(char **ip, const Bytefile &bf, std::ostream &out); + +void print_file(const Bytefile &bf, std::ostream &out); diff --git a/byterun/include/stack.h b/byterun/include/stack.h index b7f616683..e865a6d16 100644 --- a/byterun/include/stack.h +++ b/byterun/include/stack.h @@ -24,23 +24,27 @@ static inline bool s_is_empty() { } static inline void **s_nth(size_t n) { +#ifndef WITH_CHECK if ((void **)__gc_stack_top + n >= s_top()) { s_failure(&s, "not enough elements in stack"); } if (s.fp != NULL && (void **)__gc_stack_top + n >= f_locals(s.fp)) { s_failure(&s, "not enough elements in function stack"); } +#endif return (void **)__gc_stack_top + n; } static inline void **s_peek() { +#ifndef WITH_CHECK if ((void **)__gc_stack_top == s_top()) { s_failure(&s, "empty stack"); } if (s.fp != NULL && (void **)__gc_stack_top == f_locals(s.fp)) { s_failure(&s, "empty function stack"); } +#endif return (void **)__gc_stack_top; } @@ -48,9 +52,11 @@ static inline void **s_peek() { static inline aint *s_peek_i() { return (aint *)s_peek(); } static inline void s_push(void *val) { +#ifndef WITH_CHECK if ((void **)__gc_stack_top == s.stack) { s_failure(&s, "stack overflow"); } +#endif #ifdef DEBUG_VERSION printf("--> push\n"); #endif @@ -63,9 +69,11 @@ static inline void s_push_i(aint val) { s_push((void *)val); } static inline void s_push_nil() { s_push(NULL); } static inline void s_pushn_nil(size_t n) { +#ifndef WITH_CHECK if ((void **)__gc_stack_top + (aint)n - 1 <= s.stack) { s_failure(&s, "stack overflow"); } +#endif for (size_t i = 0; i < n; ++i) { __gc_stack_top -= sizeof(void *); *(void **)__gc_stack_top = NULL; @@ -73,12 +81,14 @@ static inline void s_pushn_nil(size_t n) { } static inline void *s_pop() { +#ifndef WITH_CHECK if ((void **)__gc_stack_top == s_top()) { s_failure(&s, "empty stack"); } if (s.fp != NULL && (void **)__gc_stack_top == f_locals(s.fp)) { s_failure(&s, "empty function stack"); } +#endif #ifdef DEBUG_VERSION printf("--> pop\n"); #endif @@ -102,12 +112,14 @@ static inline void s_popn(size_t n) { // behaviour static inline void s_put_nth(size_t n, void *val) { s_push_nil(); +#ifndef WITH_CHECK if ((void **)__gc_stack_top + n >= s_top()) { s_failure(&s, "not enough elements in stack"); } if (s.fp != NULL && (void **)__gc_stack_top + n >= f_locals(s.fp)) { s_failure(&s, "not enough elements in function stack"); } +#endif for (size_t i = 0; i < n; ++i) { ((void **)__gc_stack_top)[i] = ((void **)__gc_stack_top)[i + 1]; @@ -117,12 +129,14 @@ static inline void s_put_nth(size_t n, void *val) { static inline void s_rotate_n(size_t n) { s_push_nil(); +#ifndef WITH_CHECK if ((void **)__gc_stack_top + (aint)n - 1 >= s_top()) { s_failure(&s, "not enough elements in stack"); } if (s.fp != NULL && (void **)__gc_stack_top + (aint)n - 1 >= f_locals(s.fp)) { s_failure(&s, "not enough elements in function stack"); } +#endif void *buf = NULL; for (size_t i = 0; 2 * i < n; ++i) { @@ -147,6 +161,7 @@ static inline void s_enter_f(char *rp, bool is_closure_call, auint args_sz, printf("-> %i locals sz\n", locals_sz); #endif + // TODO: move checks to BEGIN/CBEGIN // check that params count is valid if ((void **)__gc_stack_top + (aint)args_sz - (is_closure_call ? 0 : 1) >= s_top()) { @@ -223,14 +238,17 @@ static inline void **var_by_category(enum VarCategory category, size_t id) { void **var = NULL; switch (category) { case VAR_GLOBAL: +#ifndef WITH_CHECK if (s.bf->global_area_size <= id) { s_failure(&s, "can't read global: too big id"); //, %i >= %ul", id, // s.bf->global_area_size); } +#endif var = s.stack + STACK_SIZE - 1 - id; break; case VAR_LOCAL: +#ifndef WITH_CHECK if (s.fp == NULL) { s_failure(&s, "can't read local outside of function"); } @@ -238,12 +256,14 @@ static inline void **var_by_category(enum VarCategory category, size_t id) { s_failure(&s, "can't read local: too big id"); //, %i >= %ul", id, // f_locals_sz(s.fp)); } +#endif // printf("id is %i, local is %i, %i\n", id, // UNBOX((auint)*((void**)f_locals(s.fp) + id)), f_locals(s.fp) - (void // **)__gc_stack_top); var = f_locals(s.fp) + (f_locals_sz(s.fp) - id - 1); break; case VAR_ARGUMENT: +#ifndef WITH_CHECK if (s.fp == NULL) { s_failure(&s, "can't read argument outside of function"); } @@ -251,9 +271,10 @@ static inline void **var_by_category(enum VarCategory category, size_t id) { s_failure(&s, "can't read arguments: too big id"); //, %i >= %ul", id, // f_args_sz(s.fp)); } +#endif var = f_args(s.fp) + (f_args_sz(s.fp) - id - 1); break; - case VAR_CLOSURE: + case VAR_CLOSURE: // TODO: check that clojure vars are used only in clojures if (s.fp == NULL) { s_failure(&s, "can't read closure parameter outside of function"); } diff --git a/byterun/include/types.h b/byterun/include/types.h index cd8f8279d..0ff7c63e2 100644 --- a/byterun/include/types.h +++ b/byterun/include/types.h @@ -73,6 +73,14 @@ static inline void s_failure(struct State *s, const char *msg) { s->instr_ip - s->bf->code_ptr, msg); } +static inline void ip_failure(char *ip, Bytefile *bf, const char *msg) { + exec_failure(read_cmd(ip), 0, ip - bf->code_ptr, msg); +} + +static inline void ip_safe_failure(char *ip, Bytefile *bf, const char *msg) { + exec_failure("_UNDEF_", 0, ip - bf->code_ptr, msg); +} + // ------ VarCategory ------ enum VarCategory { diff --git a/byterun/old-byterun.exe b/byterun/old-byterun.exe new file mode 100755 index 000000000..4ce4edcef Binary files /dev/null and b/byterun/old-byterun.exe differ diff --git a/byterun/old_byterun.exe b/byterun/old_byterun.exe new file mode 100755 index 000000000..4ce4edcef Binary files /dev/null and b/byterun/old_byterun.exe differ diff --git a/byterun/performance_check.sh b/byterun/performance_check.sh index 7e8a0f0c9..7175360f4 100755 --- a/byterun/performance_check.sh +++ b/byterun/performance_check.sh @@ -11,7 +11,12 @@ time echo '0' | lamac -s ../performance/Sort.lama > /dev/null lamac -b ../performance/Sort.lama > /dev/null +# ./byterun.exe -p Sort.bc + +echo "Old Byterun:" +time ./old_byterun.exe -i Sort.bc > /dev/null + echo "Byterun:" -time ./byterun.exe Sort.bc > /dev/null +time ./byterun.exe -vi Sort.bc > /dev/null rm Sort.* diff --git a/byterun/src/analyzer.cpp b/byterun/src/analyzer.cpp index a4a5d5dd9..202eb7879 100644 --- a/byterun/src/analyzer.cpp +++ b/byterun/src/analyzer.cpp @@ -1,5 +1,6 @@ #include "analyzer.hpp" #include "parser.hpp" +#include extern "C" { #include "types.h" @@ -21,43 +22,65 @@ void analyze(Bytefile *bf) { uint current_args_count = 0; uint16_t *current_begin_counter = nullptr; - auto const to_visit_push = [&visited, ¤t_stack_depth](size_t offset, - auto &to_visit) { + char *ip = bf->code_ptr; + char *current_ip = ip; + char *saved_current_ip = current_ip; + + auto const jmp_to_visit_push = [&saved_current_ip, &bf, &visited, + ¤t_stack_depth, + &to_visit_jmp](size_t offset) { if (visited[offset] == NOT_VISITED) { - visited[offset] = true; - to_visit.push_back(offset); + visited[offset] = current_stack_depth; + to_visit_jmp.push_back(offset); } else if (visited[offset] != current_stack_depth) { // TODO: is this condition same for calls? - failure("different stack depth on same point is not allowed"); + ip_failure(saved_current_ip, bf, + "different stack depth on same point is not allowed"); } }; - auto const control_push = [&to_visit_push, &control_flow_in](size_t offset, - auto &to_visit) { - control_flow_in[offset] = true; - to_visit_push(offset, to_visit); + auto const func_to_visit_push = [&saved_current_ip, &bf, &visited, + ¤t_stack_depth, + &to_visit_func](size_t offset) { + if (visited[offset] == NOT_VISITED) { + to_visit_func.push_back(offset); + } + visited[offset] = 0; }; - auto const check_correct_var = [&globals_count, ¤t_locals_count, + auto const jmp_control_push = [&jmp_to_visit_push, + &control_flow_in](size_t offset) { + control_flow_in[offset] = true; + jmp_to_visit_push(offset); + }; + + auto const func_control_push = [&func_to_visit_push, + &control_flow_in](size_t offset) { + control_flow_in[offset] = true; + func_to_visit_push(offset); + }; + + auto const check_correct_var = [&saved_current_ip, &bf, &globals_count, + ¤t_locals_count, ¤t_args_count](uint8_t l, uint id) { if (l > 3) { - failure("unexpected variable category"); + ip_failure(saved_current_ip, bf, "unexpected variable category"); } VarCategory category = to_var_category(l); switch (category) { case VAR_GLOBAL: if (id >= globals_count) { - failure("global var index is out of range"); + ip_failure(saved_current_ip, bf, "global var index is out of range"); } break; case VAR_LOCAL: if (id >= current_locals_count) { - failure("local var index is out of range"); + ip_failure(saved_current_ip, bf, "local var index is out of range"); } break; case VAR_ARGUMENT: if (id >= current_args_count) { - failure("argument var index is out of range"); + ip_failure(saved_current_ip, bf, "argument var index is out of range"); } break; case VAR_CLOSURE: @@ -69,7 +92,7 @@ void analyze(Bytefile *bf) { // add publics to_visit_func.reserve(bf->public_symbols_number); for (size_t i = 0; i < bf->public_symbols_number; ++i) { - control_push(get_public_offset(bf, i), to_visit_func); + func_control_push(get_public_offset(bf, i)); } if (to_visit_func.size() == 0) { @@ -77,7 +100,7 @@ void analyze(Bytefile *bf) { } while (true) { - char *ip = bf->code_ptr; + ip = bf->code_ptr; if (current_begin_counter == nullptr) { if (to_visit_func.empty()) { break; @@ -95,36 +118,47 @@ void analyze(Bytefile *bf) { } if (ip >= bf->code_ptr + bf->code_size) { - failure("instruction pointer is out of range (>= size)"); + ip_safe_failure(ip, bf, "instruction pointer is out of range (>= size)"); } if (ip < bf->code_ptr) { - failure("instruction pointer is out of range (< 0)"); + ip_safe_failure(ip, bf, "instruction pointer is out of range (< 0)"); } - char *current_ip = ip; + current_ip = ip; + saved_current_ip = current_ip; #ifdef DEBUG_VERSION - printf("0x%.8lx \n", current_ip - bf->code_ptr - 1); -#endif - + const auto [cmd, l] = parse_command(&ip, *bf, std::cout); +#else const auto [cmd, l] = parse_command(&ip, *bf); +#endif if (current_begin_counter == nullptr && cmd != Cmd::BEGIN && cmd != Cmd::CBEGIN) { - failure("function does not start with begin"); + ip_failure(saved_current_ip, bf, "function does not start with begin"); } - visited[current_ip - bf->code_ptr] = current_stack_depth; + if (visited[current_ip - bf->code_ptr] == NOT_VISITED) { + ip_failure(saved_current_ip, bf, "not visited command"); + } + current_stack_depth = visited[current_ip - bf->code_ptr]; + +#ifdef DEBUG_VERSION + std::cout << " -- [" << current_stack_depth << ']' << '\n'; +#endif ++current_ip; // skip command byte - char *const saved_current_ip = current_ip; size_t extra_stack_during_opr = 0; // change stack depth switch (cmd) { case Cmd::BINOP: current_stack_depth -= 2; + if (current_stack_depth < 0) { + ip_failure(saved_current_ip, bf, "not enough elements in stack"); + } + ++current_stack_depth; break; case Cmd::CONST: ++current_stack_depth; @@ -135,18 +169,22 @@ void analyze(Bytefile *bf) { case Cmd::SEXP: ip_read_string(¤t_ip, *bf); current_stack_depth -= ip_read_int(¤t_ip, *bf); + if (current_stack_depth < 0) { + ip_failure(saved_current_ip, bf, "not enough elements in stack"); + } + ++current_stack_depth; break; case Cmd::STI: current_stack_depth -= 2; if (current_stack_depth < 0) { - failure("not enough elements in stack"); + ip_failure(saved_current_ip, bf, "not enough elements in stack"); } ++current_stack_depth; break; case Cmd::STA: current_stack_depth -= 3; if (current_stack_depth < 0) { - failure("not enough elements in stack"); + ip_failure(saved_current_ip, bf, "not enough elements in stack"); } ++current_stack_depth; break; @@ -166,13 +204,13 @@ void analyze(Bytefile *bf) { break; case Cmd::SWAP: if (current_stack_depth < 2) { - failure("not enough elements in stack"); + ip_failure(saved_current_ip, bf, "not enough elements in stack"); } break; case Cmd::ELEM: current_stack_depth -= 2; if (current_stack_depth < 0) { - failure("not enough elements in stack"); + ip_failure(saved_current_ip, bf, "not enough elements in stack"); } ++current_stack_depth; break; @@ -187,7 +225,7 @@ void analyze(Bytefile *bf) { case Cmd::ST: check_correct_var(l, ip_read_int(¤t_ip, *bf)); if (current_stack_depth < 1) { - failure("not enough elements in stack"); + ip_failure(saved_current_ip, bf, "not enough elements in stack"); } break; case Cmd::CJMPz: @@ -197,7 +235,7 @@ void analyze(Bytefile *bf) { case Cmd::BEGIN: case Cmd::CBEGIN: if (current_begin_counter != nullptr) { - failure("unexpected function beginning"); + ip_failure(saved_current_ip, bf, "unexpected function beginning"); } current_args_count = ip_read_int(¤t_ip, *bf); current_begin_counter = (uint16_t *)(current_ip + sizeof(uint16_t)); @@ -221,7 +259,7 @@ void analyze(Bytefile *bf) { uint args_count = ip_read_int(¤t_ip, *bf); current_stack_depth -= args_count + 1; // + closure itself if (current_stack_depth < 0) { - failure("not enough elements in stack"); + ip_failure(saved_current_ip, bf, "not enough elements in stack"); } ++current_stack_depth; // NOTE: can't check args == cbegin args (?) @@ -231,27 +269,27 @@ void analyze(Bytefile *bf) { uint args_count = ip_read_int(¤t_ip, *bf); current_stack_depth -= args_count; if (current_stack_depth < 0) { - failure("not enough elements in stack"); + ip_failure(saved_current_ip, bf, "not enough elements in stack"); } ++current_stack_depth; // TODO: unify with next loop if (call_offset >= bf->code_size) { - failure("jump/call out of file"); + ip_failure(saved_current_ip, bf, "jump/call out of file"); } if (args_count != *(uint *)(bf->code_ptr + call_offset + 1)) { - failure("wrong call argument count"); + ip_failure(saved_current_ip, bf, "wrong call argument count"); } } break; case Cmd::TAG: if (current_stack_depth < 1) { - failure("not enough elements in stack"); + ip_failure(saved_current_ip, bf, "not enough elements in stack"); } break; case Cmd::ARRAY: if (current_stack_depth < 1) { - failure("not enough elements in stack"); + ip_failure(saved_current_ip, bf, "not enough elements in stack"); } break; case Cmd::FAIL: @@ -265,7 +303,7 @@ void analyze(Bytefile *bf) { --current_stack_depth; } if (current_stack_depth < 0) { - failure("not enough elements in stack"); + ip_failure(saved_current_ip, bf, "not enough elements in stack"); } ++current_stack_depth; break; @@ -276,30 +314,31 @@ void analyze(Bytefile *bf) { case Cmd::Llength: case Cmd::Lstring: if (current_stack_depth < 1) { - failure("not enough elements in stack"); + ip_failure(saved_current_ip, bf, "not enough elements in stack"); } break; case Cmd::Barray: - current_stack_depth -= ip_read_int(¤t_ip, *bf); + current_stack_depth -= ip_read_int(¤t_ip, *bf); // elem count if (current_stack_depth < 0) { - failure("not enough elements in stack"); + ip_failure(saved_current_ip, bf, "not enough elements in stack"); } ++current_stack_depth; break; case Cmd::EXIT: - failure("exit should be unreachable"); // NOTE: not sure + ip_failure(saved_current_ip, bf, + "exit should be unreachable"); // NOTE: not sure break; case Cmd::_UNDEF_: - failure("undefined command"); + ip_failure(saved_current_ip, bf, "undefined command"); break; } if (current_begin_counter == nullptr) { - failure("function does not start with begin"); + ip_failure(saved_current_ip, bf, "function does not start with begin"); } if (current_stack_depth < 0) { - failure("not enough elements in stack"); + ip_failure(saved_current_ip, bf, "not enough elements in stack"); } *current_begin_counter = @@ -307,6 +346,7 @@ void analyze(Bytefile *bf) { (uint16_t)(current_stack_depth + extra_stack_during_opr)); current_ip = saved_current_ip; + ++current_ip; // skip command byte // do jumps switch (cmd) { case Cmd::EXIT: @@ -318,25 +358,29 @@ void analyze(Bytefile *bf) { case Cmd::CJMPnz: case Cmd::CLOSURE: case Cmd::CALL: - to_visit_push(ip - bf->code_ptr, to_visit_jmp); + jmp_to_visit_push(ip - bf->code_ptr); case Cmd::JMP: { bool is_call = (cmd == Cmd::CLOSURE || cmd == Cmd::CALL); uint jmp_p = ip_read_int(¤t_ip, *bf); if (jmp_p >= bf->code_size) { // NOTE: maybe also should check that > begin (?) - failure("jump/call out of file"); + ip_failure(saved_current_ip, bf, "jump/call out of file"); + } + if (is_call) { + func_control_push(jmp_p); + } else { + jmp_control_push(jmp_p); } - control_push(jmp_p, is_call ? to_visit_func : to_visit_jmp); break; } case Cmd::_UNDEF_: - failure("undefined command"); + ip_failure(saved_current_ip, bf, "undefined command"); break; default: - to_visit_push(ip - bf->code_ptr, to_visit_jmp); + jmp_to_visit_push(ip - bf->code_ptr); break; } } diff --git a/byterun/src/cli.cpp b/byterun/src/cli.cpp index 4160c609d..2f625becf 100644 --- a/byterun/src/cli.cpp +++ b/byterun/src/cli.cpp @@ -1,3 +1,8 @@ +#include + +#include "analyzer.hpp" +#include "parser.hpp" + extern "C" { #include "../../runtime/runtime.h" #include "interpreter.h" @@ -5,8 +10,6 @@ extern "C" { #include "utils.h" } -#include "analyzer.hpp" - int main(int argc, char **argv) { if (argc < 2) { failure("no execution option"); @@ -14,6 +17,7 @@ int main(int argc, char **argv) { bool do_verification = false; bool do_interpretation = false; + bool do_print = false; if (strcmp(argv[1], "-vi") == 0) { do_verification = true; do_interpretation = true; @@ -21,6 +25,8 @@ int main(int argc, char **argv) { do_interpretation = true; } else if (strcmp(argv[1], "-v") == 0) { do_verification = true; + } else if (strcmp(argv[1], "-p") == 0) { + do_print = true; } else { failure("wrong execution option (acceptable options - '-i', '-v', '-vi')"); } @@ -33,6 +39,9 @@ int main(int argc, char **argv) { // #ifdef DEBUG_VERSION // dump_file (stdout, f); // #endif + if (do_print) { + print_file(*f, std::cout); + } if (do_verification) { analyze(f); } diff --git a/byterun/src/interpreter.c b/byterun/src/interpreter.c index faf8a096a..57ed63f3b 100644 --- a/byterun/src/interpreter.c +++ b/byterun/src/interpreter.c @@ -17,25 +17,31 @@ struct State s; static inline uint16_t ip_read_half_int(char **ip) { +#ifndef WITH_CHECK if (*ip + sizeof(uint16_t) > s.bf->code_ptr + s.bf->code_size) { failure("last command is invalid, int parameter can not be read\n"); } +#endif *ip += sizeof(uint16_t); return *(uint16_t *)((*ip) - sizeof(uint16_t)); } static inline int ip_read_int(char **ip) { +#ifndef WITH_CHECK if (*ip + sizeof(int) > s.bf->code_ptr + s.bf->code_size) { failure("last command is invalid, int parameter can not be read\n"); } +#endif *ip += sizeof(int); return *(int *)((*ip) - sizeof(int)); } static inline uint8_t ip_read_byte(char **ip) { +#ifndef WITH_CHECK if (*ip + sizeof(char) > s.bf->code_ptr + s.bf->code_size) { failure("last command is invalid, byte parameter can not be read\n"); } +#endif return *(*ip)++; } @@ -73,6 +79,7 @@ void run(Bytefile *bf, int argc, char **argv) { do { bool call_happened = false; +#ifndef WITH_CHECK if (s.ip >= bf->code_ptr + bf->code_size) { s_failure(&s, "instruction pointer is out of range (>= size)"); } @@ -80,6 +87,7 @@ void run(Bytefile *bf, int argc, char **argv) { if (s.ip < bf->code_ptr) { s_failure(&s, "instruction pointer is out of range (< 0)"); } +#endif s.instr_ip = s.ip; uint8_t x = ip_read_byte(&s.ip), h = (x & 0xF0) >> 4, l = x & 0x0F; @@ -179,9 +187,11 @@ void run(Bytefile *bf, int argc, char **argv) { case CMD_BASIC_JMP: { // JMP 0x%.8x uint jmp_p = ip_read_int(&s.ip); +#ifndef WITH_CHECK if (jmp_p >= bf->code_size) { s_failure(&s, "jump out of file"); } +#endif s.ip = bf->code_ptr + jmp_p; break; } @@ -254,9 +264,11 @@ void run(Bytefile *bf, int argc, char **argv) { case CMD_CTRL_CJMPz: { // CJMPz 0x%.8x uint jmp_p = ip_read_int(&s.ip); +#ifndef WITH_CHECK if (jmp_p >= bf->code_size) { s_failure(&s, "jump out of file"); } +#endif if (UNBOX(s_pop_i()) == 0) { s.ip = bf->code_ptr + jmp_p; } @@ -266,9 +278,11 @@ void run(Bytefile *bf, int argc, char **argv) { case CMD_CTRL_CJMPnz: { // CJMPnz 0x%.8x uint jmp_p = ip_read_int(&s.ip); +#ifndef WITH_CHECK if (jmp_p >= bf->code_size) { s_failure(&s, "jump out of file"); } +#endif if (UNBOX(s_pop_i()) != 0) { s.ip = bf->code_ptr + jmp_p; } @@ -277,34 +291,50 @@ void run(Bytefile *bf, int argc, char **argv) { case CMD_CTRL_BEGIN: { // BEGIN %d %d // function begin uint args_sz = ip_read_int(&s.ip); +// #ifdef WITH_CHECK uint locals_sz = ip_read_half_int(&s.ip); uint max_additional_stack_sz = ip_read_half_int(&s.ip); +// #else +// uint locals_sz = ip_read_int(&s.ip); +// #endif +#ifdef WITH_CHECK if (s.fp != NULL && s.call_ip == NULL) { 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); - // TODO: add ifdef +#ifndef WITH_CHECK + // TODO if ((void **)__gc_stack_top + (aint)max_additional_stack_sz - 1 <= s.stack) { s_failure(&s, "stack owerflow"); } +#endif break; } case CMD_CTRL_CBEGIN: { // CBEGIN %d %d // NOTE: example not found, no checks done uint args_sz = ip_read_int(&s.ip); - uint max_additional_stack_sz = ip_read_half_int(&s.ip); +// #ifdef WITH_CHECK uint locals_sz = ip_read_half_int(&s.ip); + uint max_additional_stack_sz = ip_read_half_int(&s.ip); +// #else + // uint locals_sz = ip_read_int(&s.ip); +// #endif +#ifndef WITH_CHECK if (s.fp != NULL && s.call_ip == NULL) { 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); // TODO: add ifdef +#ifdef WITH_CHECK if ((void **)__gc_stack_top + (aint)max_additional_stack_sz - 1 <= s.stack) { s_failure(&s, "stack owerflow"); } +#endif break; } @@ -320,9 +350,11 @@ void run(Bytefile *bf, int argc, char **argv) { var_by_category(to_var_category(arg_type), arg_id); s_push(*var_ptr); } +#ifndef WITH_CHECK if (call_offset >= bf->code_size) { s_failure(&s, "jump out of file"); } +#endif s_push(bf->code_ptr + call_offset); void *closure = Bclosure((aint *)__gc_stack_top, args_count); @@ -351,9 +383,11 @@ void run(Bytefile *bf, int argc, char **argv) { s.is_closure_call = false; s.call_ip = s.ip; +#ifndef WITH_CHECK if (call_p >= bf->code_size) { s_failure(&s, "jump out of file"); } +#endif s.ip = bf->code_ptr + call_p; break; } diff --git a/byterun/src/parser.cpp b/byterun/src/parser.cpp index 3a449ce8b..949084ebf 100644 --- a/byterun/src/parser.cpp +++ b/byterun/src/parser.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -574,3 +575,18 @@ std::pair parse_command(char **ip, const Bytefile &bf, std::ostream &out) { return parse_command_impl(ip, bf, out); } + +void print_file(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 + << ": "; + const auto [cmd, l] = parse_command(&ip, bf, out); + out << '\n'; + + if (cmd == Cmd::EXIT) { + break; + } + } +}