Skip to main content

luaur_bytecode/methods/
call_inliner_migrate_instructions.rs

1use crate::enums::bc_op_kind::BcOpKind;
2use crate::records::bc_inst::BcInst;
3use crate::records::bc_op::BcOp;
4use crate::records::bc_ref::BcRef;
5use crate::records::call_inliner::CallInliner;
6use crate::type_aliases::bc_ops::BcOps;
7
8use alloc::vec::Vec;
9use luaur_common::enums::luau_opcode::LuauOpcode;
10use luaur_common::macros::luau_assert::LUAU_ASSERT;
11
12impl<'a> CallInliner<'a> {
13    pub fn migrate_instructions(&mut self) {
14        for i in 0..self.target.instructions.len() as u32 {
15            let target_insn_op = BcOp::bc_op_bc_op_kind_u32(BcOpKind::Inst, i);
16            let caller_insn_op =
17                BcOp::bc_op_bc_op_kind_u32(BcOpKind::Inst, self.caller_inst_size_before_inline + i);
18            let target_inst_data = {
19                let target_inst = self.target.inst(target_insn_op);
20                target_inst.operator_deref().clone()
21            };
22            let target_ops: Vec<BcOp> = target_inst_data.ops.iter().copied().collect();
23            let target_reg = self.target.regs.get(&target_insn_op).copied();
24            let is_multi_consumer = match target_inst_data.op {
25                LuauOpcode::LOP_SETLIST
26                | LuauOpcode::LOP_RETURN
27                | LuauOpcode::LOP_CALLFB
28                | LuauOpcode::LOP_CALL => {
29                    let imm_op =
30                        target_inst_data.ops[if target_inst_data.op == LuauOpcode::LOP_SETLIST {
31                            1
32                        } else {
33                            0
34                        }];
35                    unsafe { self.target.immediates[imm_op.index as usize].value.valueInt < 0 }
36                }
37                _ => false,
38            };
39
40            if target_inst_data.op == LuauOpcode::LOP_RETURN
41                || target_inst_data.op == LuauOpcode::LOP_GETVARARGS
42            {
43                continue;
44            }
45
46            LUAU_ASSERT!(target_inst_data.block.kind == BcOpKind::Block);
47            let mapped_block = BcOp::bc_op_bc_op_kind_u32(
48                BcOpKind::Block,
49                self.caller_blocks_size_before_inline + target_inst_data.block.index,
50            );
51            self.caller.instructions[caller_insn_op.index as usize].op = target_inst_data.op;
52            self.caller.instructions[caller_insn_op.index as usize].block = mapped_block;
53
54            let last = *target_ops.last().unwrap();
55            let last_is_get_var_arg = last.kind == BcOpKind::Inst
56                && self.target.instructions[last.index as usize].op == LuauOpcode::LOP_GETVARARGS;
57
58            if self.target.is_vararg && is_multi_consumer && last_is_get_var_arg {
59                for inp in target_ops {
60                    if inp != last {
61                        let mapped = self.map_to_caller_op(inp);
62                        self.caller.instructions[caller_insn_op.index as usize]
63                            .ops
64                            .push_back(mapped);
65                    } else {
66                        LUAU_ASSERT!(self.var_arg_moves.contains_key(&inp));
67                        let moves = self.var_arg_moves.get(&inp).unwrap().clone();
68                        for move_op in moves {
69                            self.caller.instructions[caller_insn_op.index as usize]
70                                .ops
71                                .push_back(move_op);
72                        }
73                    }
74                }
75                let instructions = &self.caller.instructions as *const Vec<BcInst>;
76                let mut caller_inst = BcRef {
77                    vec: unsafe { &*instructions },
78                    op: caller_insn_op,
79                };
80                self.make_fixed_consumer(&mut caller_inst);
81            } else {
82                for inp in target_ops {
83                    let mapped = self.map_to_caller_op(inp);
84                    self.caller.instructions[caller_insn_op.index as usize]
85                        .ops
86                        .push_back(mapped);
87                }
88            }
89
90            if let Some(reg) = target_reg {
91                let mapped_reg = self.map_to_caller_reg(reg);
92                self.caller.regs.insert(caller_insn_op, mapped_reg);
93            }
94        }
95    }
96}