| 784 | } |
| 785 | |
| 786 | void VMCodeGen::emit_exit_handler(X86Emitter& e) { |
| 787 | off_.exit_handler = e.size(); |
| 788 | const auto& cfg = vm_.dispatcher_regs(); |
| 789 | const auto& st = vm_.state_layout(); |
| 790 | |
| 791 | e.mov_reg_mem( |
| 792 | rx::rsp, |
| 793 | cfg.state_ptr, |
| 794 | static_cast<std::int32_t>(st.saved_native_rsp), |
| 795 | true |
| 796 | ); |
| 797 | |
| 798 | // return value: VM_AX into eax. |
| 799 | e.mov_reg_mem( |
| 800 | rx::rax, |
| 801 | cfg.state_ptr, |
| 802 | static_cast<std::int32_t>(st.regs_base + vm_.slot_of_xreg(XReg::AX) * 8), |
| 803 | true |
| 804 | ); |
| 805 | |
| 806 | const std::uint32_t frame_size = static_cast<std::uint32_t>(vm_.state_layout().total_size) + vm_.shadow_stack_bytes() + vm_.frame_padding(); |
| 807 | const std::uint32_t aligned = (frame_size + 15) & ~15u; |
| 808 | e.add_reg_imm32(rx::rsp, static_cast<std::int32_t>(aligned)); |
| 809 | |
| 810 | e.popfq(); // popfd opcode, same as x64 popfq |
| 811 | auto it = g_x86_prologue_orders.find(&e); |
| 812 | if (it == g_x86_prologue_orders.end()) throw Error("emit_exit_handler x86: missing prologue order"); |
| 813 | for (auto rit = it->second.order.rbegin(); rit != it->second.order.rend(); ++rit) { |
| 814 | e.pop_reg(*rit); |
| 815 | } |
| 816 | e.ret(); |
| 817 | } |
| 818 | |
| 819 | void VMCodeGen::emit_full(X86Emitter& e, std::size_t /*bytecode_size*/, |
| 820 | std::size_t data_island_size, std::uint32_t block_table_count) { |
nothing calls this directly
no test coverage detected