--ranges hybrid mode entry stub
| 666 | |
| 667 | // --ranges hybrid mode entry stub |
| 668 | void VMCodeGen::emit_range_entry(X64Emitter& e, std::uint32_t bytecode_offset, |
| 669 | std::size_t data_island_size, |
| 670 | std::uint32_t block_table_count) { |
| 671 | const auto& cfg = vm_.dispatcher_regs(); |
| 672 | const auto& st = vm_.state_layout(); |
| 673 | |
| 674 | emit_prologue(e, data_island_size); |
| 675 | |
| 676 | // frame size has to match what emit_prologue computed. |
| 677 | const std::uint32_t frame_size = static_cast<std::uint32_t>(vm_.state_layout().total_size) + vm_.shadow_stack_bytes() + vm_.frame_padding(); |
| 678 | const std::uint32_t aligned_frame = (frame_size + 15) & ~15u; |
| 679 | |
| 680 | // host volatile GPRs into VM slots |
| 681 | auto write_slot = [&](XReg xr, std::uint8_t host_reg) { |
| 682 | e.mov_mem_reg( |
| 683 | cfg.state_ptr, |
| 684 | static_cast<std::int32_t>(st.regs_base + vm_.slot_of_xreg(xr) * 8), |
| 685 | host_reg, |
| 686 | true |
| 687 | ); |
| 688 | }; |
| 689 | |
| 690 | write_slot(XReg::AX, rx::rax); |
| 691 | write_slot(XReg::CX, rx::rcx); |
| 692 | write_slot(XReg::DX, rx::rdx); |
| 693 | write_slot(XReg::R8, rx::r8); |
| 694 | write_slot(XReg::R9, rx::r9); |
| 695 | write_slot(XReg::R10, rx::r10); |
| 696 | write_slot(XReg::R11, rx::r11); |
| 697 | |
| 698 | // saved NV regs from the host stack into VM slots |
| 699 | auto it = g_prologue_orders.find(&e); |
| 700 | if (it == g_prologue_orders.end()) throw Error("emit_range_entry: missing prologue order"); |
| 701 | |
| 702 | auto host_to_xreg = [](std::uint8_t r) -> XReg { |
| 703 | if (r == rx::rbx) return XReg::BX; |
| 704 | if (r == rx::rbp) return XReg::BP; |
| 705 | if (r == rx::rdi) return XReg::DI; |
| 706 | if (r == rx::rsi) return XReg::SI; |
| 707 | if (r == rx::r12) return XReg::R12; |
| 708 | if (r == rx::r13) return XReg::R13; |
| 709 | if (r == rx::r14) return XReg::R14; |
| 710 | if (r == rx::r15) return XReg::R15; |
| 711 | return XReg::Invalid; |
| 712 | }; |
| 713 | |
| 714 | for (std::size_t i = 0; i < it->second.order.size(); ++i) { |
| 715 | const std::uint8_t nv_reg = it->second.order[i]; |
| 716 | const XReg xr = host_to_xreg(nv_reg); |
| 717 | if (xr == XReg::Invalid) throw Error("emit_range_entry: unmapped NV reg in prologue order"); |
| 718 | const std::int32_t stack_off = static_cast<std::int32_t>(aligned_frame) + 64 - 8 * static_cast<std::int32_t>(i); |
| 719 | |
| 720 | e.mov_reg_mem( |
| 721 | rx::rax, |
| 722 | rx::rsp, |
| 723 | stack_off, |
| 724 | true |
| 725 | ); |
nothing calls this directly
no test coverage detected