Skip to main content

luaur_compiler/methods/
compiler_compile_expr_fastcall_n.rs

1use crate::records::compile_error::CompileError;
2use crate::records::compiler::Compiler;
3use luaur_ast::records::ast_expr_call::AstExprCall;
4use luaur_common::enums::luau_opcode::LuauOpcode;
5use luaur_common::macros::luau_assert::LUAU_ASSERT;
6
7impl Compiler {
8    pub fn compile_expr_fastcall_n(
9        &mut self,
10        expr: *mut AstExprCall,
11        target: u8,
12        target_count: u8,
13        target_top: bool,
14        mult_ret: bool,
15        regs: u8,
16        bfid: i32,
17        bf_k: i32,
18    ) {
19        let expr_ref = unsafe { &*expr };
20        LUAU_ASSERT!(!expr_ref.self_);
21        LUAU_ASSERT!(expr_ref.args.size >= 1);
22        LUAU_ASSERT!(expr_ref.args.size <= 3);
23        LUAU_ASSERT!(if bfid
24            == luaur_common::enums::luau_builtin_function::LuauBuiltinFunction::LBF_BIT32_EXTRACTK
25                as i32
26        {
27            bf_k >= 0
28        } else {
29            bf_k < 0
30        });
31        LUAU_ASSERT!(target_count < 255);
32
33        let opc = if expr_ref.args.size == 1 {
34            LuauOpcode::LOP_FASTCALL1
35        } else if bf_k >= 0
36            || (expr_ref.args.size == 2 && self.is_constant(unsafe { *expr_ref.args.data.add(1) }))
37        {
38            LuauOpcode::LOP_FASTCALL2K
39        } else if expr_ref.args.size == 2 {
40            LuauOpcode::LOP_FASTCALL2
41        } else {
42            LuauOpcode::LOP_FASTCALL3
43        };
44
45        let mut args = [0u32; 3];
46        for i in 0..expr_ref.args.size {
47            let arg_expr = unsafe { *expr_ref.args.data.add(i) };
48            if i > 0 && opc == LuauOpcode::LOP_FASTCALL2K {
49                let cid = self.get_constant_index(arg_expr);
50                if cid < 0 {
51                    let location = unsafe { (*arg_expr).base.location };
52                    CompileError::raise(
53                        &location,
54                        core::format_args!("Exceeded constant limit; simplify the code to compile"),
55                    );
56                }
57                args[i] = cid as u32;
58            } else if let Some(reg) = {
59                let r = self.get_expr_local_reg(arg_expr);
60                if r >= 0 {
61                    Some(r)
62                } else {
63                    None
64                }
65            } {
66                args[i] = reg as u32;
67            } else {
68                args[i] = (regs as u32) + 1 + (i as u32);
69                self.compile_expr_temp_top(arg_expr, args[i] as u8);
70            }
71        }
72
73        let bytecode = unsafe { &mut *self.bytecode };
74        let fastcall_label = bytecode.emit_label();
75
76        bytecode.emit_abc(opc, bfid as u8, args[0] as u8, 0);
77
78        if opc == LuauOpcode::LOP_FASTCALL3 {
79            LUAU_ASSERT!(bf_k < 0);
80            bytecode.emit_aux(args[1] | (args[2] << 8));
81        } else if opc != LuauOpcode::LOP_FASTCALL1 {
82            bytecode.emit_aux(if bf_k >= 0 { bf_k as u32 } else { args[1] });
83        }
84
85        for i in 0..expr_ref.args.size {
86            if i > 0 && opc == LuauOpcode::LOP_FASTCALL2K {
87                self.emit_load_k((regs + 1 + i as u8), args[i] as i32);
88            } else if args[i] != (regs as u32) + 1 + (i as u32) {
89                bytecode.emit_abc(LuauOpcode::LOP_MOVE, (regs + 1 + i as u8), args[i] as u8, 0);
90            }
91        }
92
93        self.compile_expr_temp(expr_ref.func, regs);
94
95        let call_label = bytecode.emit_label();
96
97        if !bytecode.patch_skip_c(fastcall_label, call_label) {
98            let location = unsafe { (*expr_ref.func).base.location };
99            CompileError::raise(
100                &location,
101                core::format_args!("Exceeded jump distance limit; simplify the code to compile"),
102            );
103        }
104
105        bytecode.emit_abc(
106            LuauOpcode::LOP_CALL,
107            regs,
108            (expr_ref.args.size + 1) as u8,
109            if mult_ret { 0 } else { target_count + 1 },
110        );
111
112        if !target_top {
113            for i in 0..target_count {
114                bytecode.emit_abc(LuauOpcode::LOP_MOVE, target + i, regs + i, 0);
115            }
116        }
117    }
118}