luaur_bytecode/methods/
call_inliner_migrate_instructions.rs1use 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}