History

Merged in debug_set_options (pull request #4)

Debug set options

Aaron R Robinson committed 9 years ago

Commit c55b47f2 parents 3cea79f 02a7d6a26 files · +523 −436Browse files

Unified · Split

26 files
  1. src/asm/type_signature.cpp +1 −1
  2. src/compiler_settings.gypi +2 −0
  3. src/exec/debugger.cpp +99 −43
  4. src/exec/exec.h +7 −1
  5. src/exec/main.cpp +19 −23
  6. src/include/buffered_reader.h +1 −1
  7. src/include/builtin_module.h +1 −1
  8. src/include/debug.h +1 −1
  9. src/include/disvm.h +1 −1
  10. src/include/exceptions.h +1 −1
  11. src/include/module_reader.h +1 −1
  12. src/include/opcodes.h +1 −1
  13. src/include/utf8.h +1 −1
  14. src/include/utils.h +1 −1
  15. src/include/vm_asm.h +1 −346
  16. src/include/vm_asm_sigkind.h +366 −0
  17. src/include/vm_memory.h +1 −1
  18. src/include/vm_tools.h +1 −1
  19. src/include/vm_version.h +1 −1
  20. src/vm/execution_table.cpp +2 −2
  21. src/vm/execution_table.h +1 −1
  22. src/vm/garbage_collector.h +1 −1
  23. src/vm/scheduler.h +1 −1
  24. src/vm/sys/Sysmod.h +1 −1
  25. src/vm/thread.cpp +9 −3
  26. src/vm/tool_dispatch.h +1 −1
src/asm/type_signature.cpp+1−1
@@ -4,8 +4,8 @@ · 3 unmodified lines
4// Author: arr4// Author: arr
5//5//
6 6
7#include <vm_asm.h>
8#include <array>7#include <array>
8#include <vm_asm_sigkind.h>
9#include "rfc1321/global.h"9#include "rfc1321/global.h"
10#include "rfc1321/md5.h"10#include "rfc1321/md5.h"
11 11
src/compiler_settings.gypi+2−0
@@ -33,6 +33,8 @@ · 32 unmodified lines
33 },33 },
34 'msvs_settings': {34 'msvs_settings': {
35 'VCCLCompilerTool': {35 'VCCLCompilerTool': {
36 'AdditionalOptions': '/Zc:rvalueCast',
37 'DisableLanguageExtensions': 'true',
36 'TreatWChar_tAsBuiltInType': 'false',38 'TreatWChar_tAsBuiltInType': 'false',
37 'WarningLevel': 3,39 'WarningLevel': 3,
38 'DebugInformationFormat': '3', # PDB40 'DebugInformationFormat': '3', # PDB
src/exec/debugger.cpp+99−43
@@ -11,6 +11,7 @@ · 10 unmodified lines
11#include <string>11#include <string>
12#include <algorithm>12#include <algorithm>
13#include <map>13#include <map>
14#include <unordered_set>
14#include <utils.h>15#include <utils.h>
15#include <vm_memory.h>16#include <vm_memory.h>
16#include <vm_asm.h>17#include <vm_asm.h>
@@ -383,9 +384,9 @@ namespace · 366 unmodified lines
383 384
384 auto msg = std::stringstream{};385 auto msg = std::stringstream{};
385 auto module_funcs = cxt.dbg.get_module_functions(vm_id, name_to_match);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 for (auto &f : module_funcs)388 for (auto &f : module_funcs)
388 msg << " " << f << "\n";389 msg << "\n " << f;
389 390
390 debug_print_info(msg.str());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 const auto &r = *cxt.current_register;620 const auto &r = *cxt.current_register;
619 const auto &code_section = r.module_ref->code_section;621 const auto &code_section = r.module_ref->code_section;
620 622
@@ -623,19 +625,19 @@ namespace · 2 unmodified lines
623 if (disassemble_length < 0)625 if (disassemble_length < 0)
624 {626 {
625 const auto begin_maybe = r.pc - (-disassemble_length) + 1;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 else630 else
629 {631 {
630 const auto end_maybe = static_cast<std::size_t>(r.pc + disassemble_length);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 assert(resolved_pc.empty() || resolved_pc.size() == (end_pc - begin_pc + 1) && "Resolved PCs should have failed or match the PC count");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 auto msg = std::stringstream{};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 auto op = code_section[i].op;642 auto op = code_section[i].op;
641 643
@@ -645,9 +647,9 @@ namespace · 3 unmodified lines
645 if (op.opcode == opcode_t::brkpt)647 if (op.opcode == opcode_t::brkpt)
646 {648 {
647 // Look up each of the known cookies to try and find the matching PC and module649 // 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 if (details.pc == i && details.module == r.module_ref->module)653 if (details.pc == i && details.module == r.module_ref->module)
652 {654 {
653 op.opcode = details.original_opcode;655 op.opcode = details.original_opcode;
@@ -660,9 +662,9 @@ namespace · 6 unmodified lines
660 // Print source location if resolved662 // Print source location if resolved
661 if (!resolved_pc.empty())663 if (!resolved_pc.empty())
662 {664 {
663 const auto & r = resolved_pc[i - begin_pc];665 const auto &rpc = resolved_pc[i - begin_pc];
664 if (!r.empty())666 if (!rpc.empty())
665 msg << r << "\n";667 msg << rpc << "\n";
666 }668 }
667 669
668 msg << op_prefix << std::setw(5) << i << ": " << op << "\n";670 msg << op_prefix << std::setw(5) << i << ": " << op << "\n";
@@ -811,18 +813,47 @@ namespace · 142 unmodified lines
811 << console_modifiers::reset_all;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 state826 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 return;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' command849 new_value << args[i];
824 return;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 const dbg_cmd_t cmds[] =859 const dbg_cmd_t cmds[] =
@@ -844,7 +875,7 @@ namespace · 15 unmodified lines
844 { "d", "Disassemble the next/previous N instructions (default N = 4)", "d (-?[0-9]+)?", "d, d -4, d 5", cmd_disassemble },875 { "d", "Disassemble the next/previous N instructions (default N = 4)", "d (-?[0-9]+)?", "d, d -4, d 5", cmd_disassemble },
845 { "x", "Examine memory", "x [mp|fp] [0-9]+ ([0-9]+)?", "x mp 3, x fp 20 6", cmd_examine },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 { "?", "Print help", nullptr, nullptr, cmd_help },879 { "?", "Print help", nullptr, nullptr, cmd_help },
849 880
850 // Undocumented commands881 // Undocumented commands
@@ -865,8 +896,8 @@ namespace · 14 unmodified lines
865 896
866 void print_help()897 void print_help()
867 {898 {
868 auto ss = std::stringstream{};899 auto msg = std::stringstream{};
869 ss << "Commands:\n";900 msg << "Commands:\n";
870 for (auto i = std::size_t{}; i < sizeof(cmds) / sizeof(cmds[0]); ++i)901 for (auto i = std::size_t{}; i < sizeof(cmds) / sizeof(cmds[0]); ++i)
871 {902 {
872 auto &c = cmds[i];903 auto &c = cmds[i];
@@ -875,16 +906,33 @@ namespace · 2 unmodified lines
875 if (c.description == nullptr)906 if (c.description == nullptr)
876 continue;907 continue;
877 908
878 ss << " " << c.cmd << "\t" << c.description << "\n";909 msg << " " << c.cmd << "\t" << c.description << "\n";
879 910
880 if (c.syntax != nullptr)911 if (c.syntax != nullptr)
881 ss << "\t Syntax: " << c.syntax << "\n";912 msg << "\t Syntax: " << c.syntax << "\n";
882 913
883 if (c.example != nullptr)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 void prompt(debugger &debugger, const vm_registers_t &r)938 void prompt(debugger &debugger, const vm_registers_t &r)
@@ -910,21 +958,11 @@ namespace · 19 unmodified lines
910 << console_modifiers::reset_all;958 << console_modifiers::reset_all;
911 959
912 std::getline(std::cin, cmd);960 std::getline(std::cin, cmd);
913 const auto cmd_tokens = util::split(cmd);
914 if (cmd_tokens.empty())
915 continue;
916 961
917 try962 assert(!cxt.exit_break && "Pre-condition on exit_break state before execute failed");
918 {963 execute_single_command(cxt, cmd);
919 auto cmd_exec = find_cmd(cmd_tokens[0]);964 if (cxt.exit_break)
920 cmd_exec(cmd_tokens, cxt);965 break;
921 if (cxt.exit_break)
922 break;
923 }
924 catch (const debug_cmd_error_t &e)
925 {
926 debug_print_error(e.what());
927 }
928 }966 }
929 967
930 debugger.controller->resume_all_threads();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 return _vm_id_to_symbol_info.find(vm_id) != std::cend(_vm_id_to_symbol_info);1057 return _vm_id_to_symbol_info.find(vm_id) != std::cend(_vm_id_to_symbol_info);
1020}1058}
1021 1059
1060std::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
1069void debugger::set_option(const std::string &option, std::string value)
1070{
1071 _debugger_options[option] = std::move(value);
1072}
1073
1022void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id)1074void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id)
1023{1075{
1024 _tool_id = tool_id;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 debug_print_info(ss.str());1168 debug_print_info(ss.str());
1117 1169
1118 auto reg_str = registers_to_string(*cxt.value1.registers);1170 const auto bp_cmd = get_option({ "bp-cmd" });
1119 debug_print_info(reg_str);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 prompt(*this, *cxt.value1.registers);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 catch (const std::runtime_error &e)1219 catch (const std::runtime_error &e)
1164 {1220 {
1165 // File with assumed symbol name/extension is not the correct format1221 // File with assumed symbol name/extension is not the correct format
1166 std::stringstream msg;1222 auto msg = std::stringstream{};
1167 msg << "Assumed symbol file '"1223 msg << "Assumed symbol file '"
1168 << symbol_path_maybe1224 << symbol_path_maybe
1169 << "' has invalid symbol format. ("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 || symbol_data->get_instruction_count() != m->code_section.size())1234 || symbol_data->get_instruction_count() != m->code_section.size())
1179 {1235 {
1180 // Symbol file does not match the loaded modules - stale file?1236 // Symbol file does not match the loaded modules - stale file?
1181 std::stringstream msg;1237 auto msg = std::stringstream{};
1182 msg << "Symbol file '"1238 msg << "Symbol file '"
1183 << symbol_path_maybe1239 << symbol_path_maybe
1184 << "' does not match loaded module '"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 auto symbol_iter = symbol_data->get_pc_iter();1249 auto symbol_iter = symbol_data->get_pc_iter();
1194 _vm_id_to_symbol_info[vm_id] = { std::move(symbol_data), std::move(symbol_iter) };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 msg << "Symbol file '"1253 msg << "Symbol file '"
1198 << symbol_path_maybe1254 << symbol_path_maybe
1199 << "' loaded for '"1255 << "' loaded for '"
src/exec/exec.h+7−1
@@ -13,6 +13,7 @@ · 12 unmodified lines
13#include <string>13#include <string>
14#include <memory>14#include <memory>
15#include <disvm.h>15#include <disvm.h>
16#include <vm_asm.h>
16#include <vm_tools.h>17#include <vm_tools.h>
17#include <utils.h>18#include <utils.h>
18 19
@@ -48,6 +49,10 @@ public: · 29 unmodified lines
48 // Check if the supplied module ID has symbols loaded49 // Check if the supplied module ID has symbols loaded
49 bool symbols_exist(disvm::runtime::module_id_t vm_id) const;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
51public: // vm_tool_t56public: // vm_tool_t
52 void on_load(disvm::runtime::vm_tool_controller_t &, std::size_t tool_id) override;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 std::unordered_map<std::size_t, symbol_info_t> _vm_id_to_symbol_info;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_
src/exec/main.cpp+19−23
@@ -11,7 +11,7 @@ · 10 unmodified lines
11#include <builtin_module.h>11#include <builtin_module.h>
12#include <debug.h>12#include <debug.h>
13#include <exceptions.h>13#include <exceptions.h>
14#include <vm_asm.h>14#include <vm_asm_sigkind.h>
15#include <vm_version.h>15#include <vm_version.h>
16#include "exec.h"16#include "exec.h"
17 17
@@ -21,6 +21,12 @@ using namespace disvm::assembly::sigkind; · 3 unmodified lines
21 21
22namespace22namespace
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 // Entry frame layout30 // Entry frame layout
25 struct vm_entry_frame_t final : public vm_frame_base_alloc_t31 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 std::unique_ptr<vm_module_t> create_entry_module(vm_t &vm, const std::vector<char *> &vm_args)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 // Convert arguments to a list44 // Convert arguments to a list
42 vm_string_t *command_module_path = nullptr;45 vm_string_t *command_module_path = nullptr;
43 vm_list_t *args = nullptr;46 vm_list_t *mod_args = new vm_list_t{ intrinsic_type_desc::type<vm_string_t>() };
44 vm_list_t *last = nullptr;47 vm_list_t *last = mod_args;
45 for (auto i = std::size_t{ 0 }; i < vm_args.size(); ++i)48 for (auto raw_arg : vm_args)
46 {49 {
47 auto tmp = vm_args[i];50 auto curr_arg = new vm_string_t{ std::strlen(raw_arg), reinterpret_cast<uint8_t *>(raw_arg) };
48 auto arg = new vm_string_t{ std::strlen(tmp), reinterpret_cast<uint8_t *>(tmp) };51 if (command_module_path == nullptr)
49 if (args == nullptr)
50 {52 {
51 // First argument is the module to load53 // First argument is the module to load
52 command_module_path = arg;54 command_module_path = curr_arg;
53 assert(last == nullptr);
54 args = new vm_list_t{ intrinsic_type_desc::type<vm_string_t>() };
55 last = args;
56 }55 }
57 else56 else
58 {57 {
@@ -63,10 +62,11 @@ namespace · 4 unmodified lines
63 last = new_tail;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 // Pre-load the command module in the VM.71 // Pre-load the command module in the VM.
72 command_module = vm.load_module(command_module_path->str());72 command_module = vm.load_module(command_module_path->str());
@@ -79,9 +79,7 @@ namespace · 6 unmodified lines
79 e.header.entry_pc = 0;79 e.header.entry_pc = 0;
80 e.header.entry_type = 0;80 e.header.entry_type = 0;
81 e.header.runtime_flag = (runtime_flags_t::has_import);81 e.header.runtime_flag = (runtime_flags_t::has_import);
82 82 e.module_name = create_string_from_const("_entry_");
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());
85 83
86 // Inherit the stack extent from the command module and add the entry frame size.84 // Inherit the stack extent from the command module and add the entry frame size.
87 e.header.stack_extent = command_module->header.stack_extent + sizeof(vm_entry_frame_t);85 e.header.stack_extent = command_module->header.stack_extent + sizeof(vm_entry_frame_t);
@@ -99,7 +97,7 @@ namespace · 11 unmodified lines
99 // Take a reference on the command module path and store it on the entry frame97 // Take a reference on the command module path and store it on the entry frame
100 command_module_path->add_ref();98 command_module_path->add_ref();
101 mp_base[0] = command_module_path->get_allocation();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 // Define the frame offset for the argument102 // Define the frame offset for the argument
105 const auto first_arg_offset = vm_frame_constants::limbo_first_arg_register_offset();103 const auto first_arg_offset = vm_frame_constants::limbo_first_arg_register_offset();
@@ -168,9 +166,7 @@ namespace · 62 unmodified lines
168 assert(exec_init_sig == sig_stream_t::compute_signature_hash("f(Ls)n"));166 assert(exec_init_sig == sig_stream_t::compute_signature_hash("f(Ls)n"));
169#endif167#endif
170 func.sig = exec_init_sig;168 func.sig = exec_init_sig;
171 169 func.name = create_string_from_const("init");
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());
174 170
175 import_vm_module_t import{};171 import_vm_module_t import{};
176 import.functions.push_back(std::move(func));172 import.functions.push_back(std::move(func));
src/include/buffered_reader.h+1−1
@@ -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_
src/include/builtin_module.h+1−1
@@ -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_
src/include/debug.h+1−1
@@ -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_
src/include/disvm.h+1−1
@@ -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_
src/include/exceptions.h+1−1
@@ -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_
src/include/module_reader.h+1−1
@@ -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_
src/include/opcodes.h+1−1
@@ -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_
src/include/utf8.h+1−1
@@ -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_
src/include/utils.h+1−1
@@ -78,4 +78,4 @@ inline TYPE operator ^ (TYPE a, TYPE b) { return static_cast<TYPE>(static_cast<s · 77 unmodified lines
78inline TYPE &operator ^= (TYPE &a, TYPE b) { a = a ^ b; return a; } \78inline TYPE &operator ^= (TYPE &a, TYPE b) { a = a ^ b; return a; } \
79inline TYPE operator ~ (TYPE a) { return static_cast<TYPE>(~static_cast<std::underlying_type_t<TYPE>>(a)); }79inline 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_
src/include/vm_asm.h+1−346
@@ -8,8 +8,6 @@ · 7 unmodified lines
8#define _DISVM_SRC_INCLUDE_VM_ASM_H_8#define _DISVM_SRC_INCLUDE_VM_ASM_H_
9 9
10#include <iosfwd>10#include <iosfwd>
11#include <sstream>
12#include <cassert>
13#include <cstdint>11#include <cstdint>
14#include "opcodes.h"12#include "opcodes.h"
15#include "runtime.h"13#include "runtime.h"
@@ -34,349 +32,6 @@ namespace disvm · 18 unmodified lines
34 // Get the opcode from this string.32 // Get the opcode from this string.
35 // If the supplied string cannot be resolved or if it is null, the 'invalid' opcode is returned.33 // If the supplied string cannot be resolved or if it is null, the 'invalid' opcode is returned.
36 disvm::opcode_t token_to_opcode(const char *);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 namespace symbol37 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_
src/include/vm_asm_sigkind.h+366−0
@@ -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
17namespace 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_
src/include/vm_memory.h+1−1
@@ -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_
src/include/vm_tools.h+1−1
@@ -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_
src/include/vm_version.h+1−1
@@ -12,4 +12,4 @@ · 11 unmodified lines
12#define DISVM_VERSION_PATCH 012#define DISVM_VERSION_PATCH 0
13#define DISVM_VERSION_LABEL "alpha"13#define DISVM_VERSION_LABEL "alpha"
14 14
15#endif // _DISVM_SRC_INCLUDE_VM_VERSION_H_15#endif // _DISVM_SRC_INCLUDE_VM_VERSION_H_
src/vm/execution_table.cpp+2−2
@@ -1678,7 +1678,7 @@ namespace · 1677 unmodified lines
1678 1678
1679 assert(r.module_ref != nullptr);1679 assert(r.module_ref != nullptr);
1680 std::tie(handler, target_frame, handler_pc) = find_exception_handler(r.stack, *r.module_ref, faulting_pc, *exception_id);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 if (tool_dispatch != nullptr)1683 if (tool_dispatch != nullptr)
1684 tool_dispatch->on_exception_unhandled(r, *exception_id, *e);1684 tool_dispatch->on_exception_unhandled(r, *exception_id, *e);
@@ -1687,7 +1687,7 @@ namespace · 2 unmodified lines
1687 throw unhandled_user_exception{ exception_id->str(), faulting_module_name, faulting_pc };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 // Now that we know the exception has a handler, take a reference.1692 // Now that we know the exception has a handler, take a reference.
1693 e->add_ref();1693 e->add_ref();
src/vm/execution_table.h+1−1
@@ -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_
src/vm/garbage_collector.h+1−1
@@ -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_
src/vm/scheduler.h+1−1
@@ -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_
src/vm/sys/Sysmod.h+1−1
@@ -461,4 +461,4 @@ const word_t Sys_UTFerror = 0xfffd; · 460 unmodified lines
461const word_t Sys_Runemax = 0x10ffff;461const word_t Sys_Runemax = 0x10ffff;
462const word_t Sys_Runemask = 0x1fffff;462const word_t Sys_Runemask = 0x1fffff;
463 463
464#endif // _DISVM_SRC_VM_SYS_SYSMOD_H_464#endif // _DISVM_SRC_VM_SYS_SYSMOD_H_
src/vm/thread.cpp+9−3
@@ -239,19 +239,25 @@ vm_thread_state_t vm_thread_t::execute(vm_t &vm, const uint32_t quanta) · 238 unmodified lines
239 catch (const unhandled_user_exception &uue)239 catch (const unhandled_user_exception &uue)
240 {240 {
241 _error_message = calloc_memory<char>(max_error_message);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 _registers.current_thread_state = vm_thread_state_t::broken;245 _registers.current_thread_state = vm_thread_state_t::broken;
244 }246 }
245 catch (const index_out_of_range_memory &ioor)247 catch (const index_out_of_range_memory &ioor)
246 {248 {
247 _error_message = calloc_memory<char>(max_error_message);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 _registers.current_thread_state = vm_thread_state_t::broken;253 _registers.current_thread_state = vm_thread_state_t::broken;
250 }254 }
251 catch (const vm_user_exception &ue)255 catch (const vm_user_exception &ue)
252 {256 {
253 _error_message = calloc_memory<char>(max_error_message);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 _registers.current_thread_state = vm_thread_state_t::broken;261 _registers.current_thread_state = vm_thread_state_t::broken;
256 }262 }
257 263
src/vm/tool_dispatch.h+1−1
@@ -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_