Debug set options
Unified · Split
| @@ -4,8 +4,8 @@ · 3 unmodified lines | ||
| 4 | 4 | // Author: arr |
| 5 | 5 | // |
| 6 | 6 | |
| 7 | −#include <vm_asm.h> | |
| 8 | 7 | #include <array> |
| 8 | +#include <vm_asm_sigkind.h> | |
| 9 | 9 | #include "rfc1321/global.h" |
| 10 | 10 | #include "rfc1321/md5.h" |
| 11 | 11 | |
| @@ -33,6 +33,8 @@ · 32 unmodified lines | ||
| 33 | 33 | }, |
| 34 | 34 | 'msvs_settings': { |
| 35 | 35 | 'VCCLCompilerTool': { |
| 36 | + 'AdditionalOptions': '/Zc:rvalueCast', | |
| 37 | + 'DisableLanguageExtensions': 'true', | |
| 36 | 38 | 'TreatWChar_tAsBuiltInType': 'false', |
| 37 | 39 | 'WarningLevel': 3, |
| 38 | 40 | 'DebugInformationFormat': '3', # PDB |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | #include <string> |
| 12 | 12 | #include <algorithm> |
| 13 | 13 | #include <map> |
| 14 | +#include <unordered_set> | |
| 14 | 15 | #include <utils.h> |
| 15 | 16 | #include <vm_memory.h> |
| 16 | 17 | #include <vm_asm.h> |
| @@ -383,9 +384,9 @@ namespace · 366 unmodified lines | ||
| 383 | 384 | |
| 384 | 385 | auto msg = std::stringstream{}; |
| 385 | 386 | auto module_funcs = cxt.dbg.get_module_functions(vm_id, name_to_match); |
| 386 | − msg << "Function name [PC range]\n"; | |
| 387 | + msg << "Function name [PC range]"; | |
| 387 | 388 | for (auto &f : module_funcs) |
| 388 | − msg << " " << f << "\n"; | |
| 389 | + msg << "\n " << f; | |
| 389 | 390 | |
| 390 | 391 | debug_print_info(msg.str()); |
| 391 | 392 | } |
| @@ -615,6 +616,7 @@ namespace · 223 unmodified lines | ||
| 615 | 616 | } |
| 616 | 617 | } |
| 617 | 618 | |
| 619 | + auto &dbg = cxt.dbg; | |
| 618 | 620 | const auto &r = *cxt.current_register; |
| 619 | 621 | const auto &code_section = r.module_ref->code_section; |
| 620 | 622 | |
| @@ -623,19 +625,19 @@ namespace · 2 unmodified lines | ||
| 623 | 625 | if (disassemble_length < 0) |
| 624 | 626 | { |
| 625 | 627 | const auto begin_maybe = r.pc - (-disassemble_length) + 1; |
| 626 | − begin_pc= static_cast<std::size_t>(std::max(begin_maybe, 0)); | |
| 628 | + begin_pc = static_cast<std::size_t>(std::max(begin_maybe, 0)); | |
| 627 | 629 | } |
| 628 | 630 | else |
| 629 | 631 | { |
| 630 | 632 | const auto end_maybe = static_cast<std::size_t>(r.pc + disassemble_length); |
| 631 | − end_pc = std::min(end_maybe, code_section.size()); | |
| 633 | + end_pc = std::min(end_maybe, code_section.size() - 1); | |
| 632 | 634 | } |
| 633 | 635 | |
| 634 | − auto resolved_pc = cxt.dbg.resolve_to_function_source_line(r.module_ref->module->vm_id, begin_pc, end_pc, symbol::function_name_format_t::name); | |
| 636 | + auto resolved_pc = dbg.resolve_to_function_source_line(r.module_ref->module->vm_id, begin_pc, end_pc, symbol::function_name_format_t::name); | |
| 635 | 637 | assert(resolved_pc.empty() || resolved_pc.size() == (end_pc - begin_pc + 1) && "Resolved PCs should have failed or match the PC count"); |
| 636 | 638 | |
| 637 | 639 | auto msg = std::stringstream{}; |
| 638 | − for (auto i = begin_pc; i < (end_pc + 1); ++i) | |
| 640 | + for (auto i = begin_pc; i <= end_pc; ++i) | |
| 639 | 641 | { |
| 640 | 642 | auto op = code_section[i].op; |
| 641 | 643 | |
| @@ -645,9 +647,9 @@ namespace · 3 unmodified lines | ||
| 645 | 647 | if (op.opcode == opcode_t::brkpt) |
| 646 | 648 | { |
| 647 | 649 | // Look up each of the known cookies to try and find the matching PC and module |
| 648 | − for (auto bp_cookie : cxt.dbg.breakpoint_cookies) | |
| 650 | + for (auto bp_cookie : dbg.breakpoint_cookies) | |
| 649 | 651 | { |
| 650 | − const auto details = cxt.dbg.controller->get_breakpoint_details(bp_cookie); | |
| 652 | + const auto details = dbg.controller->get_breakpoint_details(bp_cookie); | |
| 651 | 653 | if (details.pc == i && details.module == r.module_ref->module) |
| 652 | 654 | { |
| 653 | 655 | op.opcode = details.original_opcode; |
| @@ -660,9 +662,9 @@ namespace · 6 unmodified lines | ||
| 660 | 662 | // Print source location if resolved |
| 661 | 663 | if (!resolved_pc.empty()) |
| 662 | 664 | { |
| 663 | − const auto & r = resolved_pc[i - begin_pc]; | |
| 664 | − if (!r.empty()) | |
| 665 | − msg << r << "\n"; | |
| 665 | + const auto &rpc = resolved_pc[i - begin_pc]; | |
| 666 | + if (!rpc.empty()) | |
| 667 | + msg << rpc << "\n"; | |
| 666 | 668 | } |
| 667 | 669 | |
| 668 | 670 | msg << op_prefix << std::setw(5) << i << ": " << op << "\n"; |
| @@ -811,18 +813,47 @@ namespace · 142 unmodified lines | ||
| 811 | 813 | << console_modifiers::reset_all; |
| 812 | 814 | } |
| 813 | 815 | |
| 814 | − void set_value_cmd(const std::vector<std::string> &args, dbg_cmd_cxt_t &) | |
| 816 | + std::unordered_set<std::string> dbg_options = | |
| 815 | 817 | { |
| 816 | − if (args.size() == 0) | |
| 818 | + { "bp-cmd" } | |
| 819 | + }; | |
| 820 | + | |
| 821 | + void set_value_cmd(const std::vector<std::string> &args, dbg_cmd_cxt_t &cxt) | |
| 822 | + { | |
| 823 | + auto msg = std::stringstream{}; | |
| 824 | + if (args.size() == 1) | |
| 817 | 825 | { |
| 818 | − // [TODO] Print all options current state | |
| 826 | + msg << "Debug options\n"; | |
| 827 | + for (auto &option : dbg_options) | |
| 828 | + { | |
| 829 | + auto v = cxt.dbg.get_option(option); | |
| 830 | + msg << std::setw(16) << option | |
| 831 | + << ": " | |
| 832 | + << (v.empty() ? "<none>" : v) | |
| 833 | + << "\n"; | |
| 834 | + } | |
| 835 | + | |
| 836 | + debug_print_info(msg.str()); | |
| 819 | 837 | return; |
| 820 | 838 | } |
| 821 | − else if (0 == args[0].compare("help")) | |
| 839 | + | |
| 840 | + auto &curr_option = args[1]; | |
| 841 | + if (std::cend(dbg_options) == dbg_options.find(curr_option)) | |
| 842 | + throw debug_cmd_error_t{ "Invalid debug option" }; | |
| 843 | + | |
| 844 | + auto new_value = std::stringstream{}; | |
| 845 | + | |
| 846 | + // Reconstitute the parsed debug arguments - in-case of space breaks. | |
| 847 | + for (auto i = std::size_t{ 2 }; i < args.size(); ++i) | |
| 822 | 848 | { |
| 823 | − // [TODO] Print help for 'set' command | |
| 824 | − return; | |
| 849 | + new_value << args[i]; | |
| 850 | + | |
| 851 | + // For the last parsed arg | |
| 852 | + if (i + 1 < args.size()) | |
| 853 | + new_value << " "; | |
| 825 | 854 | } |
| 855 | + | |
| 856 | + cxt.dbg.set_option(curr_option, new_value.str()); | |
| 826 | 857 | } |
| 827 | 858 | |
| 828 | 859 | const dbg_cmd_t cmds[] = |
| @@ -844,7 +875,7 @@ namespace · 15 unmodified lines | ||
| 844 | 875 | { "d", "Disassemble the next/previous N instructions (default N = 4)", "d (-?[0-9]+)?", "d, d -4, d 5", cmd_disassemble }, |
| 845 | 876 | { "x", "Examine memory", "x [mp|fp] [0-9]+ ([0-9]+)?", "x mp 3, x fp 20 6", cmd_examine }, |
| 846 | 877 | |
| 847 | − //{ "set" , "Set a debugger option", "set [ _a-zA-Z0-9]*", "'set help' for available options", set_value_cmd }, | |
| 878 | + { "set" , "Set a debug option", "set [ _a-zA-Z0-9]*", "'set' for available options", set_value_cmd }, | |
| 848 | 879 | { "?", "Print help", nullptr, nullptr, cmd_help }, |
| 849 | 880 | |
| 850 | 881 | // Undocumented commands |
| @@ -865,8 +896,8 @@ namespace · 14 unmodified lines | ||
| 865 | 896 | |
| 866 | 897 | void print_help() |
| 867 | 898 | { |
| 868 | − auto ss = std::stringstream{}; | |
| 869 | − ss << "Commands:\n"; | |
| 899 | + auto msg = std::stringstream{}; | |
| 900 | + msg << "Commands:\n"; | |
| 870 | 901 | for (auto i = std::size_t{}; i < sizeof(cmds) / sizeof(cmds[0]); ++i) |
| 871 | 902 | { |
| 872 | 903 | auto &c = cmds[i]; |
| @@ -875,16 +906,33 @@ namespace · 2 unmodified lines | ||
| 875 | 906 | if (c.description == nullptr) |
| 876 | 907 | continue; |
| 877 | 908 | |
| 878 | − ss << " " << c.cmd << "\t" << c.description << "\n"; | |
| 909 | + msg << " " << c.cmd << "\t" << c.description << "\n"; | |
| 879 | 910 | |
| 880 | 911 | if (c.syntax != nullptr) |
| 881 | − ss << "\t Syntax: " << c.syntax << "\n"; | |
| 912 | + msg << "\t Syntax: " << c.syntax << "\n"; | |
| 882 | 913 | |
| 883 | 914 | if (c.example != nullptr) |
| 884 | − ss << "\t Example(s): " << c.example << "\n"; | |
| 915 | + msg << "\t Example(s): " << c.example << "\n"; | |
| 885 | 916 | } |
| 886 | 917 | |
| 887 | − debug_print_info(ss.str()); | |
| 918 | + debug_print_info(msg.str()); | |
| 919 | + } | |
| 920 | + | |
| 921 | + void execute_single_command(dbg_cmd_cxt_t &cxt, const std::string &cmd) | |
| 922 | + { | |
| 923 | + const auto cmd_tokens = util::split(cmd); | |
| 924 | + if (cmd_tokens.empty()) | |
| 925 | + return; | |
| 926 | + | |
| 927 | + try | |
| 928 | + { | |
| 929 | + auto cmd_exec = find_cmd(cmd_tokens[0]); | |
| 930 | + cmd_exec(cmd_tokens, cxt); | |
| 931 | + } | |
| 932 | + catch (const debug_cmd_error_t &e) | |
| 933 | + { | |
| 934 | + debug_print_error(e.what()); | |
| 935 | + } | |
| 888 | 936 | } |
| 889 | 937 | |
| 890 | 938 | void prompt(debugger &debugger, const vm_registers_t &r) |
| @@ -910,21 +958,11 @@ namespace · 19 unmodified lines | ||
| 910 | 958 | << console_modifiers::reset_all; |
| 911 | 959 | |
| 912 | 960 | std::getline(std::cin, cmd); |
| 913 | − const auto cmd_tokens = util::split(cmd); | |
| 914 | − if (cmd_tokens.empty()) | |
| 915 | − continue; | |
| 916 | 961 | |
| 917 | − try | |
| 918 | − { | |
| 919 | − auto cmd_exec = find_cmd(cmd_tokens[0]); | |
| 920 | − cmd_exec(cmd_tokens, cxt); | |
| 921 | − if (cxt.exit_break) | |
| 922 | − break; | |
| 923 | − } | |
| 924 | − catch (const debug_cmd_error_t &e) | |
| 925 | − { | |
| 926 | − debug_print_error(e.what()); | |
| 927 | − } | |
| 962 | + assert(!cxt.exit_break && "Pre-condition on exit_break state before execute failed"); | |
| 963 | + execute_single_command(cxt, cmd); | |
| 964 | + if (cxt.exit_break) | |
| 965 | + break; | |
| 928 | 966 | } |
| 929 | 967 | |
| 930 | 968 | debugger.controller->resume_all_threads(); |
| @@ -1019,6 +1057,20 @@ bool debugger::symbols_exist(disvm::runtime::module_id_t vm_id) const · 88 unmodified lines | ||
| 1019 | 1057 | return _vm_id_to_symbol_info.find(vm_id) != std::cend(_vm_id_to_symbol_info); |
| 1020 | 1058 | } |
| 1021 | 1059 | |
| 1060 | +std::string debugger::get_option(const std::string &option) const | |
| 1061 | +{ | |
| 1062 | + auto iter = _debugger_options.find(option); | |
| 1063 | + if (iter == std::cend(_debugger_options)) | |
| 1064 | + return{}; | |
| 1065 | + | |
| 1066 | + return iter->second; | |
| 1067 | +} | |
| 1068 | + | |
| 1069 | +void debugger::set_option(const std::string &option, std::string value) | |
| 1070 | +{ | |
| 1071 | + _debugger_options[option] = std::move(value); | |
| 1072 | +} | |
| 1073 | + | |
| 1022 | 1074 | void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id) |
| 1023 | 1075 | { |
| 1024 | 1076 | _tool_id = tool_id; |
| @@ -1115,8 +1167,12 @@ void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id) · 90 unmodified lines | ||
| 1115 | 1167 | |
| 1116 | 1168 | debug_print_info(ss.str()); |
| 1117 | 1169 | |
| 1118 | − auto reg_str = registers_to_string(*cxt.value1.registers); | |
| 1119 | − debug_print_info(reg_str); | |
| 1170 | + const auto bp_cmd = get_option({ "bp-cmd" }); | |
| 1171 | + if (!bp_cmd.empty()) | |
| 1172 | + { | |
| 1173 | + dbg_cmd_cxt_t dbg_cxt{ *this, *cxt.value1.registers }; | |
| 1174 | + execute_single_command(dbg_cxt, bp_cmd); | |
| 1175 | + } | |
| 1120 | 1176 | |
| 1121 | 1177 | prompt(*this, *cxt.value1.registers); |
| 1122 | 1178 | })); |
| @@ -1163,7 +1219,7 @@ void debugger::load_symbols(const disvm::loaded_vm_module_t &loaded_mod) · 40 unmodified lines | ||
| 1163 | 1219 | catch (const std::runtime_error &e) |
| 1164 | 1220 | { |
| 1165 | 1221 | // File with assumed symbol name/extension is not the correct format |
| 1166 | − std::stringstream msg; | |
| 1222 | + auto msg = std::stringstream{}; | |
| 1167 | 1223 | msg << "Assumed symbol file '" |
| 1168 | 1224 | << symbol_path_maybe |
| 1169 | 1225 | << "' has invalid symbol format. (" |
| @@ -1178,7 +1234,7 @@ void debugger::load_symbols(const disvm::loaded_vm_module_t &loaded_mod) · 8 unmodified lines | ||
| 1178 | 1234 | || symbol_data->get_instruction_count() != m->code_section.size()) |
| 1179 | 1235 | { |
| 1180 | 1236 | // Symbol file does not match the loaded modules - stale file? |
| 1181 | − std::stringstream msg; | |
| 1237 | + auto msg = std::stringstream{}; | |
| 1182 | 1238 | msg << "Symbol file '" |
| 1183 | 1239 | << symbol_path_maybe |
| 1184 | 1240 | << "' does not match loaded module '" |
| @@ -1193,7 +1249,7 @@ void debugger::load_symbols(const disvm::loaded_vm_module_t &loaded_mod) · 8 unmodified lines | ||
| 1193 | 1249 | auto symbol_iter = symbol_data->get_pc_iter(); |
| 1194 | 1250 | _vm_id_to_symbol_info[vm_id] = { std::move(symbol_data), std::move(symbol_iter) }; |
| 1195 | 1251 | |
| 1196 | − std::stringstream msg; | |
| 1252 | + auto msg = std::stringstream{}; | |
| 1197 | 1253 | msg << "Symbol file '" |
| 1198 | 1254 | << symbol_path_maybe |
| 1199 | 1255 | << "' loaded for '" |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <string> |
| 14 | 14 | #include <memory> |
| 15 | 15 | #include <disvm.h> |
| 16 | +#include <vm_asm.h> | |
| 16 | 17 | #include <vm_tools.h> |
| 17 | 18 | #include <utils.h> |
| 18 | 19 | |
| @@ -48,6 +49,10 @@ public: · 29 unmodified lines | ||
| 48 | 49 | // Check if the supplied module ID has symbols loaded |
| 49 | 50 | bool symbols_exist(disvm::runtime::module_id_t vm_id) const; |
| 50 | 51 | |
| 52 | + // Get/set debugger option | |
| 53 | + std::string get_option(const std::string &option) const; | |
| 54 | + void set_option(const std::string &option, std::string value); | |
| 55 | + | |
| 51 | 56 | public: // vm_tool_t |
| 52 | 57 | void on_load(disvm::runtime::vm_tool_controller_t &, std::size_t tool_id) override; |
| 53 | 58 | |
| @@ -71,6 +76,7 @@ private: · 17 unmodified lines | ||
| 71 | 76 | }; |
| 72 | 77 | |
| 73 | 78 | std::unordered_map<std::size_t, symbol_info_t> _vm_id_to_symbol_info; |
| 79 | + std::unordered_map<std::string, std::string> _debugger_options; | |
| 74 | 80 | }; |
| 75 | 81 | |
| 76 | −#endif // _DISVM_SRC_EXEC_EXEC_H_ | |
| 82 | +#endif // _DISVM_SRC_EXEC_EXEC_H_ | |
| @@ -11,7 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | #include <builtin_module.h> |
| 12 | 12 | #include <debug.h> |
| 13 | 13 | #include <exceptions.h> |
| 14 | −#include <vm_asm.h> | |
| 14 | +#include <vm_asm_sigkind.h> | |
| 15 | 15 | #include <vm_version.h> |
| 16 | 16 | #include "exec.h" |
| 17 | 17 | |
| @@ -21,6 +21,12 @@ using namespace disvm::assembly::sigkind; · 3 unmodified lines | ||
| 21 | 21 | |
| 22 | 22 | namespace |
| 23 | 23 | { |
| 24 | + template<int L> | |
| 25 | + std::unique_ptr<vm_string_t> create_string_from_const(const char(&ca)[L]) | |
| 26 | + { | |
| 27 | + return std::make_unique<vm_string_t>(L - 1, reinterpret_cast<const uint8_t*>(ca)); | |
| 28 | + } | |
| 29 | + | |
| 24 | 30 | // Entry frame layout |
| 25 | 31 | struct vm_entry_frame_t final : public vm_frame_base_alloc_t |
| 26 | 32 | { |
| @@ -35,24 +41,17 @@ namespace · 8 unmodified lines | ||
| 35 | 41 | |
| 36 | 42 | std::unique_ptr<vm_module_t> create_entry_module(vm_t &vm, const std::vector<char *> &vm_args) |
| 37 | 43 | { |
| 38 | − if (vm_args.size() == 0) | |
| 39 | − throw vm_user_exception{ "Entry module not supplied" }; | |
| 40 | − | |
| 41 | 44 | // Convert arguments to a list |
| 42 | 45 | vm_string_t *command_module_path = nullptr; |
| 43 | − vm_list_t *args = nullptr; | |
| 44 | − vm_list_t *last = nullptr; | |
| 45 | − for (auto i = std::size_t{ 0 }; i < vm_args.size(); ++i) | |
| 46 | + vm_list_t *mod_args = new vm_list_t{ intrinsic_type_desc::type<vm_string_t>() }; | |
| 47 | + vm_list_t *last = mod_args; | |
| 48 | + for (auto raw_arg : vm_args) | |
| 46 | 49 | { |
| 47 | − auto tmp = vm_args[i]; | |
| 48 | − auto arg = new vm_string_t{ std::strlen(tmp), reinterpret_cast<uint8_t *>(tmp) }; | |
| 49 | − if (args == nullptr) | |
| 50 | + auto curr_arg = new vm_string_t{ std::strlen(raw_arg), reinterpret_cast<uint8_t *>(raw_arg) }; | |
| 51 | + if (command_module_path == nullptr) | |
| 50 | 52 | { |
| 51 | 53 | // First argument is the module to load |
| 52 | − command_module_path = arg; | |
| 53 | − assert(last == nullptr); | |
| 54 | − args = new vm_list_t{ intrinsic_type_desc::type<vm_string_t>() }; | |
| 55 | − last = args; | |
| 54 | + command_module_path = curr_arg; | |
| 56 | 55 | } |
| 57 | 56 | else |
| 58 | 57 | { |
| @@ -63,10 +62,11 @@ namespace · 4 unmodified lines | ||
| 63 | 62 | last = new_tail; |
| 64 | 63 | } |
| 65 | 64 | |
| 66 | − pt_ref(last->value()) = arg->get_allocation(); | |
| 65 | + pt_ref(last->value()) = curr_arg->get_allocation(); | |
| 67 | 66 | } |
| 68 | 67 | |
| 69 | − assert(args != nullptr); | |
| 68 | + if (command_module_path == nullptr) | |
| 69 | + throw vm_user_exception{ "Entry module not supplied" }; | |
| 70 | 70 | |
| 71 | 71 | // Pre-load the command module in the VM. |
| 72 | 72 | command_module = vm.load_module(command_module_path->str()); |
| @@ -79,9 +79,7 @@ namespace · 6 unmodified lines | ||
| 79 | 79 | e.header.entry_pc = 0; |
| 80 | 80 | e.header.entry_type = 0; |
| 81 | 81 | e.header.runtime_flag = (runtime_flags_t::has_import); |
| 82 | − | |
| 83 | − std::array<uint8_t, 8> mod_name = { "_entry_" }; | |
| 84 | − e.module_name = std::make_unique<vm_string_t>(mod_name.size() - 1, mod_name.data()); | |
| 82 | + e.module_name = create_string_from_const("_entry_"); | |
| 85 | 83 | |
| 86 | 84 | // Inherit the stack extent from the command module and add the entry frame size. |
| 87 | 85 | e.header.stack_extent = command_module->header.stack_extent + sizeof(vm_entry_frame_t); |
| @@ -99,7 +97,7 @@ namespace · 11 unmodified lines | ||
| 99 | 97 | // Take a reference on the command module path and store it on the entry frame |
| 100 | 98 | command_module_path->add_ref(); |
| 101 | 99 | mp_base[0] = command_module_path->get_allocation(); |
| 102 | − mp_base[1] = args->get_allocation(); | |
| 100 | + mp_base[1] = mod_args->get_allocation(); | |
| 103 | 101 | |
| 104 | 102 | // Define the frame offset for the argument |
| 105 | 103 | const auto first_arg_offset = vm_frame_constants::limbo_first_arg_register_offset(); |
| @@ -168,9 +166,7 @@ namespace · 62 unmodified lines | ||
| 168 | 166 | assert(exec_init_sig == sig_stream_t::compute_signature_hash("f(Ls)n")); |
| 169 | 167 | #endif |
| 170 | 168 | func.sig = exec_init_sig; |
| 171 | − | |
| 172 | − std::array<uint8_t, 5> func_name = { "init" }; | |
| 173 | − func.name = std::make_unique<vm_string_t>(func_name.size() - 1, func_name.data()); | |
| 169 | + func.name = create_string_from_const("init"); | |
| 174 | 170 | |
| 175 | 171 | import_vm_module_t import{}; |
| 176 | 172 | import.functions.push_back(std::move(func)); |
| @@ -156,4 +156,4 @@ namespace disvm · 155 unmodified lines | ||
| 156 | 156 | } |
| 157 | 157 | } |
| 158 | 158 | |
| 159 | −#endif // _DISVM_SRC_INCLUDE_BUFFERED_READER_H_ | |
| 159 | +#endif // _DISVM_SRC_INCLUDE_BUFFERED_READER_H_ | |
| @@ -118,4 +118,4 @@ namespace disvm · 117 unmodified lines | ||
| 118 | 118 | } |
| 119 | 119 | } |
| 120 | 120 | |
| 121 | −#endif // _DISVM_SRC_INCLUDE_BUILTIN_MODULE_H_ | |
| 121 | +#endif // _DISVM_SRC_INCLUDE_BUILTIN_MODULE_H_ | |
| @@ -97,4 +97,4 @@ namespace disvm · 96 unmodified lines | ||
| 97 | 97 | } |
| 98 | 98 | } |
| 99 | 99 | |
| 100 | −#endif // _DISVM_SRC_INCLUDE_DEBUG_H_ | |
| 100 | +#endif // _DISVM_SRC_INCLUDE_DEBUG_H_ | |
| @@ -125,4 +125,4 @@ namespace disvm · 124 unmodified lines | ||
| 125 | 125 | }; |
| 126 | 126 | } |
| 127 | 127 | |
| 128 | −#endif // _DISVM_SRC_INCLUDE_DISVM_H_ | |
| 128 | +#endif // _DISVM_SRC_INCLUDE_DISVM_H_ | |
| @@ -143,4 +143,4 @@ namespace disvm · 142 unmodified lines | ||
| 143 | 143 | } |
| 144 | 144 | } |
| 145 | 145 | |
| 146 | −#endif // _DISVM_SRC_INCLUDE_EXCEPTIONS_H_ | |
| 146 | +#endif // _DISVM_SRC_INCLUDE_EXCEPTIONS_H_ | |
| @@ -26,4 +26,4 @@ namespace disvm · 25 unmodified lines | ||
| 26 | 26 | } |
| 27 | 27 | } |
| 28 | 28 | |
| 29 | −#endif // _DISVM_SRC_INCLUDE_MODULE_READER_H_ | |
| 29 | +#endif // _DISVM_SRC_INCLUDE_MODULE_READER_H_ | |
| @@ -199,4 +199,4 @@ namespace disvm · 198 unmodified lines | ||
| 199 | 199 | }; |
| 200 | 200 | } |
| 201 | 201 | |
| 202 | −#endif // _DISVM_SRC_INCLUDE_OPCODES_H_ | |
| 202 | +#endif // _DISVM_SRC_INCLUDE_OPCODES_H_ | |
| @@ -54,4 +54,4 @@ namespace disvm · 53 unmodified lines | ||
| 54 | 54 | } |
| 55 | 55 | } |
| 56 | 56 | |
| 57 | −#endif // _DISVM_SRC_INCLUDE_UTF8_H_ | |
| 57 | +#endif // _DISVM_SRC_INCLUDE_UTF8_H_ | |
| @@ -78,4 +78,4 @@ inline TYPE operator ^ (TYPE a, TYPE b) { return static_cast<TYPE>(static_cast<s · 77 unmodified lines | ||
| 78 | 78 | inline TYPE &operator ^= (TYPE &a, TYPE b) { a = a ^ b; return a; } \ |
| 79 | 79 | inline TYPE operator ~ (TYPE a) { return static_cast<TYPE>(~static_cast<std::underlying_type_t<TYPE>>(a)); } |
| 80 | 80 | |
| 81 | −#endif // _DISVM_SRC_INCLUDE_UTILS_H_ | |
| 81 | +#endif // _DISVM_SRC_INCLUDE_UTILS_H_ | |
| @@ -8,8 +8,6 @@ · 7 unmodified lines | ||
| 8 | 8 | #define _DISVM_SRC_INCLUDE_VM_ASM_H_ |
| 9 | 9 | |
| 10 | 10 | #include <iosfwd> |
| 11 | −#include <sstream> | |
| 12 | −#include <cassert> | |
| 13 | 11 | #include <cstdint> |
| 14 | 12 | #include "opcodes.h" |
| 15 | 13 | #include "runtime.h" |
| @@ -34,349 +32,6 @@ namespace disvm · 18 unmodified lines | ||
| 34 | 32 | // Get the opcode from this string. |
| 35 | 33 | // If the supplied string cannot be resolved or if it is null, the 'invalid' opcode is returned. |
| 36 | 34 | disvm::opcode_t token_to_opcode(const char *); |
| 37 | − | |
| 38 | − // Namespace named after enum type in Limbo compiler | |
| 39 | − // Source: limbo/types.c | |
| 40 | − namespace sigkind | |
| 41 | − { | |
| 42 | − // Signature stream | |
| 43 | − class sig_stream_t final | |
| 44 | − { | |
| 45 | − public: // static | |
| 46 | − static uint32_t compute_signature_hash(const char *); | |
| 47 | − | |
| 48 | − // Type delimiter | |
| 49 | − static const char delim; | |
| 50 | − | |
| 51 | − public: | |
| 52 | − std::string get_signature() const; | |
| 53 | − | |
| 54 | − uint32_t get_signature_hash() const; | |
| 55 | − | |
| 56 | − sig_stream_t &operator<<(const char); | |
| 57 | − sig_stream_t &operator<<(const char *); | |
| 58 | − sig_stream_t &operator<<(const uint32_t); | |
| 59 | − sig_stream_t &operator<<(const sig_stream_t &); | |
| 60 | − | |
| 61 | − private: | |
| 62 | − mutable std::stringstream _ss; | |
| 63 | − }; | |
| 64 | − | |
| 65 | − // Type context modifiers | |
| 66 | − enum class modifier_id_t : uint8_t | |
| 67 | − { | |
| 68 | − self = 'S', | |
| 69 | − cycle = 'y', | |
| 70 | − }; | |
| 71 | − | |
| 72 | − sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::modifier_id_t &); | |
| 73 | − | |
| 74 | − // Instrinsic VM types | |
| 75 | − enum class type_id_t : uint8_t | |
| 76 | − { | |
| 77 | − unknown = 0, // This will be interpreted as a 'null' value which will help debug where the type building failed. | |
| 78 | − none = 'n', | |
| 79 | − byte = 'b', | |
| 80 | − integer = 'i', | |
| 81 | − real = 'r', | |
| 82 | − big = 'B', | |
| 83 | − string = 's', | |
| 84 | − poly = 'P', | |
| 85 | − fixed = 'x', | |
| 86 | − array = 'A', | |
| 87 | − ref = 'R', | |
| 88 | − list = 'L', | |
| 89 | − channel = 'C', | |
| 90 | − adt = 'a', | |
| 91 | − adt_pick_tag = 'p', | |
| 92 | − tuple = 't', | |
| 93 | − module = 'm', | |
| 94 | − function = 'f', | |
| 95 | − function_varargs = 0xff, // "f*" | |
| 96 | − }; | |
| 97 | − | |
| 98 | − sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::type_id_t &); | |
| 99 | − | |
| 100 | − template<type_id_t T> | |
| 101 | − struct Tbasic_type | |
| 102 | − { | |
| 103 | − static const type_id_t id; | |
| 104 | − | |
| 105 | − constexpr operator type_id_t() const | |
| 106 | − { | |
| 107 | − return Tbasic_type::id; | |
| 108 | − } | |
| 109 | − }; | |
| 110 | − | |
| 111 | − template<type_id_t T> | |
| 112 | − const type_id_t Tbasic_type<T>::id = T; | |
| 113 | − | |
| 114 | − using Tnone = Tbasic_type<type_id_t::none>; | |
| 115 | − using Tbyte = Tbasic_type<type_id_t::byte>; | |
| 116 | − using Tinteger = Tbasic_type<type_id_t::integer>; | |
| 117 | − using Treal = Tbasic_type<type_id_t::real>; | |
| 118 | − using Tbig = Tbasic_type<type_id_t::big>; | |
| 119 | − using Tstring = Tbasic_type<type_id_t::string>; | |
| 120 | − using Tpoly = Tbasic_type<type_id_t::poly>; | |
| 121 | − | |
| 122 | − class Tfixed final : public Tbasic_type<type_id_t::fixed> | |
| 123 | − { | |
| 124 | − public: | |
| 125 | − Tfixed(double scale); | |
| 126 | − | |
| 127 | − friend sig_stream_t &operator<<(sig_stream_t &os, const Tfixed &); | |
| 128 | − | |
| 129 | − private: | |
| 130 | − const double _scale; | |
| 131 | − }; | |
| 132 | − | |
| 133 | − sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tfixed &); | |
| 134 | − | |
| 135 | − // Type that contains/modifies another type | |
| 136 | − template <type_id_t ID> | |
| 137 | − class Tbasic_aggregate_type : public Tbasic_type<ID> | |
| 138 | − { | |
| 139 | − public: | |
| 140 | − template<typename U> | |
| 141 | − static Tbasic_aggregate_type create(const U &type) | |
| 142 | − { | |
| 143 | − sig_stream_t ss; | |
| 144 | − ss << Tbasic_type<ID>::id << type; | |
| 145 | − | |
| 146 | − return Tbasic_aggregate_type{ ss }; | |
| 147 | − } | |
| 148 | − | |
| 149 | − friend sig_stream_t &operator<<(sig_stream_t &, const Tbasic_aggregate_type &); | |
| 150 | − | |
| 151 | − private: | |
| 152 | − sig_stream_t _s; | |
| 153 | − Tbasic_aggregate_type(sig_stream_t &s) : _s{ std::move(s) } { } | |
| 154 | − }; | |
| 155 | − | |
| 156 | − using Tarray = Tbasic_aggregate_type<type_id_t::array>; | |
| 157 | − using Tref = Tbasic_aggregate_type<type_id_t::ref>; | |
| 158 | − using Tlist = Tbasic_aggregate_type<type_id_t::list>; | |
| 159 | − using Tchannel = Tbasic_aggregate_type<type_id_t::channel>; | |
| 160 | − | |
| 161 | − sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tarray &); | |
| 162 | − sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tref &); | |
| 163 | − sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tlist &); | |
| 164 | − sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tchannel &); | |
| 165 | − | |
| 166 | − // Reference to another previously defined type in the current signature | |
| 167 | − class Ttype_ref final | |
| 168 | − { | |
| 169 | − public: // static | |
| 170 | − static const char id; | |
| 171 | − | |
| 172 | − public: | |
| 173 | − Ttype_ref(uint32_t num); | |
| 174 | − | |
| 175 | − friend sig_stream_t &operator<<(sig_stream_t &os, const Ttype_ref &); | |
| 176 | − | |
| 177 | − private: | |
| 178 | − const uint32_t _num; | |
| 179 | − }; | |
| 180 | − | |
| 181 | − sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Ttype_ref &); | |
| 182 | − | |
| 183 | − // Named member type | |
| 184 | − class Tm final | |
| 185 | − { | |
| 186 | − public: | |
| 187 | − template <typename T> | |
| 188 | − Tm(const char *name, const T &type) | |
| 189 | − { | |
| 190 | − _s << name << ':' << type; | |
| 191 | − } | |
| 192 | − | |
| 193 | − friend sig_stream_t &operator<<(sig_stream_t &os, const Tm &); | |
| 194 | − | |
| 195 | − private: | |
| 196 | − sig_stream_t _s; | |
| 197 | − }; | |
| 198 | − | |
| 199 | − sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tm &); | |
| 200 | − | |
| 201 | − inline void nested_type(const sig_stream_t &) | |
| 202 | − { | |
| 203 | − return; | |
| 204 | − } | |
| 205 | − | |
| 206 | − template<typename T, typename ...S> | |
| 207 | − void nested_type(sig_stream_t &ss, const T &t, const S&...s) | |
| 208 | − { | |
| 209 | − ss << t; | |
| 210 | − nested_type(ss, s...); | |
| 211 | − } | |
| 212 | − | |
| 213 | − template<typename T1, typename T2, typename ...S> | |
| 214 | − void nested_type(sig_stream_t &ss, const T1 &t1, const T2 &t2, const S&...s) | |
| 215 | − { | |
| 216 | − ss << t1 << sig_stream_t::delim; | |
| 217 | − nested_type(ss, t2, s...); | |
| 218 | − } | |
| 219 | − | |
| 220 | − // Type whose definition depends on contained types | |
| 221 | − template <type_id_t ID> | |
| 222 | − class Tnested_aggregate_type : public Tbasic_type<ID> | |
| 223 | − { | |
| 224 | − public: // static | |
| 225 | − static const char begin; | |
| 226 | − static const char end; | |
| 227 | − | |
| 228 | − template<typename ...NT> | |
| 229 | − static Tnested_aggregate_type create(const NT&... nestedTypes) | |
| 230 | − { | |
| 231 | − sig_stream_t ss; | |
| 232 | − ss << Tbasic_type<ID>::id << Tnested_aggregate_type::begin; | |
| 233 | − | |
| 234 | − nested_type(ss, nestedTypes...); | |
| 235 | − | |
| 236 | − ss << Tnested_aggregate_type::end; | |
| 237 | − | |
| 238 | − return Tnested_aggregate_type{ ss }; | |
| 239 | − } | |
| 240 | − | |
| 241 | − public: | |
| 242 | − Tnested_aggregate_type(sig_stream_t &s) | |
| 243 | − : _s{ std::move(s) } | |
| 244 | − { } | |
| 245 | − | |
| 246 | − friend sig_stream_t &operator<<(sig_stream_t &, const Tnested_aggregate_type &); | |
| 247 | − | |
| 248 | − private: | |
| 249 | − sig_stream_t _s; | |
| 250 | − }; | |
| 251 | − | |
| 252 | − using Ttuple = Tnested_aggregate_type<type_id_t::tuple>; | |
| 253 | − using Tmodule = Tnested_aggregate_type<type_id_t::module>; | |
| 254 | − | |
| 255 | − sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Ttuple &); | |
| 256 | − sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tmodule &); | |
| 257 | − | |
| 258 | − // Abstract data type (ADT) pick tag | |
| 259 | − // Note: This type should only be a part of an ADT instance. | |
| 260 | − class Tadt_pick_tag final : public Tbasic_type<type_id_t::adt_pick_tag> | |
| 261 | − { | |
| 262 | − public: // static | |
| 263 | − static const char *tag_delim; | |
| 264 | − static const char begin; | |
| 265 | − static const char end; | |
| 266 | − | |
| 267 | − static Tadt_pick_tag create(const char *pick_tag, uint32_t adt_ref, std::initializer_list<const Tm> tms); | |
| 268 | − | |
| 269 | − friend sig_stream_t &operator<<(sig_stream_t &, const Tadt_pick_tag &); | |
| 270 | − | |
| 271 | − private: | |
| 272 | − sig_stream_t _s; | |
| 273 | − Tadt_pick_tag(sig_stream_t &s) : _s{ std::move(s) } { } | |
| 274 | − }; | |
| 275 | − | |
| 276 | − sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tadt_pick_tag &); | |
| 277 | − | |
| 278 | − // Abstract data type (ADT) | |
| 279 | − class Tadt final : public Tnested_aggregate_type<type_id_t::adt> | |
| 280 | − { | |
| 281 | − public: // static | |
| 282 | − // Unhide base class version of function | |
| 283 | − using Tnested_aggregate_type::create; | |
| 284 | − | |
| 285 | − // Create an ADT with a single pick tag | |
| 286 | − static Tadt create(const Tadt_pick_tag &p) | |
| 287 | − { | |
| 288 | − sig_stream_t ss; | |
| 289 | − ss << Tbasic_type::id | |
| 290 | − << Tadt::begin | |
| 291 | − << sig_stream_t::delim | |
| 292 | − << p | |
| 293 | − << Tadt::end; | |
| 294 | − | |
| 295 | − return Tadt{ ss }; | |
| 296 | − } | |
| 297 | − | |
| 298 | − template<typename T, typename ...NT> | |
| 299 | − static Tadt create(const Tadt_pick_tag &p, const T &t, const NT&... nestedTypes) | |
| 300 | − { | |
| 301 | − // [SPEC] When generating type signatures, the Limbo compiler | |
| 302 | − // doesn't identify the case where a pick tag is the first type | |
| 303 | − // so it always prefixes the nested signature with a leading ','. | |
| 304 | − // We special case this scenario to maintain compatibility. The | |
| 305 | − // single pick tag for an ADT must also be handled (above). | |
| 306 | − sig_stream_t ss; | |
| 307 | − ss << Tbasic_type::id | |
| 308 | − << Tadt::begin | |
| 309 | − << sig_stream_t::delim | |
| 310 | − << p | |
| 311 | − << sig_stream_t::delim; | |
| 312 | − | |
| 313 | − nested_type(ss, t, nestedTypes...); | |
| 314 | − | |
| 315 | − ss << Tadt::end; | |
| 316 | − | |
| 317 | − return Tadt{ ss }; | |
| 318 | − } | |
| 319 | − | |
| 320 | − private: | |
| 321 | − Tadt(sig_stream_t &s) : Tnested_aggregate_type{ s } { } | |
| 322 | − }; | |
| 323 | − | |
| 324 | − sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tnested_aggregate_type<type_id_t::adt> &); | |
| 325 | − | |
| 326 | − // Function type | |
| 327 | − template<type_id_t T> | |
| 328 | − class Tfunction_base_type final : public Tbasic_type<T> | |
| 329 | − { | |
| 330 | − public: // static | |
| 331 | − static const char begin; | |
| 332 | − static const char end; | |
| 333 | − | |
| 334 | − template<typename ...AT> | |
| 335 | − static Tfunction_base_type create(AT... argTypes) | |
| 336 | − { | |
| 337 | − Tfunction_base_type a; | |
| 338 | − a._s << Tfunction_base_type::id << Tfunction_base_type::begin; | |
| 339 | − | |
| 340 | − nested_type(a._s, argTypes...); | |
| 341 | − | |
| 342 | − a._s << Tfunction_base_type::end; | |
| 343 | − return a; | |
| 344 | − } | |
| 345 | − | |
| 346 | − public: | |
| 347 | − template<typename RT> | |
| 348 | − Tfunction_base_type &returns(RT r) | |
| 349 | − { | |
| 350 | − assert(!_fully_defined && "Function type already complete"); | |
| 351 | − _s << r; | |
| 352 | − _fully_defined = true; | |
| 353 | − | |
| 354 | − return *this; | |
| 355 | − } | |
| 356 | − | |
| 357 | − friend sig_stream_t &operator<<(sig_stream_t &, Tfunction_base_type &); | |
| 358 | − friend sig_stream_t &operator<<(sig_stream_t &, const Tfunction_base_type &); | |
| 359 | − | |
| 360 | − private: | |
| 361 | − bool _fully_defined; | |
| 362 | − sig_stream_t _s; | |
| 363 | − Tfunction_base_type() : _fully_defined{ false } { } | |
| 364 | − }; | |
| 365 | − | |
| 366 | − template<type_id_t T> | |
| 367 | − const char Tfunction_base_type<T>::begin = '('; | |
| 368 | − | |
| 369 | − template<type_id_t T> | |
| 370 | − const char Tfunction_base_type<T>::end = ')'; | |
| 371 | − | |
| 372 | − using Tfunction = Tfunction_base_type<type_id_t::function>; | |
| 373 | − using Tfunction_varargs = Tfunction_base_type<type_id_t::function_varargs>; | |
| 374 | − | |
| 375 | − sig_stream_t &operator<<(sig_stream_t &, disvm::assembly::sigkind::Tfunction &); | |
| 376 | − sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tfunction &); | |
| 377 | − sig_stream_t &operator<<(sig_stream_t &, disvm::assembly::sigkind::Tfunction_varargs &); | |
| 378 | − sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tfunction_varargs &); | |
| 379 | − } | |
| 380 | 35 | } |
| 381 | 36 | |
| 382 | 37 | namespace symbol |
| @@ -495,4 +150,4 @@ namespace disvm · 112 unmodified lines | ||
| 495 | 150 | } |
| 496 | 151 | } |
| 497 | 152 | |
| 498 | −#endif // _DISVM_SRC_INCLUDE_VM_ASM_H_ | |
| 153 | +#endif // _DISVM_SRC_INCLUDE_VM_ASM_H_ | |
| @@ -0,0 +1,366 @@ | ||
| 1 | +// | |
| 2 | +// Dis VM | |
| 3 | +// File: vm_asm_sigkind.h | |
| 4 | +// Author: arr | |
| 5 | +// | |
| 6 | + | |
| 7 | +#ifndef _DISVM_SRC_INCLUDE_VM_ASM_SIGKIND_H_ | |
| 8 | +#define _DISVM_SRC_INCLUDE_VM_ASM_SIGKIND_H_ | |
| 9 | + | |
| 10 | +#include <iosfwd> | |
| 11 | +#include <sstream> | |
| 12 | +#include <cassert> | |
| 13 | +#include <cstdint> | |
| 14 | +#include "opcodes.h" | |
| 15 | +#include "runtime.h" | |
| 16 | + | |
| 17 | +namespace disvm | |
| 18 | +{ | |
| 19 | + namespace assembly | |
| 20 | + { | |
| 21 | + // Namespace named after enum type in Limbo compiler | |
| 22 | + // Source: limbo/types.c | |
| 23 | + namespace sigkind | |
| 24 | + { | |
| 25 | + // Signature stream | |
| 26 | + class sig_stream_t final | |
| 27 | + { | |
| 28 | + public: // static | |
| 29 | + static uint32_t compute_signature_hash(const char *); | |
| 30 | + | |
| 31 | + // Type delimiter | |
| 32 | + static const char delim; | |
| 33 | + | |
| 34 | + public: | |
| 35 | + std::string get_signature() const; | |
| 36 | + | |
| 37 | + uint32_t get_signature_hash() const; | |
| 38 | + | |
| 39 | + sig_stream_t &operator<<(const char); | |
| 40 | + sig_stream_t &operator<<(const char *); | |
| 41 | + sig_stream_t &operator<<(const uint32_t); | |
| 42 | + sig_stream_t &operator<<(const sig_stream_t &); | |
| 43 | + | |
| 44 | + private: | |
| 45 | + mutable std::stringstream _ss; | |
| 46 | + }; | |
| 47 | + | |
| 48 | + // Type context modifiers | |
| 49 | + enum class modifier_id_t : uint8_t | |
| 50 | + { | |
| 51 | + self = 'S', | |
| 52 | + cycle = 'y', | |
| 53 | + }; | |
| 54 | + | |
| 55 | + sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::modifier_id_t &); | |
| 56 | + | |
| 57 | + // Instrinsic VM types | |
| 58 | + enum class type_id_t : uint8_t | |
| 59 | + { | |
| 60 | + unknown = 0, // This will be interpreted as a 'null' value which will help debug where the type building failed. | |
| 61 | + none = 'n', | |
| 62 | + byte = 'b', | |
| 63 | + integer = 'i', | |
| 64 | + real = 'r', | |
| 65 | + big = 'B', | |
| 66 | + string = 's', | |
| 67 | + poly = 'P', | |
| 68 | + fixed = 'x', | |
| 69 | + array = 'A', | |
| 70 | + ref = 'R', | |
| 71 | + list = 'L', | |
| 72 | + channel = 'C', | |
| 73 | + adt = 'a', | |
| 74 | + adt_pick_tag = 'p', | |
| 75 | + tuple = 't', | |
| 76 | + module = 'm', | |
| 77 | + function = 'f', | |
| 78 | + function_varargs = 0xff, // "f*" | |
| 79 | + }; | |
| 80 | + | |
| 81 | + sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::type_id_t &); | |
| 82 | + | |
| 83 | + template<type_id_t T> | |
| 84 | + struct Tbasic_type | |
| 85 | + { | |
| 86 | + static const type_id_t id; | |
| 87 | + | |
| 88 | + constexpr operator type_id_t() const | |
| 89 | + { | |
| 90 | + return Tbasic_type::id; | |
| 91 | + } | |
| 92 | + }; | |
| 93 | + | |
| 94 | + template<type_id_t T> | |
| 95 | + const type_id_t Tbasic_type<T>::id = T; | |
| 96 | + | |
| 97 | + using Tnone = Tbasic_type<type_id_t::none>; | |
| 98 | + using Tbyte = Tbasic_type<type_id_t::byte>; | |
| 99 | + using Tinteger = Tbasic_type<type_id_t::integer>; | |
| 100 | + using Treal = Tbasic_type<type_id_t::real>; | |
| 101 | + using Tbig = Tbasic_type<type_id_t::big>; | |
| 102 | + using Tstring = Tbasic_type<type_id_t::string>; | |
| 103 | + using Tpoly = Tbasic_type<type_id_t::poly>; | |
| 104 | + | |
| 105 | + class Tfixed final : public Tbasic_type<type_id_t::fixed> | |
| 106 | + { | |
| 107 | + public: | |
| 108 | + Tfixed(double scale); | |
| 109 | + | |
| 110 | + friend sig_stream_t &operator<<(sig_stream_t &os, const Tfixed &); | |
| 111 | + | |
| 112 | + private: | |
| 113 | + const double _scale; | |
| 114 | + }; | |
| 115 | + | |
| 116 | + sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tfixed &); | |
| 117 | + | |
| 118 | + // Type that contains/modifies another type | |
| 119 | + template <type_id_t ID> | |
| 120 | + class Tbasic_aggregate_type : public Tbasic_type<ID> | |
| 121 | + { | |
| 122 | + public: | |
| 123 | + template<typename U> | |
| 124 | + static Tbasic_aggregate_type create(const U &type) | |
| 125 | + { | |
| 126 | + sig_stream_t ss; | |
| 127 | + ss << Tbasic_type<ID>::id << type; | |
| 128 | + | |
| 129 | + return Tbasic_aggregate_type{ ss }; | |
| 130 | + } | |
| 131 | + | |
| 132 | + friend sig_stream_t &operator<<(sig_stream_t &, const Tbasic_aggregate_type &); | |
| 133 | + | |
| 134 | + private: | |
| 135 | + sig_stream_t _s; | |
| 136 | + Tbasic_aggregate_type(sig_stream_t &s) : _s{ std::move(s) } { } | |
| 137 | + }; | |
| 138 | + | |
| 139 | + using Tarray = Tbasic_aggregate_type<type_id_t::array>; | |
| 140 | + using Tref = Tbasic_aggregate_type<type_id_t::ref>; | |
| 141 | + using Tlist = Tbasic_aggregate_type<type_id_t::list>; | |
| 142 | + using Tchannel = Tbasic_aggregate_type<type_id_t::channel>; | |
| 143 | + | |
| 144 | + sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tarray &); | |
| 145 | + sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tref &); | |
| 146 | + sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tlist &); | |
| 147 | + sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tchannel &); | |
| 148 | + | |
| 149 | + // Reference to another previously defined type in the current signature | |
| 150 | + class Ttype_ref final | |
| 151 | + { | |
| 152 | + public: // static | |
| 153 | + static const char id; | |
| 154 | + | |
| 155 | + public: | |
| 156 | + Ttype_ref(uint32_t num); | |
| 157 | + | |
| 158 | + friend sig_stream_t &operator<<(sig_stream_t &os, const Ttype_ref &); | |
| 159 | + | |
| 160 | + private: | |
| 161 | + const uint32_t _num; | |
| 162 | + }; | |
| 163 | + | |
| 164 | + sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Ttype_ref &); | |
| 165 | + | |
| 166 | + // Named member type | |
| 167 | + class Tm final | |
| 168 | + { | |
| 169 | + public: | |
| 170 | + template <typename T> | |
| 171 | + Tm(const char *name, const T &type) | |
| 172 | + { | |
| 173 | + _s << name << ':' << type; | |
| 174 | + } | |
| 175 | + | |
| 176 | + friend sig_stream_t &operator<<(sig_stream_t &os, const Tm &); | |
| 177 | + | |
| 178 | + private: | |
| 179 | + sig_stream_t _s; | |
| 180 | + }; | |
| 181 | + | |
| 182 | + sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tm &); | |
| 183 | + | |
| 184 | + inline void nested_type(const sig_stream_t &) | |
| 185 | + { | |
| 186 | + return; | |
| 187 | + } | |
| 188 | + | |
| 189 | + template<typename T, typename ...S> | |
| 190 | + void nested_type(sig_stream_t &ss, const T &t, const S&...s) | |
| 191 | + { | |
| 192 | + ss << t; | |
| 193 | + nested_type(ss, s...); | |
| 194 | + } | |
| 195 | + | |
| 196 | + template<typename T1, typename T2, typename ...S> | |
| 197 | + void nested_type(sig_stream_t &ss, const T1 &t1, const T2 &t2, const S&...s) | |
| 198 | + { | |
| 199 | + ss << t1 << sig_stream_t::delim; | |
| 200 | + nested_type(ss, t2, s...); | |
| 201 | + } | |
| 202 | + | |
| 203 | + // Type whose definition depends on contained types | |
| 204 | + template <type_id_t ID> | |
| 205 | + class Tnested_aggregate_type : public Tbasic_type<ID> | |
| 206 | + { | |
| 207 | + public: // static | |
| 208 | + static const char begin; | |
| 209 | + static const char end; | |
| 210 | + | |
| 211 | + template<typename ...NT> | |
| 212 | + static Tnested_aggregate_type create(const NT&... nestedTypes) | |
| 213 | + { | |
| 214 | + sig_stream_t ss; | |
| 215 | + ss << Tbasic_type<ID>::id << Tnested_aggregate_type::begin; | |
| 216 | + | |
| 217 | + nested_type(ss, nestedTypes...); | |
| 218 | + | |
| 219 | + ss << Tnested_aggregate_type::end; | |
| 220 | + | |
| 221 | + return Tnested_aggregate_type{ ss }; | |
| 222 | + } | |
| 223 | + | |
| 224 | + public: | |
| 225 | + Tnested_aggregate_type(sig_stream_t &s) | |
| 226 | + : _s{ std::move(s) } | |
| 227 | + { } | |
| 228 | + | |
| 229 | + friend sig_stream_t &operator<<(sig_stream_t &, const Tnested_aggregate_type &); | |
| 230 | + | |
| 231 | + private: | |
| 232 | + sig_stream_t _s; | |
| 233 | + }; | |
| 234 | + | |
| 235 | + using Ttuple = Tnested_aggregate_type<type_id_t::tuple>; | |
| 236 | + using Tmodule = Tnested_aggregate_type<type_id_t::module>; | |
| 237 | + | |
| 238 | + sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Ttuple &); | |
| 239 | + sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tmodule &); | |
| 240 | + | |
| 241 | + // Abstract data type (ADT) pick tag | |
| 242 | + // Note: This type should only be a part of an ADT instance. | |
| 243 | + class Tadt_pick_tag final : public Tbasic_type<type_id_t::adt_pick_tag> | |
| 244 | + { | |
| 245 | + public: // static | |
| 246 | + static const char *tag_delim; | |
| 247 | + static const char begin; | |
| 248 | + static const char end; | |
| 249 | + | |
| 250 | + static Tadt_pick_tag create(const char *pick_tag, uint32_t adt_ref, std::initializer_list<const Tm> tms); | |
| 251 | + | |
| 252 | + friend sig_stream_t &operator<<(sig_stream_t &, const Tadt_pick_tag &); | |
| 253 | + | |
| 254 | + private: | |
| 255 | + sig_stream_t _s; | |
| 256 | + Tadt_pick_tag(sig_stream_t &s) : _s{ std::move(s) } { } | |
| 257 | + }; | |
| 258 | + | |
| 259 | + sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tadt_pick_tag &); | |
| 260 | + | |
| 261 | + // Abstract data type (ADT) | |
| 262 | + class Tadt final : public Tnested_aggregate_type<type_id_t::adt> | |
| 263 | + { | |
| 264 | + public: // static | |
| 265 | + // Unhide base class version of function | |
| 266 | + using Tnested_aggregate_type::create; | |
| 267 | + | |
| 268 | + // Create an ADT with a single pick tag | |
| 269 | + static Tadt create(const Tadt_pick_tag &p) | |
| 270 | + { | |
| 271 | + sig_stream_t ss; | |
| 272 | + ss << Tbasic_type::id | |
| 273 | + << Tadt::begin | |
| 274 | + << sig_stream_t::delim | |
| 275 | + << p | |
| 276 | + << Tadt::end; | |
| 277 | + | |
| 278 | + return Tadt{ ss }; | |
| 279 | + } | |
| 280 | + | |
| 281 | + template<typename T, typename ...NT> | |
| 282 | + static Tadt create(const Tadt_pick_tag &p, const T &t, const NT&... nestedTypes) | |
| 283 | + { | |
| 284 | + // [SPEC] When generating type signatures, the Limbo compiler | |
| 285 | + // doesn't identify the case where a pick tag is the first type | |
| 286 | + // so it always prefixes the nested signature with a leading ','. | |
| 287 | + // We special case this scenario to maintain compatibility. The | |
| 288 | + // single pick tag for an ADT must also be handled (above). | |
| 289 | + sig_stream_t ss; | |
| 290 | + ss << Tbasic_type::id | |
| 291 | + << Tadt::begin | |
| 292 | + << sig_stream_t::delim | |
| 293 | + << p | |
| 294 | + << sig_stream_t::delim; | |
| 295 | + | |
| 296 | + nested_type(ss, t, nestedTypes...); | |
| 297 | + | |
| 298 | + ss << Tadt::end; | |
| 299 | + | |
| 300 | + return Tadt{ ss }; | |
| 301 | + } | |
| 302 | + | |
| 303 | + private: | |
| 304 | + Tadt(sig_stream_t &s) : Tnested_aggregate_type{ s } { } | |
| 305 | + }; | |
| 306 | + | |
| 307 | + sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tnested_aggregate_type<type_id_t::adt> &); | |
| 308 | + | |
| 309 | + // Function type | |
| 310 | + template<type_id_t T> | |
| 311 | + class Tfunction_base_type final : public Tbasic_type<T> | |
| 312 | + { | |
| 313 | + public: // static | |
| 314 | + static const char begin; | |
| 315 | + static const char end; | |
| 316 | + | |
| 317 | + template<typename ...AT> | |
| 318 | + static Tfunction_base_type create(AT... argTypes) | |
| 319 | + { | |
| 320 | + Tfunction_base_type a; | |
| 321 | + a._s << Tfunction_base_type::id << Tfunction_base_type::begin; | |
| 322 | + | |
| 323 | + nested_type(a._s, argTypes...); | |
| 324 | + | |
| 325 | + a._s << Tfunction_base_type::end; | |
| 326 | + return a; | |
| 327 | + } | |
| 328 | + | |
| 329 | + public: | |
| 330 | + template<typename RT> | |
| 331 | + Tfunction_base_type &returns(RT r) | |
| 332 | + { | |
| 333 | + assert(!_fully_defined && "Function type already complete"); | |
| 334 | + _s << r; | |
| 335 | + _fully_defined = true; | |
| 336 | + | |
| 337 | + return *this; | |
| 338 | + } | |
| 339 | + | |
| 340 | + friend sig_stream_t &operator<<(sig_stream_t &, Tfunction_base_type &); | |
| 341 | + friend sig_stream_t &operator<<(sig_stream_t &, const Tfunction_base_type &); | |
| 342 | + | |
| 343 | + private: | |
| 344 | + bool _fully_defined; | |
| 345 | + sig_stream_t _s; | |
| 346 | + Tfunction_base_type() : _fully_defined{ false } { } | |
| 347 | + }; | |
| 348 | + | |
| 349 | + template<type_id_t T> | |
| 350 | + const char Tfunction_base_type<T>::begin = '('; | |
| 351 | + | |
| 352 | + template<type_id_t T> | |
| 353 | + const char Tfunction_base_type<T>::end = ')'; | |
| 354 | + | |
| 355 | + using Tfunction = Tfunction_base_type<type_id_t::function>; | |
| 356 | + using Tfunction_varargs = Tfunction_base_type<type_id_t::function_varargs>; | |
| 357 | + | |
| 358 | + sig_stream_t &operator<<(sig_stream_t &, disvm::assembly::sigkind::Tfunction &); | |
| 359 | + sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tfunction &); | |
| 360 | + sig_stream_t &operator<<(sig_stream_t &, disvm::assembly::sigkind::Tfunction_varargs &); | |
| 361 | + sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tfunction_varargs &); | |
| 362 | + } | |
| 363 | + } | |
| 364 | +} | |
| 365 | + | |
| 366 | +#endif // _DISVM_SRC_INCLUDE_VM_ASM_SIGKIND_H_ | |
| @@ -131,4 +131,4 @@ namespace disvm · 130 unmodified lines | ||
| 131 | 131 | } |
| 132 | 132 | } |
| 133 | 133 | |
| 134 | −#endif // _DISVM_SRC_INCLUDE_VM_MEMORY_H_ | |
| 134 | +#endif // _DISVM_SRC_INCLUDE_VM_MEMORY_H_ | |
| @@ -95,4 +95,4 @@ namespace disvm · 94 unmodified lines | ||
| 95 | 95 | } |
| 96 | 96 | } |
| 97 | 97 | |
| 98 | −#endif // _DISVM_SRC_INCLUDE_VM_TOOLS_H_ | |
| 98 | +#endif // _DISVM_SRC_INCLUDE_VM_TOOLS_H_ | |
| @@ -12,4 +12,4 @@ · 11 unmodified lines | ||
| 12 | 12 | #define DISVM_VERSION_PATCH 0 |
| 13 | 13 | #define DISVM_VERSION_LABEL "alpha" |
| 14 | 14 | |
| 15 | −#endif // _DISVM_SRC_INCLUDE_VM_VERSION_H_ | |
| 15 | +#endif // _DISVM_SRC_INCLUDE_VM_VERSION_H_ | |
| @@ -1678,7 +1678,7 @@ namespace · 1677 unmodified lines | ||
| 1678 | 1678 | |
| 1679 | 1679 | assert(r.module_ref != nullptr); |
| 1680 | 1680 | std::tie(handler, target_frame, handler_pc) = find_exception_handler(r.stack, *r.module_ref, faulting_pc, *exception_id); |
| 1681 | − if (handler == nullptr && target_frame == nullptr && handler_pc == runtime_constants::invalid_program_counter) | |
| 1681 | + if (handler == nullptr) | |
| 1682 | 1682 | { |
| 1683 | 1683 | if (tool_dispatch != nullptr) |
| 1684 | 1684 | tool_dispatch->on_exception_unhandled(r, *exception_id, *e); |
| @@ -1687,7 +1687,7 @@ namespace · 2 unmodified lines | ||
| 1687 | 1687 | throw unhandled_user_exception{ exception_id->str(), faulting_module_name, faulting_pc }; |
| 1688 | 1688 | } |
| 1689 | 1689 | |
| 1690 | − assert(target_frame != nullptr); | |
| 1690 | + assert(target_frame != nullptr && handler_pc != runtime_constants::invalid_program_counter); | |
| 1691 | 1691 | |
| 1692 | 1692 | // Now that we know the exception has a handler, take a reference. |
| 1693 | 1693 | e->add_ref(); |
| @@ -18,4 +18,4 @@ namespace disvm · 17 unmodified lines | ||
| 18 | 18 | } |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | −#endif // _DISVM_SRC_VM_EXECUTION_TABLE_H_ | |
| 21 | +#endif // _DISVM_SRC_VM_EXECUTION_TABLE_H_ | |
| @@ -42,4 +42,4 @@ namespace disvm · 41 unmodified lines | ||
| 42 | 42 | } |
| 43 | 43 | } |
| 44 | 44 | |
| 45 | −#endif // _DISVM_SRC_VM_GARBAGE_COLLECTOR_H_ | |
| 45 | +#endif // _DISVM_SRC_VM_GARBAGE_COLLECTOR_H_ | |
| @@ -102,4 +102,4 @@ namespace disvm · 101 unmodified lines | ||
| 102 | 102 | } |
| 103 | 103 | } |
| 104 | 104 | |
| 105 | −#endif // _DISVM_SRC_VM_SCHEDULER_H_ | |
| 105 | +#endif // _DISVM_SRC_VM_SCHEDULER_H_ | |
| @@ -461,4 +461,4 @@ const word_t Sys_UTFerror = 0xfffd; · 460 unmodified lines | ||
| 461 | 461 | const word_t Sys_Runemax = 0x10ffff; |
| 462 | 462 | const word_t Sys_Runemask = 0x1fffff; |
| 463 | 463 | |
| 464 | −#endif // _DISVM_SRC_VM_SYS_SYSMOD_H_ | |
| 464 | +#endif // _DISVM_SRC_VM_SYS_SYSMOD_H_ | |
| @@ -239,19 +239,25 @@ vm_thread_state_t vm_thread_t::execute(vm_t &vm, const uint32_t quanta) · 238 unmodified lines | ||
| 239 | 239 | catch (const unhandled_user_exception &uue) |
| 240 | 240 | { |
| 241 | 241 | _error_message = calloc_memory<char>(max_error_message); |
| 242 | − std::snprintf(_error_message, max_error_message, "%s - '%s' in %s at instruction %d", uue.what(), uue.exception_id, uue.module_name, uue.program_counter); | |
| 242 | + const int ec = std::snprintf(_error_message, max_error_message, "%s - '%s' in %s at instruction %d", uue.what(), uue.exception_id, uue.module_name, uue.program_counter); | |
| 243 | + assert(ec > 0 && ec < max_error_message); | |
| 244 | + (void)ec; | |
| 243 | 245 | _registers.current_thread_state = vm_thread_state_t::broken; |
| 244 | 246 | } |
| 245 | 247 | catch (const index_out_of_range_memory &ioor) |
| 246 | 248 | { |
| 247 | 249 | _error_message = calloc_memory<char>(max_error_message); |
| 248 | − std::snprintf(_error_message, max_error_message, "%s - %d [%d,%d]", ioor.what(), ioor.invalid_value, ioor.valid_min, ioor.valid_max); | |
| 250 | + const int ec = std::snprintf(_error_message, max_error_message, "%s - %d [%d,%d]", ioor.what(), ioor.invalid_value, ioor.valid_min, ioor.valid_max); | |
| 251 | + assert(ec > 0 && ec < max_error_message); | |
| 252 | + (void)ec; | |
| 249 | 253 | _registers.current_thread_state = vm_thread_state_t::broken; |
| 250 | 254 | } |
| 251 | 255 | catch (const vm_user_exception &ue) |
| 252 | 256 | { |
| 253 | 257 | _error_message = calloc_memory<char>(max_error_message); |
| 254 | − std::snprintf(_error_message, max_error_message, "%s", ue.what()); | |
| 258 | + const int ec = std::snprintf(_error_message, max_error_message, "%s", ue.what()); | |
| 259 | + assert(ec > 0 && ec < max_error_message); | |
| 260 | + (void)ec; | |
| 255 | 261 | _registers.current_thread_state = vm_thread_state_t::broken; |
| 256 | 262 | } |
| 257 | 263 | |
| @@ -122,4 +122,4 @@ namespace disvm · 121 unmodified lines | ||
| 122 | 122 | } |
| 123 | 123 | } |
| 124 | 124 | |
| 125 | −#endif // _DISVM_SRC_VM_TOOL_DISPATCH_H_ | |
| 125 | +#endif // _DISVM_SRC_VM_TOOL_DISPATCH_H_ | |