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,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_ | |