Skip to main content

luaur_bytecode/methods/
call_inliner_map_to_caller_op.rs

1use crate::enums::bc_op_kind::BcOpKind;
2use crate::records::bc_function::BcFunction;
3use crate::records::bc_inst::BcInst;
4use crate::records::bc_op::BcOp;
5use crate::records::bc_phi::BcPhi;
6use crate::records::bc_proj::BcProj;
7use crate::records::bc_vm_const::BcVmConst;
8use crate::records::call_inliner::CallInliner;
9use crate::type_aliases::reg::Reg;
10
11use luaur_common::enums::luau_opcode::LuauOpcode;
12use luaur_common::macros::luau_assert::LUAU_ASSERT;
13
14impl<'a> CallInliner<'a> {
15    pub fn map_to_caller_op(&mut self, target_op: BcOp) -> BcOp {
16        match target_op.kind {
17            BcOpKind::Inst => self.map_inst_op(target_op),
18            BcOpKind::Block => self.map_block_op(target_op),
19            BcOpKind::Imm => {
20                let imm = self.target.imm_op(target_op).clone();
21                self.caller.immediates.push(imm);
22                BcOp::bc_op_bc_op_kind_u32(
23                    BcOpKind::Imm,
24                    (self.caller.immediates.len() as u32).wrapping_sub(1),
25                )
26            }
27            BcOpKind::Phi => {
28                let phi_op = self.caller.add_phi();
29                let target_phi_ref = self.target.phi(target_op);
30                let ops_len = target_phi_ref.operator_deref().ops.len();
31
32                for i in 0..ops_len {
33                    let target_phi_op = {
34                        let target_phi = self.target.phi(target_op);
35                        target_phi.operator_deref().ops[i]
36                    };
37                    let mapped = self.map_to_caller_op(target_phi_op);
38                    let mut phi = self.caller.phi(phi_op);
39                    phi.operator_deref_mut().ops.push_back(mapped);
40                }
41                phi_op
42            }
43            BcOpKind::Proj => {
44                let proj_ref = self.target.proj(target_op);
45                let proj = *proj_ref.operator_deref();
46                if self.target.is_vararg {
47                    let inst_ref = self.target.inst(proj.op);
48                    let inst = inst_ref.operator_deref();
49                    if inst.op == LuauOpcode::LOP_GETVARARGS {
50                        // BcGetVarArgs is a helper struct wrapping a BcInst reference.
51                        // Since we don't have the full BcGetVarArgs definition here,
52                        // we use the underlying inst and proj.index directly.
53                        LUAU_ASSERT!(inst.ops.len() > 1);
54                        return self.get_var_arg_param(proj.op, proj.index);
55                    }
56                }
57                let mapped_op = self.map_to_caller_op(proj.op);
58                self.caller.add_proj(mapped_op, proj.index)
59            }
60            BcOpKind::VmReg => {
61                if target_op.index < self.target.numparams as u32 {
62                    LUAU_ASSERT!(target_op.index < self.call_params.len() as u32);
63                    self.call_params[target_op.index as usize]
64                } else {
65                    BcOp::bc_op_bc_op_kind_u32(
66                        BcOpKind::VmReg,
67                        self.map_to_caller_reg(target_op.index as Reg) as u32,
68                    )
69                }
70            }
71            BcOpKind::VmConst => {
72                crate::methods::call_inliner_map_vm_const_op::call_inliner_map_vm_const_op(
73                    self.caller_vm_const_size_before_inline,
74                    target_op,
75                )
76            }
77            BcOpKind::VmProto => self.map_proto_op(target_op),
78            BcOpKind::VmUpvalue => self.map_up_value_op(target_op),
79            _ => target_op,
80        }
81    }
82}