fixes, ifdefs for different byterun versions

This commit is contained in:
ProgramSnail 2024-12-15 03:33:46 +03:00
parent 5a6dbe3692
commit 2589f6166f
11 changed files with 244 additions and 58 deletions

View file

@ -9,6 +9,20 @@
(:runtime ../runtime/runtime.a)) (:runtime ../runtime/runtime.a))
(mode (mode
(promote (until-clean))) (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 (action
(run g++ -std=c++20 -Iinclude/ %{main} %{parser} %{analyzer} %{runtime} %{obj} -o %{target}))) (run g++ -std=c++20 -Iinclude/ %{main} %{parser} %{analyzer} %{runtime} %{obj} -o %{target})))
@ -21,7 +35,7 @@
(mode (mode
(promote (until-clean))) (promote (until-clean)))
(action (action
(run gcc -Iinclude/ -c %{src} -o %{target}))) (run gcc -Iinclude/ -DWITH_CHECK -c %{src} -o %{target})))
(rule (rule
(target parser.o) (target parser.o)
@ -32,10 +46,43 @@
(mode (mode
(promote (until-clean))) (promote (until-clean)))
(action (action
(run gcc -Iinclude/ -c %{src} -o %{target}))) (run gcc -Iinclude/ -DWITH_CHECK -c %{src} -o %{target})))
(rule (rule
(target interpreter.o) (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 (deps
(:include (source_tree include)) (:include (source_tree include))
(:src src/interpreter.c) (:src src/interpreter.c)

View file

@ -70,3 +70,5 @@ static inline const char *ip_read_string(char **ip, const Bytefile &bf) {
std::pair<Cmd, uint8_t> parse_command(char **ip, const Bytefile &bf); std::pair<Cmd, uint8_t> parse_command(char **ip, const Bytefile &bf);
std::pair<Cmd, uint8_t> parse_command(char **ip, const Bytefile &bf, std::pair<Cmd, uint8_t> parse_command(char **ip, const Bytefile &bf,
std::ostream &out); std::ostream &out);
void print_file(const Bytefile &bf, std::ostream &out);

View file

@ -24,23 +24,27 @@ static inline bool s_is_empty() {
} }
static inline void **s_nth(size_t n) { static inline void **s_nth(size_t n) {
#ifndef WITH_CHECK
if ((void **)__gc_stack_top + n >= s_top()) { if ((void **)__gc_stack_top + n >= s_top()) {
s_failure(&s, "not enough elements in stack"); s_failure(&s, "not enough elements in stack");
} }
if (s.fp != NULL && (void **)__gc_stack_top + n >= f_locals(s.fp)) { if (s.fp != NULL && (void **)__gc_stack_top + n >= f_locals(s.fp)) {
s_failure(&s, "not enough elements in function stack"); s_failure(&s, "not enough elements in function stack");
} }
#endif
return (void **)__gc_stack_top + n; return (void **)__gc_stack_top + n;
} }
static inline void **s_peek() { static inline void **s_peek() {
#ifndef WITH_CHECK
if ((void **)__gc_stack_top == s_top()) { if ((void **)__gc_stack_top == s_top()) {
s_failure(&s, "empty stack"); s_failure(&s, "empty stack");
} }
if (s.fp != NULL && (void **)__gc_stack_top == f_locals(s.fp)) { if (s.fp != NULL && (void **)__gc_stack_top == f_locals(s.fp)) {
s_failure(&s, "empty function stack"); s_failure(&s, "empty function stack");
} }
#endif
return (void **)__gc_stack_top; 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 aint *s_peek_i() { return (aint *)s_peek(); }
static inline void s_push(void *val) { static inline void s_push(void *val) {
#ifndef WITH_CHECK
if ((void **)__gc_stack_top == s.stack) { if ((void **)__gc_stack_top == s.stack) {
s_failure(&s, "stack overflow"); s_failure(&s, "stack overflow");
} }
#endif
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
printf("--> push\n"); printf("--> push\n");
#endif #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_push_nil() { s_push(NULL); }
static inline void s_pushn_nil(size_t n) { static inline void s_pushn_nil(size_t n) {
#ifndef WITH_CHECK
if ((void **)__gc_stack_top + (aint)n - 1 <= s.stack) { if ((void **)__gc_stack_top + (aint)n - 1 <= s.stack) {
s_failure(&s, "stack overflow"); s_failure(&s, "stack overflow");
} }
#endif
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
__gc_stack_top -= sizeof(void *); __gc_stack_top -= sizeof(void *);
*(void **)__gc_stack_top = NULL; *(void **)__gc_stack_top = NULL;
@ -73,12 +81,14 @@ static inline void s_pushn_nil(size_t n) {
} }
static inline void *s_pop() { static inline void *s_pop() {
#ifndef WITH_CHECK
if ((void **)__gc_stack_top == s_top()) { if ((void **)__gc_stack_top == s_top()) {
s_failure(&s, "empty stack"); s_failure(&s, "empty stack");
} }
if (s.fp != NULL && (void **)__gc_stack_top == f_locals(s.fp)) { if (s.fp != NULL && (void **)__gc_stack_top == f_locals(s.fp)) {
s_failure(&s, "empty function stack"); s_failure(&s, "empty function stack");
} }
#endif
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
printf("--> pop\n"); printf("--> pop\n");
#endif #endif
@ -102,12 +112,14 @@ static inline void s_popn(size_t n) {
// behaviour // behaviour
static inline void s_put_nth(size_t n, void *val) { static inline void s_put_nth(size_t n, void *val) {
s_push_nil(); s_push_nil();
#ifndef WITH_CHECK
if ((void **)__gc_stack_top + n >= s_top()) { if ((void **)__gc_stack_top + n >= s_top()) {
s_failure(&s, "not enough elements in stack"); s_failure(&s, "not enough elements in stack");
} }
if (s.fp != NULL && (void **)__gc_stack_top + n >= f_locals(s.fp)) { if (s.fp != NULL && (void **)__gc_stack_top + n >= f_locals(s.fp)) {
s_failure(&s, "not enough elements in function stack"); s_failure(&s, "not enough elements in function stack");
} }
#endif
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
((void **)__gc_stack_top)[i] = ((void **)__gc_stack_top)[i + 1]; ((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) { static inline void s_rotate_n(size_t n) {
s_push_nil(); s_push_nil();
#ifndef WITH_CHECK
if ((void **)__gc_stack_top + (aint)n - 1 >= s_top()) { if ((void **)__gc_stack_top + (aint)n - 1 >= s_top()) {
s_failure(&s, "not enough elements in stack"); s_failure(&s, "not enough elements in stack");
} }
if (s.fp != NULL && (void **)__gc_stack_top + (aint)n - 1 >= f_locals(s.fp)) { if (s.fp != NULL && (void **)__gc_stack_top + (aint)n - 1 >= f_locals(s.fp)) {
s_failure(&s, "not enough elements in function stack"); s_failure(&s, "not enough elements in function stack");
} }
#endif
void *buf = NULL; void *buf = NULL;
for (size_t i = 0; 2 * i < n; ++i) { 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); 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()) {
@ -223,14 +238,17 @@ static inline void **var_by_category(enum VarCategory category, size_t id) {
void **var = NULL; void **var = NULL;
switch (category) { switch (category) {
case VAR_GLOBAL: case VAR_GLOBAL:
#ifndef WITH_CHECK
if (s.bf->global_area_size <= id) { if (s.bf->global_area_size <= id) {
s_failure(&s, s_failure(&s,
"can't read global: too big id"); //, %i >= %ul", id, "can't read global: too big id"); //, %i >= %ul", id,
// s.bf->global_area_size); // s.bf->global_area_size);
} }
#endif
var = s.stack + STACK_SIZE - 1 - id; var = s.stack + STACK_SIZE - 1 - id;
break; break;
case VAR_LOCAL: case VAR_LOCAL:
#ifndef WITH_CHECK
if (s.fp == NULL) { if (s.fp == NULL) {
s_failure(&s, "can't read local outside of function"); 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, s_failure(&s, "can't read local: too big id"); //, %i >= %ul", id,
// f_locals_sz(s.fp)); // f_locals_sz(s.fp));
} }
#endif
// printf("id is %i, local is %i, %i\n", id, // printf("id is %i, local is %i, %i\n", id,
// UNBOX((auint)*((void**)f_locals(s.fp) + id)), f_locals(s.fp) - (void // UNBOX((auint)*((void**)f_locals(s.fp) + id)), f_locals(s.fp) - (void
// **)__gc_stack_top); // **)__gc_stack_top);
var = f_locals(s.fp) + (f_locals_sz(s.fp) - id - 1); var = f_locals(s.fp) + (f_locals_sz(s.fp) - id - 1);
break; break;
case VAR_ARGUMENT: case VAR_ARGUMENT:
#ifndef WITH_CHECK
if (s.fp == NULL) { if (s.fp == NULL) {
s_failure(&s, "can't read argument outside of function"); 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, s_failure(&s, "can't read arguments: too big id"); //, %i >= %ul", id,
// f_args_sz(s.fp)); // f_args_sz(s.fp));
} }
#endif
var = f_args(s.fp) + (f_args_sz(s.fp) - id - 1); var = f_args(s.fp) + (f_args_sz(s.fp) - id - 1);
break; break;
case VAR_CLOSURE: case VAR_CLOSURE: // TODO: check that clojure vars are used only in clojures
if (s.fp == NULL) { if (s.fp == NULL) {
s_failure(&s, "can't read closure parameter outside of function"); s_failure(&s, "can't read closure parameter outside of function");
} }

View file

@ -73,6 +73,14 @@ static inline void s_failure(struct State *s, const char *msg) {
s->instr_ip - s->bf->code_ptr, 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 ------ // ------ VarCategory ------
enum VarCategory { enum VarCategory {

BIN
byterun/old-byterun.exe Executable file

Binary file not shown.

BIN
byterun/old_byterun.exe Executable file

Binary file not shown.

View file

@ -11,7 +11,12 @@ time echo '0' | lamac -s ../performance/Sort.lama > /dev/null
lamac -b ../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:" echo "Byterun:"
time ./byterun.exe Sort.bc > /dev/null time ./byterun.exe -vi Sort.bc > /dev/null
rm Sort.* rm Sort.*

View file

@ -1,5 +1,6 @@
#include "analyzer.hpp" #include "analyzer.hpp"
#include "parser.hpp" #include "parser.hpp"
#include <iostream>
extern "C" { extern "C" {
#include "types.h" #include "types.h"
@ -21,43 +22,65 @@ void analyze(Bytefile *bf) {
uint current_args_count = 0; uint current_args_count = 0;
uint16_t *current_begin_counter = nullptr; uint16_t *current_begin_counter = nullptr;
auto const to_visit_push = [&visited, &current_stack_depth](size_t offset, char *ip = bf->code_ptr;
auto &to_visit) { char *current_ip = ip;
char *saved_current_ip = current_ip;
auto const jmp_to_visit_push = [&saved_current_ip, &bf, &visited,
&current_stack_depth,
&to_visit_jmp](size_t offset) {
if (visited[offset] == NOT_VISITED) { if (visited[offset] == NOT_VISITED) {
visited[offset] = true; visited[offset] = current_stack_depth;
to_visit.push_back(offset); to_visit_jmp.push_back(offset);
} else if (visited[offset] != current_stack_depth) { } else if (visited[offset] != current_stack_depth) {
// TODO: is this condition same for calls? // 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 const func_to_visit_push = [&saved_current_ip, &bf, &visited,
auto &to_visit) { &current_stack_depth,
control_flow_in[offset] = true; &to_visit_func](size_t offset) {
to_visit_push(offset, to_visit); if (visited[offset] == NOT_VISITED) {
to_visit_func.push_back(offset);
}
visited[offset] = 0;
}; };
auto const check_correct_var = [&globals_count, &current_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,
&current_locals_count,
&current_args_count](uint8_t l, uint id) { &current_args_count](uint8_t l, uint id) {
if (l > 3) { if (l > 3) {
failure("unexpected variable category"); ip_failure(saved_current_ip, bf, "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) {
failure("global var index is out of range"); ip_failure(saved_current_ip, bf, "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) {
failure("local var index is out of range"); ip_failure(saved_current_ip, bf, "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) {
failure("argument var index is out of range"); ip_failure(saved_current_ip, bf, "argument var index is out of range");
} }
break; break;
case VAR_CLOSURE: case VAR_CLOSURE:
@ -69,7 +92,7 @@ void analyze(Bytefile *bf) {
// add publics // add publics
to_visit_func.reserve(bf->public_symbols_number); to_visit_func.reserve(bf->public_symbols_number);
for (size_t i = 0; i < bf->public_symbols_number; ++i) { 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) { if (to_visit_func.size() == 0) {
@ -77,7 +100,7 @@ void analyze(Bytefile *bf) {
} }
while (true) { while (true) {
char *ip = bf->code_ptr; ip = bf->code_ptr;
if (current_begin_counter == nullptr) { if (current_begin_counter == nullptr) {
if (to_visit_func.empty()) { if (to_visit_func.empty()) {
break; break;
@ -95,36 +118,47 @@ void analyze(Bytefile *bf) {
} }
if (ip >= bf->code_ptr + bf->code_size) { 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) { 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 #ifdef DEBUG_VERSION
printf("0x%.8lx \n", current_ip - bf->code_ptr - 1); const auto [cmd, l] = parse_command(&ip, *bf, std::cout);
#endif #else
const auto [cmd, l] = parse_command(&ip, *bf); const auto [cmd, l] = parse_command(&ip, *bf);
#endif
if (current_begin_counter == nullptr && cmd != Cmd::BEGIN && if (current_begin_counter == nullptr && cmd != Cmd::BEGIN &&
cmd != Cmd::CBEGIN) { 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 ++current_ip; // skip command byte
char *const saved_current_ip = current_ip;
size_t extra_stack_during_opr = 0; size_t extra_stack_during_opr = 0;
// change stack depth // change stack depth
switch (cmd) { switch (cmd) {
case Cmd::BINOP: case Cmd::BINOP:
current_stack_depth -= 2; current_stack_depth -= 2;
if (current_stack_depth < 0) {
ip_failure(saved_current_ip, bf, "not enough elements in stack");
}
++current_stack_depth;
break; break;
case Cmd::CONST: case Cmd::CONST:
++current_stack_depth; ++current_stack_depth;
@ -135,18 +169,22 @@ void analyze(Bytefile *bf) {
case Cmd::SEXP: case Cmd::SEXP:
ip_read_string(&current_ip, *bf); ip_read_string(&current_ip, *bf);
current_stack_depth -= ip_read_int(&current_ip, *bf); current_stack_depth -= ip_read_int(&current_ip, *bf);
if (current_stack_depth < 0) {
ip_failure(saved_current_ip, bf, "not enough elements in stack");
}
++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) {
failure("not enough elements in stack"); ip_failure(saved_current_ip, bf, "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) {
failure("not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
break; break;
@ -166,13 +204,13 @@ void analyze(Bytefile *bf) {
break; break;
case Cmd::SWAP: case Cmd::SWAP:
if (current_stack_depth < 2) { if (current_stack_depth < 2) {
failure("not enough elements in stack"); ip_failure(saved_current_ip, bf, "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) {
failure("not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
break; break;
@ -187,7 +225,7 @@ void analyze(Bytefile *bf) {
case Cmd::ST: case Cmd::ST:
check_correct_var(l, ip_read_int(&current_ip, *bf)); check_correct_var(l, ip_read_int(&current_ip, *bf));
if (current_stack_depth < 1) { if (current_stack_depth < 1) {
failure("not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
break; break;
case Cmd::CJMPz: case Cmd::CJMPz:
@ -197,7 +235,7 @@ 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) {
failure("unexpected function beginning"); ip_failure(saved_current_ip, bf, "unexpected function beginning");
} }
current_args_count = ip_read_int(&current_ip, *bf); current_args_count = ip_read_int(&current_ip, *bf);
current_begin_counter = (uint16_t *)(current_ip + sizeof(uint16_t)); current_begin_counter = (uint16_t *)(current_ip + sizeof(uint16_t));
@ -221,7 +259,7 @@ void analyze(Bytefile *bf) {
uint args_count = ip_read_int(&current_ip, *bf); uint args_count = ip_read_int(&current_ip, *bf);
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) {
failure("not enough elements in stack"); ip_failure(saved_current_ip, bf, "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 (?)
@ -231,27 +269,27 @@ void analyze(Bytefile *bf) {
uint args_count = ip_read_int(&current_ip, *bf); uint args_count = ip_read_int(&current_ip, *bf);
current_stack_depth -= args_count; current_stack_depth -= args_count;
if (current_stack_depth < 0) { 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; ++current_stack_depth;
// TODO: unify with next loop // TODO: unify with next loop
if (call_offset >= bf->code_size) { 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)) { 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; } break;
case Cmd::TAG: case Cmd::TAG:
if (current_stack_depth < 1) { if (current_stack_depth < 1) {
failure("not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
break; break;
case Cmd::ARRAY: case Cmd::ARRAY:
if (current_stack_depth < 1) { if (current_stack_depth < 1) {
failure("not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
break; break;
case Cmd::FAIL: case Cmd::FAIL:
@ -265,7 +303,7 @@ void analyze(Bytefile *bf) {
--current_stack_depth; --current_stack_depth;
} }
if (current_stack_depth < 0) { 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; ++current_stack_depth;
break; break;
@ -276,30 +314,31 @@ 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) {
failure("not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
break; break;
case Cmd::Barray: case Cmd::Barray:
current_stack_depth -= ip_read_int(&current_ip, *bf); current_stack_depth -= ip_read_int(&current_ip, *bf); // elem count
if (current_stack_depth < 0) { 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; ++current_stack_depth;
break; break;
case Cmd::EXIT: 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; break;
case Cmd::_UNDEF_: case Cmd::_UNDEF_:
failure("undefined command"); ip_failure(saved_current_ip, bf, "undefined command");
break; break;
} }
if (current_begin_counter == nullptr) { 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) { 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 = *current_begin_counter =
@ -307,6 +346,7 @@ void analyze(Bytefile *bf) {
(uint16_t)(current_stack_depth + extra_stack_during_opr)); (uint16_t)(current_stack_depth + extra_stack_during_opr));
current_ip = saved_current_ip; current_ip = saved_current_ip;
++current_ip; // skip command byte
// do jumps // do jumps
switch (cmd) { switch (cmd) {
case Cmd::EXIT: case Cmd::EXIT:
@ -318,25 +358,29 @@ void analyze(Bytefile *bf) {
case Cmd::CJMPnz: case Cmd::CJMPnz:
case Cmd::CLOSURE: case Cmd::CLOSURE:
case Cmd::CALL: case Cmd::CALL:
to_visit_push(ip - bf->code_ptr, to_visit_jmp); jmp_to_visit_push(ip - bf->code_ptr);
case Cmd::JMP: { case Cmd::JMP: {
bool is_call = (cmd == Cmd::CLOSURE || cmd == Cmd::CALL); bool is_call = (cmd == Cmd::CLOSURE || cmd == Cmd::CALL);
uint jmp_p = ip_read_int(&current_ip, *bf); uint jmp_p = ip_read_int(&current_ip, *bf);
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 (?)
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; break;
} }
case Cmd::_UNDEF_: case Cmd::_UNDEF_:
failure("undefined command"); ip_failure(saved_current_ip, bf, "undefined command");
break; break;
default: default:
to_visit_push(ip - bf->code_ptr, to_visit_jmp); jmp_to_visit_push(ip - bf->code_ptr);
break; break;
} }
} }

View file

@ -1,3 +1,8 @@
#include <iostream>
#include "analyzer.hpp"
#include "parser.hpp"
extern "C" { extern "C" {
#include "../../runtime/runtime.h" #include "../../runtime/runtime.h"
#include "interpreter.h" #include "interpreter.h"
@ -5,8 +10,6 @@ extern "C" {
#include "utils.h" #include "utils.h"
} }
#include "analyzer.hpp"
int main(int argc, char **argv) { int main(int argc, char **argv) {
if (argc < 2) { if (argc < 2) {
failure("no execution option"); failure("no execution option");
@ -14,6 +17,7 @@ int main(int argc, char **argv) {
bool do_verification = false; bool do_verification = false;
bool do_interpretation = false; bool do_interpretation = false;
bool do_print = false;
if (strcmp(argv[1], "-vi") == 0) { if (strcmp(argv[1], "-vi") == 0) {
do_verification = true; do_verification = true;
do_interpretation = true; do_interpretation = true;
@ -21,6 +25,8 @@ int main(int argc, char **argv) {
do_interpretation = true; do_interpretation = true;
} else if (strcmp(argv[1], "-v") == 0) { } else if (strcmp(argv[1], "-v") == 0) {
do_verification = true; do_verification = true;
} else if (strcmp(argv[1], "-p") == 0) {
do_print = true;
} else { } else {
failure("wrong execution option (acceptable options - '-i', '-v', '-vi')"); failure("wrong execution option (acceptable options - '-i', '-v', '-vi')");
} }
@ -33,6 +39,9 @@ int main(int argc, char **argv) {
// #ifdef DEBUG_VERSION // #ifdef DEBUG_VERSION
// dump_file (stdout, f); // dump_file (stdout, f);
// #endif // #endif
if (do_print) {
print_file(*f, std::cout);
}
if (do_verification) { if (do_verification) {
analyze(f); analyze(f);
} }

View file

@ -17,25 +17,31 @@
struct State s; struct State s;
static inline uint16_t ip_read_half_int(char **ip) { 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) { 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"); failure("last command is invalid, int parameter can not be read\n");
} }
#endif
*ip += sizeof(uint16_t); *ip += sizeof(uint16_t);
return *(uint16_t *)((*ip) - sizeof(uint16_t)); return *(uint16_t *)((*ip) - sizeof(uint16_t));
} }
static inline int ip_read_int(char **ip) { static inline int ip_read_int(char **ip) {
#ifndef WITH_CHECK
if (*ip + sizeof(int) > s.bf->code_ptr + s.bf->code_size) { if (*ip + sizeof(int) > s.bf->code_ptr + s.bf->code_size) {
failure("last command is invalid, int parameter can not be read\n"); failure("last command is invalid, int parameter can not be read\n");
} }
#endif
*ip += sizeof(int); *ip += sizeof(int);
return *(int *)((*ip) - sizeof(int)); return *(int *)((*ip) - sizeof(int));
} }
static inline uint8_t ip_read_byte(char **ip) { static inline uint8_t ip_read_byte(char **ip) {
#ifndef WITH_CHECK
if (*ip + sizeof(char) > s.bf->code_ptr + s.bf->code_size) { if (*ip + sizeof(char) > s.bf->code_ptr + s.bf->code_size) {
failure("last command is invalid, byte parameter can not be read\n"); failure("last command is invalid, byte parameter can not be read\n");
} }
#endif
return *(*ip)++; return *(*ip)++;
} }
@ -73,6 +79,7 @@ void run(Bytefile *bf, int argc, char **argv) {
do { do {
bool call_happened = false; bool call_happened = false;
#ifndef WITH_CHECK
if (s.ip >= bf->code_ptr + bf->code_size) { if (s.ip >= bf->code_ptr + bf->code_size) {
s_failure(&s, "instruction pointer is out of range (>= 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) { if (s.ip < bf->code_ptr) {
s_failure(&s, "instruction pointer is out of range (< 0)"); s_failure(&s, "instruction pointer is out of range (< 0)");
} }
#endif
s.instr_ip = s.ip; s.instr_ip = s.ip;
uint8_t x = ip_read_byte(&s.ip), h = (x & 0xF0) >> 4, l = x & 0x0F; 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 case CMD_BASIC_JMP: { // JMP 0x%.8x
uint jmp_p = ip_read_int(&s.ip); uint jmp_p = ip_read_int(&s.ip);
#ifndef WITH_CHECK
if (jmp_p >= bf->code_size) { if (jmp_p >= bf->code_size) {
s_failure(&s, "jump out of file"); s_failure(&s, "jump out of file");
} }
#endif
s.ip = bf->code_ptr + jmp_p; s.ip = bf->code_ptr + jmp_p;
break; break;
} }
@ -254,9 +264,11 @@ void run(Bytefile *bf, int argc, char **argv) {
case CMD_CTRL_CJMPz: { // CJMPz 0x%.8x case CMD_CTRL_CJMPz: { // CJMPz 0x%.8x
uint jmp_p = ip_read_int(&s.ip); uint jmp_p = ip_read_int(&s.ip);
#ifndef WITH_CHECK
if (jmp_p >= bf->code_size) { if (jmp_p >= bf->code_size) {
s_failure(&s, "jump out of file"); s_failure(&s, "jump out of file");
} }
#endif
if (UNBOX(s_pop_i()) == 0) { if (UNBOX(s_pop_i()) == 0) {
s.ip = bf->code_ptr + jmp_p; 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 case CMD_CTRL_CJMPnz: { // CJMPnz 0x%.8x
uint jmp_p = ip_read_int(&s.ip); uint jmp_p = ip_read_int(&s.ip);
#ifndef WITH_CHECK
if (jmp_p >= bf->code_size) { if (jmp_p >= bf->code_size) {
s_failure(&s, "jump out of file"); s_failure(&s, "jump out of file");
} }
#endif
if (UNBOX(s_pop_i()) != 0) { if (UNBOX(s_pop_i()) != 0) {
s.ip = bf->code_ptr + jmp_p; 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 case CMD_CTRL_BEGIN: { // BEGIN %d %d // function begin
uint args_sz = ip_read_int(&s.ip); uint args_sz = ip_read_int(&s.ip);
// #ifdef WITH_CHECK
uint locals_sz = ip_read_half_int(&s.ip); uint locals_sz = ip_read_half_int(&s.ip);
uint max_additional_stack_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) { if (s.fp != NULL && s.call_ip == NULL) {
s_failure(&s, "begin should only be called after call"); 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, s_enter_f(s.call_ip /*ip from call*/, s.is_closure_call, args_sz,
locals_sz); locals_sz);
// TODO: add ifdef #ifndef WITH_CHECK
// TODO
if ((void **)__gc_stack_top + (aint)max_additional_stack_sz - 1 <= s.stack) { if ((void **)__gc_stack_top + (aint)max_additional_stack_sz - 1 <= s.stack) {
s_failure(&s, "stack owerflow"); s_failure(&s, "stack owerflow");
} }
#endif
break; break;
} }
case CMD_CTRL_CBEGIN: { // CBEGIN %d %d case CMD_CTRL_CBEGIN: { // CBEGIN %d %d
// NOTE: example not found, no checks done // NOTE: example not found, no checks done
uint args_sz = ip_read_int(&s.ip); 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 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) { if (s.fp != NULL && s.call_ip == NULL) {
s_failure(&s, "begin should only be called after call"); 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, s_enter_f(s.call_ip /*ip from call*/, s.is_closure_call, args_sz,
locals_sz); locals_sz);
// TODO: add ifdef // TODO: add ifdef
#ifdef WITH_CHECK
if ((void **)__gc_stack_top + (aint)max_additional_stack_sz - 1 <= s.stack) { if ((void **)__gc_stack_top + (aint)max_additional_stack_sz - 1 <= s.stack) {
s_failure(&s, "stack owerflow"); s_failure(&s, "stack owerflow");
} }
#endif
break; break;
} }
@ -320,9 +350,11 @@ void run(Bytefile *bf, int argc, char **argv) {
var_by_category(to_var_category(arg_type), arg_id); var_by_category(to_var_category(arg_type), arg_id);
s_push(*var_ptr); s_push(*var_ptr);
} }
#ifndef WITH_CHECK
if (call_offset >= bf->code_size) { if (call_offset >= bf->code_size) {
s_failure(&s, "jump out of file"); s_failure(&s, "jump out of file");
} }
#endif
s_push(bf->code_ptr + call_offset); s_push(bf->code_ptr + call_offset);
void *closure = Bclosure((aint *)__gc_stack_top, args_count); 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.is_closure_call = false;
s.call_ip = s.ip; s.call_ip = s.ip;
#ifndef WITH_CHECK
if (call_p >= bf->code_size) { if (call_p >= bf->code_size) {
s_failure(&s, "jump out of file"); s_failure(&s, "jump out of file");
} }
#endif
s.ip = bf->code_ptr + call_p; s.ip = bf->code_ptr + call_p;
break; break;
} }

View file

@ -1,5 +1,6 @@
#include <cassert> #include <cassert>
#include <errno.h> #include <errno.h>
#include <iomanip>
#include <iostream> #include <iostream>
#include <malloc.h> #include <malloc.h>
#include <string.h> #include <string.h>
@ -574,3 +575,18 @@ std::pair<Cmd, uint8_t> parse_command(char **ip, const Bytefile &bf,
std::ostream &out) { std::ostream &out) {
return parse_command_impl<true>(ip, bf, out); return parse_command_impl<true>(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;
}
}
}