Unified · Split
| @@ -322,8 +322,15 @@ namespace · 321 unmodified lines | ||
| 322 | 322 | { |
| 323 | 323 | auto msg = std::stringstream{}; |
| 324 | 324 | msg << "Modules:\n"; |
| 325 | − for (auto m : cxt.vm.get_loaded_modules()) | |
| 326 | − msg << " " << m->module_name->str() << "\n"; | |
| 325 | + | |
| 326 | + cxt.vm.enum_loaded_modules([&msg](const loaded_vm_module_t &m) | |
| 327 | + { | |
| 328 | + auto module_instance = m.module.lock(); | |
| 329 | + if (module_instance == nullptr) | |
| 330 | + return; | |
| 331 | + | |
| 332 | + msg << std::setw(24) << module_instance->module_name->str() << std::setw(0) << " " << m.origin->str() << "\n"; | |
| 333 | + }); | |
| 327 | 334 | |
| 328 | 335 | debug_print_info(msg.str()); |
| 329 | 336 | } |
| @@ -625,7 +632,7 @@ namespace · 295 unmodified lines | ||
| 625 | 632 | { "r", "Print registers", nullptr, nullptr, cmd_print_registers }, |
| 626 | 633 | { "t", "Print all threads", nullptr, nullptr, cmd_print_threads }, |
| 627 | 634 | { "m", "Print all loaded modules", nullptr, nullptr, cmd_print_modules }, |
| 628 | − { "sw", "Stack walk/back trace", "bt ([0-9]+|\\*)?", "bt, bt 34, bt *", cmd_stacktrace }, | |
| 635 | + { "bt", "Stack walk/back trace for the current or supplied thread", "bt ([0-9]+|\\*)?", "bt, bt 34, bt *", cmd_stacktrace }, | |
| 629 | 636 | { "st", "Switch to thread", "st [0-9]+", "st 42", cmd_switchthread }, |
| 630 | 637 | { "d", "Disassemble the next/previous N instructions", "d (-?[0-9]+)?", "d, d -4, d 5", cmd_disassemble }, |
| 631 | 638 | { "x", "Examine memory", "x [mp|fp] [0-9]+ ([0-9]+)?", "x mp 3, x fp 20 6", cmd_examine }, |
| @@ -35,6 +35,19 @@ namespace disvm · 34 unmodified lines | ||
| 35 | 35 | const char * const label; // Optional |
| 36 | 36 | }; |
| 37 | 37 | |
| 38 | + // Loaded module reference | |
| 39 | + class loaded_vm_module_t final | |
| 40 | + { | |
| 41 | + public: | |
| 42 | + // Origin of module | |
| 43 | + std::unique_ptr<runtime::vm_string_t> origin; | |
| 44 | + | |
| 45 | + // Weak reference to a loaded module | |
| 46 | + std::weak_ptr<runtime::vm_module_t> module; | |
| 47 | + }; | |
| 48 | + | |
| 49 | + using loaded_vm_module_callback_t = std::function<void(const loaded_vm_module_t&)>; | |
| 50 | + | |
| 38 | 51 | // Virtual machine |
| 39 | 52 | class vm_t final |
| 40 | 53 | { |
| @@ -71,9 +84,11 @@ namespace disvm · 30 unmodified lines | ||
| 71 | 84 | // Load the module at the supplied path into the virtual machine |
| 72 | 85 | std::shared_ptr<runtime::vm_module_t> load_module(const char *path); |
| 73 | 86 | |
| 74 | − // Get a collection of all currently loaded modules. | |
| 75 | − // Note this will only include modules that have been loaded by a call to vm_t::load_module. | |
| 76 | − std::vector<std::shared_ptr<runtime::vm_module_t>> get_loaded_modules() const; | |
| 87 | + // Enumerate all loaded modules - this can include references to modules that | |
| 88 | + // have been unloaded due to no longer being used. If the module instance is null, the | |
| 89 | + // module is no longer loaded. | |
| 90 | + // Note this will only enumerate modules that have been loaded by a call to vm_t::load_module. | |
| 91 | + void enum_loaded_modules(loaded_vm_module_callback_t callback) const; | |
| 77 | 92 | |
| 78 | 93 | // Access the scheduler control for this VM. |
| 79 | 94 | runtime::vm_scheduler_control_t &get_scheduler_control() const; |
| @@ -94,25 +109,7 @@ namespace disvm · 14 unmodified lines | ||
| 94 | 109 | private: |
| 95 | 110 | const runtime::vm_thread_t &schedule_thread(std::unique_ptr<runtime::vm_thread_t> thread); |
| 96 | 111 | |
| 97 | − // Loaded module reference | |
| 98 | − class loaded_module_t final | |
| 99 | − { | |
| 100 | − public: | |
| 101 | − loaded_module_t(std::unique_ptr<runtime::vm_string_t> origin, std::shared_ptr<runtime::vm_module_t> module); | |
| 102 | − loaded_module_t(const loaded_module_t &) = delete; | |
| 103 | − loaded_module_t &operator=(const loaded_module_t &) = delete; | |
| 104 | − | |
| 105 | − loaded_module_t(loaded_module_t &&); | |
| 106 | − ~loaded_module_t(); | |
| 107 | − | |
| 108 | − // Origin of module | |
| 109 | − std::unique_ptr<runtime::vm_string_t> origin; | |
| 110 | − | |
| 111 | − // Weak reference to a loaded module | |
| 112 | − std::weak_ptr<runtime::vm_module_t> module; | |
| 113 | − }; | |
| 114 | − | |
| 115 | − using loaded_modules_t = std::forward_list<loaded_module_t>; | |
| 112 | + using loaded_modules_t = std::forward_list<loaded_vm_module_t>; | |
| 116 | 113 | mutable std::mutex _modules_lock; |
| 117 | 114 | loaded_modules_t _modules; |
| 118 | 115 | |
| @@ -20,25 +20,6 @@ · 19 unmodified lines | ||
| 20 | 20 | using namespace disvm; |
| 21 | 21 | using namespace disvm::runtime; |
| 22 | 22 | |
| 23 | −vm_t::loaded_module_t::loaded_module_t(std::unique_ptr<runtime::vm_string_t> origin, std::shared_ptr<runtime::vm_module_t> module) | |
| 24 | − : origin{ std::move(origin) } | |
| 25 | − , module{ module } | |
| 26 | −{ | |
| 27 | − assert(this->origin != nullptr); | |
| 28 | −} | |
| 29 | − | |
| 30 | −vm_t::loaded_module_t::loaded_module_t(loaded_module_t &&other) | |
| 31 | − : origin{ std::move(other.origin) } | |
| 32 | − , module{ std::move(other.module) } | |
| 33 | −{ | |
| 34 | −} | |
| 35 | − | |
| 36 | −vm_t::loaded_module_t::~loaded_module_t() | |
| 37 | −{ | |
| 38 | − if (origin != nullptr) | |
| 39 | − origin->release(); | |
| 40 | −} | |
| 41 | − | |
| 42 | 23 | vm_t::vm_t( |
| 43 | 24 | create_vm_interface_callback_t<runtime::vm_scheduler_t> create_scheduler, |
| 44 | 25 | create_vm_interface_callback_t<runtime::vm_garbage_collector_t> create_gc) |
| @@ -80,6 +61,13 @@ vm_t::~vm_t() · 35 unmodified lines | ||
| 80 | 61 | // Release the scheduler first since it could be using the gc instance. |
| 81 | 62 | _scheduler.reset(); |
| 82 | 63 | _gc.reset(); |
| 64 | + | |
| 65 | + std::lock_guard<std::mutex> lock{ _modules_lock }; | |
| 66 | + for (auto &m : _modules) | |
| 67 | + { | |
| 68 | + if (m.origin != nullptr) | |
| 69 | + m.origin->release(); | |
| 70 | + } | |
| 83 | 71 | } |
| 84 | 72 | |
| 85 | 73 | vm_version_t vm_t::get_version() const |
| @@ -139,7 +127,7 @@ std::shared_ptr<runtime::vm_module_t> vm_t::load_module(const char *path) · 53 unmodified lines | ||
| 139 | 127 | throw vm_user_exception{ "Invalid module path" }; |
| 140 | 128 | |
| 141 | 129 | std::lock_guard<std::mutex> lock{ _modules_lock }; |
| 142 | − | |
| 130 | + | |
| 143 | 131 | // Check if the module is already loaded. |
| 144 | 132 | auto iter = std::begin(_modules); |
| 145 | 133 | while (iter != std::end(_modules)) |
| @@ -182,26 +170,21 @@ std::shared_ptr<runtime::vm_module_t> vm_t::load_module(const char *path) · 36 unmodified lines | ||
| 182 | 170 | _tool_dispatch->on_module_load(new_module, *path_local); |
| 183 | 171 | } |
| 184 | 172 | |
| 185 | − _modules.push_front(std::move(loaded_module_t{ std::move(path_local), new_module })); | |
| 173 | + _modules.push_front(std::move(loaded_vm_module_t{ std::move(path_local), new_module })); | |
| 186 | 174 | |
| 187 | 175 | debug::log_msg(debug::component_trace_t::module, debug::log_level_t::debug, "load: vm module: >>%s<<\n", path); |
| 188 | 176 | |
| 189 | 177 | return new_module; |
| 190 | 178 | } |
| 191 | 179 | |
| 192 | −std::vector<std::shared_ptr<runtime::vm_module_t>> vm_t::get_loaded_modules() const | |
| 180 | +void vm_t::enum_loaded_modules(loaded_vm_module_callback_t callback) const | |
| 193 | 181 | { |
| 194 | − auto result = std::vector<std::shared_ptr<runtime::vm_module_t>>{}; | |
| 182 | + if (callback == nullptr) | |
| 183 | + throw vm_system_exception{ "Callback should not be null" }; | |
| 195 | 184 | |
| 196 | 185 | std::lock_guard<std::mutex> lock{ _modules_lock }; |
| 197 | 186 | for (auto &m : _modules) |
| 198 | − { | |
| 199 | − auto loaded_module_maybe = m.module.lock(); | |
| 200 | − if (loaded_module_maybe != nullptr) | |
| 201 | − result.push_back(loaded_module_maybe); | |
| 202 | − } | |
| 203 | − | |
| 204 | − return result; | |
| 187 | + callback(m); | |
| 205 | 188 | } |
| 206 | 189 | |
| 207 | 190 | runtime::vm_scheduler_control_t &vm_t::get_scheduler_control() const |
| @@ -422,7 +422,9 @@ std::shared_ptr<const type_descriptor_t> type_descriptor_t::create( · 421 unmodified lines | ||
| 422 | 422 | free_memory(const_cast<byte_t *>(td->pointer_map)); |
| 423 | 423 | debug::assign_debug_pointer(const_cast<byte_t **>(&td->pointer_map)); |
| 424 | 424 | |
| 425 | − debug::log_msg(debug::component_trace_t::memory, debug::log_level_t::debug, "destroy: type descriptor\n"); | |
| 425 | + if (debug::is_component_tracing_enabled<debug::component_trace_t::memory>()) | |
| 426 | + debug::log_msg(debug::component_trace_t::memory, debug::log_level_t::debug, "destroy: type descriptor\n"); | |
| 427 | + | |
| 426 | 428 | free_memory(td); |
| 427 | 429 | } |
| 428 | 430 | } deleter; |
| @@ -451,5 +453,6 @@ type_descriptor_t::type_descriptor_t( · 22 unmodified lines | ||
| 451 | 453 | , pointer_map{ pointer_map } |
| 452 | 454 | , finalizer{ finalizer } |
| 453 | 455 | { |
| 454 | − debug::log_msg(debug::component_trace_t::memory, debug::log_level_t::debug, "init: type descriptor\n"); | |
| 456 | + if (debug::is_component_tracing_enabled<debug::component_trace_t::memory>()) | |
| 457 | + debug::log_msg(debug::component_trace_t::memory, debug::log_level_t::debug, "init: type descriptor\n"); | |
| 455 | 458 | } |