Showing the changes to src/vm/thread.cpp (1 of 11 files). Show all
Unified · Split
| @@ -54,6 +54,7 @@ vm_registers_t::vm_registers_t( · 53 unmodified lines | |||
| 54 | const vm_thread_t &thread, | 54 | const vm_thread_t &thread, |
| 55 | vm_module_ref_t &entry) | 55 | vm_module_ref_t &entry) |
| 56 | : current_thread_state{ vm_thread_state_t::ready } | 56 | : current_thread_state{ vm_thread_state_t::ready } |
| 57 | , current_thread_quanta{ 0 } | ||
| 57 | , module_ref{ &entry } | 58 | , module_ref{ &entry } |
| 58 | , mp_base{ entry.mp_base } | 59 | , mp_base{ entry.mp_base } |
| 59 | , thread{ thread } | 60 | , thread{ thread } |
| @@ -163,64 +164,89 @@ vm_thread_t::~vm_thread_t() · 103 unmodified lines | |||
| 163 | debug::log_msg(debug::component_trace_t::thread, debug::log_level_t::debug, "destroy: vm thread: %d %d\n", _thread_id, _parent_thread_id); | 164 | debug::log_msg(debug::component_trace_t::thread, debug::log_level_t::debug, "destroy: vm thread: %d %d\n", _thread_id, _parent_thread_id); |
| 164 | } | 165 | } |
| 165 | 166 | ||
| 166 | vm_thread_state_t vm_thread_t::execute(vm_t &vm, const uint32_t quanta) | 167 | namespace |
| 167 | { | 168 | { |
| 168 | _registers.current_thread_state = vm_thread_state_t::running; | 169 | struct execute_with_tool_t |
| 169 | assert(_registers.pc != runtime_constants::invalid_program_counter); | ||
| 170 | |||
| 171 | auto execution_duration = uint32_t{ 0 }; | ||
| 172 | |||
| 173 | try | ||
| 174 | { | 170 | { |
| 175 | for (; execution_duration < quanta; ++execution_duration) | 171 | void begin_exec_loop(vm_registers_t ®isters, vm_t &) |
| 176 | { | 172 | { |
| 177 | if (_registers.stack.peek_frame() == nullptr) | 173 | auto tool_dispatch = registers.tool_dispatch.load(); |
| 178 | { | 174 | assert(tool_dispatch != nullptr); |
| 179 | if (debug::is_component_tracing_enabled<debug::component_trace_t::thread>()) | ||
| 180 | debug::log_msg(debug::component_trace_t::thread, debug::log_level_t::debug, "exit: vm thread: stack exhausted: %d\n", _thread_id); | ||
| 181 | 175 | ||
| 182 | _registers.current_thread_state = vm_thread_state_t::empty_stack; | 176 | tool_dispatch->block_if_thread_suspended(registers.thread.get_thread_id()); |
| 177 | } | ||
| 178 | }; | ||
| 183 | 179 | ||
| 184 | auto tool_dispatch = _registers.tool_dispatch.load(); | 180 | struct execute_normal_t |
| 185 | if (tool_dispatch != nullptr) | 181 | { |
| 186 | tool_dispatch->on_thread_end(*this); | 182 | void begin_exec_loop(vm_registers_t &, vm_t &) { } |
| 183 | }; | ||
| 187 | 184 | ||
| 188 | break; | 185 | template<typename EXEC_DETOUR> |
| 189 | } | 186 | void execute_impl(vm_registers_t ®isters, vm_t &vm) |
| 187 | { | ||
| 188 | EXEC_DETOUR detour{}; | ||
| 189 | auto &execution_duration = registers.current_thread_quanta; | ||
| 190 | for (; 0 != execution_duration; --execution_duration) | ||
| 191 | { | ||
| 192 | detour.begin_exec_loop(registers, vm); | ||
| 193 | assert(registers.stack.peek_frame() != nullptr && "Thread state should not be running with empty stack"); | ||
| 190 | 194 | ||
| 191 | const auto &code_section = _registers.module_ref->code_section; | 195 | const auto &code_section = registers.module_ref->code_section; |
| 192 | assert(static_cast<std::size_t>(_registers.pc) < code_section.size()); | 196 | assert(static_cast<std::size_t>(registers.pc) < code_section.size()); |
| 193 | 197 | ||
| 194 | assert(!_registers.module_ref->is_builtin_module() && "Interpreter thread is unable to execute native instructions"); | 198 | assert(!registers.module_ref->is_builtin_module() && "Interpreter thread is unable to execute native instructions"); |
| 195 | const auto &inst = code_section[_registers.pc].op; | 199 | const auto &inst = code_section[registers.pc].op; |
| 196 | const auto opcode = static_cast<std::size_t>(inst.opcode); | 200 | const auto opcode = static_cast<std::size_t>(inst.opcode); |
| 197 | if (static_cast<std::size_t>(opcode_t::last_opcode) < opcode) | 201 | if (static_cast<std::size_t>(opcode_t::last_opcode) < opcode) |
| 198 | throw vm_system_exception{ "Unknown op-code" }; | 202 | throw vm_system_exception{ "Unknown op-code" }; |
| 199 | 203 | ||
| 200 | // Instruction is valid, decode and update registers for operation | 204 | // Instruction is valid, decode and update registers for operation |
| 201 | decode_address(inst, _registers); | 205 | decode_address(inst, registers); |
| 202 | _registers.pc++; | 206 | registers.pc++; |
| 203 | vm_exec_table[opcode](_registers, vm); | 207 | vm_exec_table[opcode](registers, vm); |
| 204 | 208 | ||
| 205 | if (_registers.current_thread_state != vm_thread_state_t::running) | 209 | if (registers.current_thread_state != vm_thread_state_t::running) |
| 206 | break; | 210 | break; |
| 207 | } | 211 | } |
| 208 | } | 212 | } |
| 213 | } | ||
| 214 | |||
| 215 | vm_thread_state_t vm_thread_t::execute(vm_t &vm, const uint32_t quanta) | ||
| 216 | { | ||
| 217 | _registers.current_thread_state = vm_thread_state_t::running; | ||
| 218 | _registers.current_thread_quanta = quanta; | ||
| 219 | assert(_registers.pc != runtime_constants::invalid_program_counter); | ||
| 220 | auto tool_dispatch = _registers.tool_dispatch.load(); | ||
| 221 | |||
| 222 | try | ||
| 223 | { | ||
| 224 | if (tool_dispatch == nullptr) | ||
| 225 | execute_impl<execute_normal_t>(_registers, vm); | ||
| 226 | else | ||
| 227 | execute_impl<execute_with_tool_t>(_registers, vm); | ||
| 228 | } | ||
| 209 | catch (const unhandled_user_exception &uue) | 229 | catch (const unhandled_user_exception &uue) |
| 210 | { | 230 | { |
| 211 | // [TODO] Store the exception | 231 | // [TODO] Store the exception |
| 212 | std::fprintf(stderr, "%s - '%s' in %s at instruction %d\n", uue.what(), uue.exception_id, uue.module_name, uue.program_counter); | 232 | std::fprintf(stderr, "%s - '%s' in %s at instruction %d\n", uue.what(), uue.exception_id, uue.module_name, uue.program_counter); |
| 213 | _registers.current_thread_state = vm_thread_state_t::broken; | 233 | _registers.current_thread_state = vm_thread_state_t::broken; |
| 234 | if (tool_dispatch != nullptr) | ||
| 235 | tool_dispatch->on_thread_broken(*this); | ||
| 214 | } | 236 | } |
| 215 | catch (const index_out_of_range_memory &ioor) | 237 | catch (const index_out_of_range_memory &ioor) |
| 216 | { | 238 | { |
| 217 | std::fprintf(stderr, "%s - %d [%d,%d]\n", ioor.what(), ioor.invalid_value, ioor.valid_min, ioor.valid_max); | 239 | std::fprintf(stderr, "%s - %d [%d,%d]\n", ioor.what(), ioor.invalid_value, ioor.valid_min, ioor.valid_max); |
| 218 | _registers.current_thread_state = vm_thread_state_t::broken; | 240 | _registers.current_thread_state = vm_thread_state_t::broken; |
| 241 | if (tool_dispatch != nullptr) | ||
| 242 | tool_dispatch->on_thread_broken(*this); | ||
| 219 | } | 243 | } |
| 220 | catch (const vm_user_exception &ue) | 244 | catch (const vm_user_exception &ue) |
| 221 | { | 245 | { |
| 222 | std::fprintf(stderr, "%s\n", ue.what()); | 246 | std::fprintf(stderr, "%s\n", ue.what()); |
| 223 | _registers.current_thread_state = vm_thread_state_t::broken; | 247 | _registers.current_thread_state = vm_thread_state_t::broken; |
| 248 | if (tool_dispatch != nullptr) | ||
| 249 | tool_dispatch->on_thread_broken(*this); | ||
| 224 | } | 250 | } |
| 225 | 251 | ||
| 226 | // Log the execution result | 252 | // Log the execution result |
| @@ -231,14 +257,22 @@ vm_thread_state_t vm_thread_t::execute(vm_t &vm, const uint32_t quanta) · 4 unmodified lines | |||
| 231 | debug::log_level_t::debug, | 257 | debug::log_level_t::debug, |
| 232 | "status: vm thread: execute: %d %d %d %d\n", | 258 | "status: vm thread: execute: %d %d %d %d\n", |
| 233 | _thread_id, | 259 | _thread_id, |
| 234 | execution_duration, | 260 | (quanta - _registers.current_thread_quanta), |
| 235 | quanta, | 261 | quanta, |
| 236 | _registers.current_thread_state); | 262 | _registers.current_thread_state); |
| 237 | } | 263 | } |
| 238 | 264 | ||
| 239 | // If the thread is still in the running state transition it back to ready. | 265 | // If the thread is still in the running state transition it back to its entry state. |
| 240 | if (_registers.current_thread_state == vm_thread_state_t::running) | 266 | if (_registers.current_thread_state == vm_thread_state_t::running) |
| 241 | _registers.current_thread_state = vm_thread_state_t::ready; | 267 | { |
| 268 | _registers.current_thread_state = (tool_dispatch == nullptr) ? vm_thread_state_t::ready : vm_thread_state_t::debug; | ||
| 269 | } | ||
| 270 | else if (vm_thread_state_t::exiting == _registers.current_thread_state | ||
| 271 | || vm_thread_state_t::empty_stack == _registers.current_thread_state) | ||
| 272 | { | ||
| 273 | if (tool_dispatch != nullptr) | ||
| 274 | tool_dispatch->on_thread_end(*this); | ||
| 275 | } | ||
| 242 | 276 | ||
| 243 | return _registers.current_thread_state; | 277 | return _registers.current_thread_state; |
| 244 | } | 278 | } |