interpreter: migration to universial stdlib support (without varargs yet)

This commit is contained in:
ProgramSnail 2025-01-20 23:13:42 +03:00
parent 318ebc72aa
commit 58f0bfc0b9
9 changed files with 163 additions and 119 deletions

View file

@ -24,3 +24,5 @@ int32_t mod_load(const char *name, bool do_verification); // < 0 => not found
uint32_t mod_add(Bytefile *module, bool do_verification); 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);
bool run_stdlib_func(const char *name, size_t args_count);

View file

@ -37,11 +37,12 @@ enum class Cmd : int8_t {
LINE, LINE,
CALLF, CALLF,
PATT, PATT,
Lread, // NOTE: no longer used
Lwrite, // Lread,
Llength, // Lwrite,
Lstring, // Llength,
Barray, // Lstring,
// Barray,
EXIT, EXIT,
_UNDEF_, _UNDEF_,
}; };

View file

@ -117,7 +117,7 @@ enum CMD_TOPLVL {
CMD_ST, CMD_ST,
CMD_CTRL, CMD_CTRL,
CMD_PATT, CMD_PATT,
CMD_BUILTIN, // CMD_BUILTIN, // NOTE: no longer used
CMD_EXIT = 15, CMD_EXIT = 15,
}; };
@ -177,10 +177,10 @@ enum CMD_PATTS {
CMD_PATT_FUN_TAG, CMD_PATT_FUN_TAG,
}; };
enum CMD_BUILTINS { // enum CMD_BUILTINS { // NOTE: no longer used
CMD_BUILTIN_Lread = 0, // CMD_BUILTIN_Lread = 0,
CMD_BUILTIN_Lwrite, // CMD_BUILTIN_Lwrite,
CMD_BUILTIN_Llength, // CMD_BUILTIN_Llength,
CMD_BUILTIN_Lstring, // CMD_BUILTIN_Lstring,
CMD_BUILTIN_Barray, // CMD_BUILTIN_Barray,
}; // };

View file

@ -34,4 +34,3 @@ time ./byterun.exe -i Sort.bc > /dev/null
rm Sort.* rm Sort.*
rm *.o rm *.o
rm *.a

View file

@ -324,7 +324,7 @@ void analyze(uint32_t mod_id) {
break; break;
case Cmd::CALLF: { case Cmd::CALLF: {
// TODO: find link to real function and replace call (need to save all // TODO: find link to real function and replace call (need to save all
// modules in one space) // modules in one space) <- optimization
ip_read_int_unsafe(&current_ip); // function name (str) ip_read_int_unsafe(&current_ip); // function name (str)
uint args_count = ip_read_int_unsafe(&current_ip); uint args_count = ip_read_int_unsafe(&current_ip);
@ -344,23 +344,24 @@ void analyze(uint32_t mod_id) {
} }
++current_stack_depth; ++current_stack_depth;
break; break;
case Cmd::Lread: // NOTE: no longer used
++current_stack_depth; // case Cmd::Lread:
break; // ++current_stack_depth;
case Cmd::Lwrite: // break;
case Cmd::Llength: // case Cmd::Lwrite:
case Cmd::Lstring: // case Cmd::Llength:
if (current_stack_depth < 1) { // case Cmd::Lstring:
ip_failure(saved_current_ip, mod_id, "not enough elements in stack"); // if (current_stack_depth < 1) {
} // ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
break; // }
case Cmd::Barray: // break;
current_stack_depth -= ip_read_int_unsafe(&current_ip); // elem count // case Cmd::Barray:
if (current_stack_depth < 0) { // current_stack_depth -= ip_read_int_unsafe(&current_ip); // elem count
ip_failure(saved_current_ip, mod_id, "not enough elements in stack"); // if (current_stack_depth < 0) {
} // ip_failure(saved_current_ip, mod_id, "not enough elements in stack");
++current_stack_depth; // }
break; // ++current_stack_depth;
// break;
case Cmd::EXIT: case Cmd::EXIT:
ip_failure(saved_current_ip, mod_id, ip_failure(saved_current_ip, mod_id,
"exit should be unreachable"); // NOTE: not sure "exit should be unreachable"); // NOTE: not sure

View file

@ -99,6 +99,27 @@ void run_mod_rec(uint mod_id, int argc, char **argv, bool do_verification) {
run_mod(mod_id, argc, argv); run_mod(mod_id, argc, argv);
} }
static inline void call_Barray(size_t elem_count, char** ip, void** buffer) {
// size_t elem_count = ip_read_int(ip);
void **opr_buffer = (void**)(elem_count > BUFFER_SIZE
? alloc(elem_count * sizeof(void *))
: buffer);
for (size_t i = 0; i < elem_count; ++i) {
opr_buffer[elem_count - i - 1] = s_pop();
}
// s_rotate_n(elem_count);
// NOTE: not sure if elems should be added
void *array =
Barray((aint *)opr_buffer,
BOX(elem_count));
// void *array = Barray((aint *)s_peek(), BOX(elem_count));
s_push(array);
}
void run_mod(uint mod_id, int argc, char **argv) { void run_mod(uint mod_id, int argc, char **argv) {
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
printf("--- module init state ---\n"); printf("--- module init state ---\n");
@ -463,11 +484,21 @@ void run_mod(uint mod_id, int argc, char **argv) {
case CMD_CTRL_CALLF: { // CALLF %s %d // call external function case CMD_CTRL_CALLF: { // CALLF %s %d // call external function
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 size_t args_count = ip_read_int(&s.ip); // args count
if (run_stdlib_func(call_func_name, args_count)) {
// case of stdlib function
break;
}
if (strcmp(call_func_name, ".array") == 0) {
call_Barray(args_count, &s.ip, buffer);
break;
}
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"); failure("RUNTIME:ERROR: external function <%s> with <%zu> args not found\n", call_func_name, args_count);
} }
call_happened = true; call_happened = true;
@ -519,52 +550,53 @@ void run_mod(uint mod_id, int argc, char **argv) {
} }
break; break;
case CMD_BUILTIN: { // NOTE: no longer used
switch (l) { // case CMD_BUILTIN: {
case CMD_BUILTIN_Lread: // CALL Lread // switch (l) {
s_push_i(Lread()); // case CMD_BUILTIN_Lread: // CALL Lread
break; // s_push_i(Lread());
// break;
case CMD_BUILTIN_Lwrite: // CALL Lwrite // case CMD_BUILTIN_Lwrite: // CALL Lwrite
Lwrite(*s_peek_i()); // Lwrite(*s_peek_i());
break; // break;
case CMD_BUILTIN_Llength: // CALL Llength // case CMD_BUILTIN_Llength: // CALL Llength
s_push_i(Llength(s_pop())); // s_push_i(Llength(s_pop()));
break; // break;
case CMD_BUILTIN_Lstring: { // CALL Lstring // case CMD_BUILTIN_Lstring: { // CALL Lstring
void *val = s_pop(); // void *val = s_pop();
void *str = Lstring((aint *)&val); // void *str = Lstring((aint *)&val);
s_push(str); // s_push(str);
break; // break;
} // }
case CMD_BUILTIN_Barray: { // CALL Barray %d // case CMD_BUILTIN_Barray: { // CALL Barray %d
size_t elem_count = ip_read_int(&s.ip); // size_t elem_count = ip_read_int(&s.ip);
void **opr_buffer = (void**)(elem_count > BUFFER_SIZE // void **opr_buffer = (void**)(elem_count > BUFFER_SIZE
? alloc(elem_count * sizeof(void *)) // ? alloc(elem_count * sizeof(void *))
: buffer); // : buffer);
for (size_t i = 0; i < elem_count; ++i) { // for (size_t i = 0; i < elem_count; ++i) {
opr_buffer[elem_count - i - 1] = s_pop(); // opr_buffer[elem_count - i - 1] = s_pop();
} // }
// s_rotate_n(elem_count); // // s_rotate_n(elem_count);
void *array = // void *array =
Barray((aint *)opr_buffer, // Barray((aint *)opr_buffer,
BOX(elem_count)); // NOTE: not sure if elems should be // BOX(elem_count)); // NOTE: not sure if elems should be
// added // // added
// void *array = Barray((aint *)s_peek(), BOX(elem_count)); // // void *array = Barray((aint *)s_peek(), BOX(elem_count));
s_push(array); // s_push(array);
break; // break;
} // }
default: // default:
s_failure(&s, "invalid opcode"); // %d-%d\n", h, l); // s_failure(&s, "invalid opcode"); // %d-%d\n", h, l);
} // }
} break; // } break;
default: default:
s_failure(&s, "invalid opcode"); // %d-%d\n", h, l); s_failure(&s, "invalid opcode"); // %d-%d\n", h, l);

View file

@ -154,7 +154,7 @@ struct StdFunc {
bool is_args = false; // one var for all args bool is_args = false; // one var for all args
bool is_vararg = false; bool is_vararg = false;
}; };
bool run_stdlib_func(const char *name) { bool run_stdlib_func(const char *name, size_t args_count) {
static const std::unordered_map<std::string, StdFunc> std_func = { static const std::unordered_map<std::string, StdFunc> std_func = {
{"Luppercase", {.ptr = (void (*)()) & Luppercase, .args_count = 1}}, {"Luppercase", {.ptr = (void (*)()) & Luppercase, .args_count = 1}},
{"Llowercase", {.ptr = (void (*)()) & Llowercase, .args_count = 1}}, {"Llowercase", {.ptr = (void (*)()) & Llowercase, .args_count = 1}},
@ -217,8 +217,14 @@ bool run_stdlib_func(const char *name) {
return false; return false;
} }
// TODO: stack safity check // TODO: move to bytecode verifier
// TODO: add stdlib func stack check to verification step if ((!it->second.is_vararg && it->second.args_count != args_count) ||
it->second.args_count > args_count) {
failure("RUNTIME ERROR: stdlib function <%s> argument count <%zu> is not "
"expected (expected is <%s%zu>)\n",
name, it->second.args_count, it->second.is_vararg ? ">=" : "=",
args_count);
}
// TODO: work with varargs // TODO: work with varargs
if (it->second.is_vararg) { if (it->second.is_vararg) {

View file

@ -219,16 +219,17 @@ const char *command_name(Cmd cmd, int8_t l) {
return "_UNDEF_PATT_"; return "_UNDEF_PATT_";
} }
return pats[l]; return pats[l];
case Cmd::Lread: // NOTE: no longer used
return "CALL\tLread"; // case Cmd::Lread:
case Cmd::Lwrite: // return "CALL\tLread";
return "CALL\tLwrite"; // case Cmd::Lwrite:
case Cmd::Llength: // return "CALL\tLwrite";
return "CALL\tLlength"; // case Cmd::Llength:
case Cmd::Lstring: // return "CALL\tLlength";
return "CALL\tLstring"; // case Cmd::Lstring:
case Cmd::Barray: // return "CALL\tLstring";
return "CALL\tBarray\t%d"; // case Cmd::Barray:
// return "CALL\tBarray\t%d";
case Cmd::_UNDEF_: case Cmd::_UNDEF_:
return "_UNDEF_"; return "_UNDEF_";
} }
@ -552,35 +553,37 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
break; break;
case CMD_BUILTIN: { // NOTE: no longer used
switch (l) { // case CMD_BUILTIN: {
case CMD_BUILTIN_Lread: // CALL Lread // switch (l) {
cmd = Cmd::Lread; // case CMD_BUILTIN_Lread: // CALL Lread
read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out); // cmd = Cmd::Lread;
break; // read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
case CMD_BUILTIN_Lwrite: // CALL Lwrite // break;
cmd = Cmd::Lwrite; // case CMD_BUILTIN_Lwrite: // CALL Lwrite
read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out); // cmd = Cmd::Lwrite;
break; // read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
case CMD_BUILTIN_Llength: // CALL Llength // break;
cmd = Cmd::Llength; // case CMD_BUILTIN_Llength: // CALL Llength
read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out); // cmd = Cmd::Llength;
break; // read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
case CMD_BUILTIN_Lstring: // CALL Lstring // break;
cmd = Cmd::Lstring; // case CMD_BUILTIN_Lstring: // CALL Lstring
read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out); // cmd = Cmd::Lstring;
break; // read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
// break;
case CMD_BUILTIN_Barray: // CALL Barray %d // case CMD_BUILTIN_Barray: // CALL Barray %d
cmd = Cmd::Barray; // cmd = Cmd::Barray;
read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf, // read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip,
out); // bf,
break; // out);
// break;
default: // default:
failure("invalid opcode"); // failure("invalid opcode");
} // }
} break; // } break;
default: default:
failure("invalid opcode"); failure("invalid opcode");

View file

@ -275,17 +275,17 @@ module ByteCode = struct
add_fixup s; add_fixup s;
add_ints [ 0 ] add_ints [ 0 ]
(* 0x70 *) (* 0x70 *)
| CALL (f, _, _) when f = labeled "read" -> add_bytes [ (7 * 16) + 0 ] (* | CALL (f, _, _) when f = labeled "read" -> add_bytes [ (7 * 16) + 0 ] *)
(* 0x71 *) (* 0x71 *)
| CALL (f, _, _) when f = labeled "write" -> add_bytes [ (7 * 16) + 1 ] (* | CALL (f, _, _) when f = labeled "write" -> add_bytes [ (7 * 16) + 1 ] *)
(* 0x72 *) (* 0x72 *)
| CALL (f, _, _) when f = labeled "length" -> add_bytes [ (7 * 16) + 2 ] (* | CALL (f, _, _) when f = labeled "length" -> add_bytes [ (7 * 16) + 2 ] *)
(* 0x73 *) (* 0x73 *)
| CALL (f, _, _) when f = labeled "string" -> add_bytes [ (7 * 16) + 3 ] (* | CALL (f, _, _) when f = labeled "string" -> add_bytes [ (7 * 16) + 3 ] *)
(* 0x74 *) (* 0x74 *)
| CALL (".array", n, _) -> (* | CALL (".array", n, _) -> *)
add_bytes [ (7 * 16) + 4 ]; (* add_bytes [ (7 * 16) + 4 ]; *)
add_ints [ n ] (* add_ints [ n ] *)
(* 0x52 n:32 n:32 *) (* 0x52 n:32 n:32 *)
| BEGIN (_, a, l, [], _, _) -> | BEGIN (_, a, l, [], _, _) ->
add_bytes [ (5 * 16) + 2 ]; add_bytes [ (5 * 16) + 2 ];