| 863 | } |
| 864 | |
| 865 | void VMCodeGen::emit_exit_handler(X64Emitter& e) { |
| 866 | off_.exit_handler = e.size(); |
| 867 | const auto& cfg = vm_.dispatcher_regs(); |
| 868 | const auto& st = vm_.state_layout(); |
| 869 | |
| 870 | e.mov_reg_mem( |
| 871 | rx::rsp, |
| 872 | cfg.state_ptr, |
| 873 | static_cast<std::int32_t>(st.saved_native_rsp), |
| 874 | true |
| 875 | ); |
| 876 | |
| 877 | // return value: VM_AX into rax |
| 878 | e.mov_reg_mem( |
| 879 | rx::rax, |
| 880 | cfg.state_ptr, |
| 881 | static_cast<std::int32_t>(st.regs_base + vm_.slot_of_xreg(XReg::AX) * 8), |
| 882 | true |
| 883 | ); |
| 884 | |
| 885 | const std::uint32_t frame_size = static_cast<std::uint32_t>(vm_.state_layout().total_size) + vm_.shadow_stack_bytes() + vm_.frame_padding(); |
| 886 | const std::uint32_t aligned = (frame_size + 15) & ~15u; |
| 887 | e.add_reg_imm32(rx::rsp, static_cast<std::int32_t>(aligned)); |
| 888 | e.popfq(); |
| 889 | auto it = g_prologue_orders.find(&e); |
| 890 | if (it == g_prologue_orders.end()) throw Error("emit_exit_handler: missing prologue order"); |
| 891 | |
| 892 | for (auto rit = it->second.order.rbegin(); rit != it->second.order.rend(); ++rit) { |
| 893 | e.pop_reg(*rit); |
| 894 | } |
| 895 | |
| 896 | e.ret(); |
| 897 | } |
| 898 | } |
nothing calls this directly
no test coverage detected