luaur_compiler/methods/
compiler_compile_expr_fastcall_n.rs1use 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}