Unified · Split
| @@ -4,8 +4,8 @@ · 3 unmodified lines | |||
| 4 | // Author: arr | 4 | // 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 | ||
| @@ -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', # PDB | 40 | 'DebugInformationFormat': '3', # PDB |
| @@ -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 | ||
| 22 | namespace | 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 | // Entry frame layout | 30 | // Entry frame layout |
| 25 | struct vm_entry_frame_t final : public vm_frame_base_alloc_t | 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 | 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 list | 44 | // 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 load | 53 | // 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 | else | 56 | 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 frame | 97 | // 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 argument | 102 | // 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 | #endif | 167 | #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)); |
| @@ -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 | inline TYPE &operator ^= (TYPE &a, TYPE b) { a = a ^ b; return a; } \ | 78 | inline TYPE &operator ^= (TYPE &a, TYPE b) { a = a ^ b; return a; } \ |
| 79 | inline TYPE operator ~ (TYPE a) { return static_cast<TYPE>(~static_cast<std::underlying_type_t<TYPE>>(a)); } | 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 | #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 symbol | 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 | #define DISVM_VERSION_PATCH 0 | 12 | #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_ |
| @@ -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(); |
| @@ -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 | const word_t Sys_Runemax = 0x10ffff; | 461 | const word_t Sys_Runemax = 0x10ffff; |
| 462 | const word_t Sys_Runemask = 0x1fffff; | 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 | 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 | ||
| @@ -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_ |