luaur_compiler/methods/
compiler_compile_expr_call.rs1use crate::functions::get_builtin::get_builtin;
2use crate::functions::get_builtin_info::get_builtin_info;
3use crate::functions::sref_compiler::sref_ast_name;
4use crate::records::builtin_info::BuiltinInfo;
5use crate::records::compiler::Compiler;
6use crate::records::reg_scope::RegScope;
7use luaur_ast::records::ast_expr_call::AstExprCall;
8use luaur_ast::records::ast_expr_index_name::AstExprIndexName;
9use luaur_ast::records::ast_node::AstNode;
10use luaur_bytecode::methods::bytecode_builder_get_string_hash::bytecode_builder_get_string_hash;
11use luaur_common::enums::luau_builtin_function::LuauBuiltinFunction;
12use luaur_common::enums::luau_bytecode_type::LuauBytecodeType;
13use luaur_common::enums::luau_feedback_type::LuauFeedbackType;
14use luaur_common::enums::luau_opcode::LuauOpcode;
15use luaur_common::macros::luau_assert::LUAU_ASSERT;
16
17impl Compiler {
18 pub fn compile_expr_call(
19 &mut self,
20 expr: *mut AstExprCall,
21 target: u8,
22 target_count: u8,
23 target_top: bool,
24 mult_ret: bool,
25 ) {
26 unsafe {
27 let expr_ref = &*expr;
28 LUAU_ASSERT!(target_count < 255);
29 LUAU_ASSERT!(!target_top || (target as u32 + target_count as u32) == self.reg_top);
30
31 self.set_debug_line_ast_node(expr as *mut _);
32
33 if self.options.optimization_level >= 2 && !expr_ref.self_ {
34 let func = self.get_function_expr(expr_ref.func);
35 let fi = if !func.is_null() {
36 self.functions.find(&func)
37 } else {
38 None
39 };
40
41 if fi.map_or(false, |f| f.can_inline)
42 && self.try_compile_inlined_call(
43 expr,
44 func,
45 target,
46 target_count,
47 mult_ret,
48 luaur_common::FInt::LuauCompileInlineThreshold.get(),
49 luaur_common::FInt::LuauCompileInlineThresholdMaxBoost.get(),
50 luaur_common::FInt::LuauCompileInlineDepth.get(),
51 )
52 {
53 return;
54 }
55 }
56
57 let mut rs = self.reg_scope_compiler();
58 let reg_count =
59 (1 + (expr_ref.self_ as usize) + expr_ref.args.size).max(target_count as usize);
60 let regs = if target_top {
61 self.alloc_reg(expr as *mut _, (reg_count - target_count as usize) as u32)
62 - target_count
63 } else {
64 self.alloc_reg(expr as *mut _, reg_count as u32)
65 };
66
67 let mut selfreg = 0u8;
68 let mut bfid = -1;
69
70 if self.options.optimization_level >= 1 && !expr_ref.self_ {
71 if let Some(id) = self.builtins.find(&expr) {
76 if *id
77 != luaur_common::enums::luau_builtin_function::LuauBuiltinFunction::LBF_NONE
78 as i32
79 {
80 bfid = *id;
81 }
82 }
83 }
84
85 if bfid >= 0 && (*self.bytecode).needs_debug_remarks() {
86 let builtin = get_builtin(expr_ref.func, &self.globals, &self.variables);
87 let last_mult = expr_ref.args.size > 0
88 && self.is_expr_mult_ret(*expr_ref.args.data.add(expr_ref.args.size - 1));
89 if !builtin.empty() {
90 let argc = expr_ref.args.size as i32;
93 let suffix = if last_mult { "+" } else { "" };
94 let method = core::ffi::CStr::from_ptr(builtin.method.value)
95 .to_str()
96 .unwrap_or("");
97 if builtin.object.value.is_null() {
98 (*self.bytecode).add_debug_remark(format_args!(
99 "builtin {}/{}{}",
100 method, argc, suffix
101 ));
102 } else {
103 let object = core::ffi::CStr::from_ptr(builtin.object.value)
104 .to_str()
105 .unwrap_or("");
106 (*self.bytecode).add_debug_remark(format_args!(
107 "builtin {}.{}/{}{}",
108 object, method, argc, suffix
109 ));
110 }
111 }
112 }
113
114 if bfid == LuauBuiltinFunction::LBF_SELECT_VARARG as i32 {
115 if !mult_ret && target_count == 1 {
118 return self.compile_expr_select_vararg(
119 expr,
120 target,
121 target_count,
122 target_top,
123 mult_ret,
124 regs,
125 );
126 } else {
127 bfid = -1;
128 }
129 }
130
131 if bfid == LuauBuiltinFunction::LBF_BIT32_EXTRACT as i32
132 && expr_ref.args.size == 3
133 && self.is_constant(*expr_ref.args.data.add(1))
134 && self.is_constant(*expr_ref.args.data.add(2))
135 {
136 let fc = self.get_constant(*expr_ref.args.data.add(1));
137 let wc = self.get_constant(*expr_ref.args.data.add(2));
138 let fi = if fc.r#type == crate::enums::type_constant_folding::Type::Type_Number {
139 fc.data.value_number as i32
140 } else {
141 -1
142 };
143 let wi = if wc.r#type == crate::enums::type_constant_folding::Type::Type_Number {
144 wc.data.value_number as i32
145 } else {
146 -1
147 };
148 if fi >= 0 && wi > 0 && fi + wi <= 32 {
149 let fwp = fi | ((wi - 1) << 5);
150 let cid = (*self.bytecode).add_constant_number(fwp as f64);
151 if cid >= 0 {
152 return self.compile_expr_fastcall_n(
153 expr,
154 target,
155 target_count,
156 target_top,
157 mult_ret,
158 regs,
159 LuauBuiltinFunction::LBF_BIT32_EXTRACTK as i32,
160 cid,
161 );
162 }
163 }
164 }
165
166 let mut max_fastcall_args = 2;
167 if bfid >= 0 && expr_ref.args.size == 3 {
168 for i in 0..expr_ref.args.size {
169 if self.get_expr_local_reg(*expr_ref.args.data.add(i)) >= 0 {
170 max_fastcall_args = 3;
171 break;
172 }
173 }
174 }
175
176 if bfid >= 0 && expr_ref.args.size >= 1 && expr_ref.args.size <= max_fastcall_args {
177 if !self.is_expr_mult_ret(*expr_ref.args.data.add(expr_ref.args.size - 1)) {
178 return self.compile_expr_fastcall_n(
179 expr,
180 target,
181 target_count,
182 target_top,
183 mult_ret,
184 regs,
185 bfid,
186 -1,
187 );
188 } else if self.options.optimization_level >= 2 {
189 let info = get_builtin_info(bfid);
190 if expr_ref.args.size as i32 == info.params
191 && (info.flags & BuiltinInfo::Flag_NoneSafe) != 0
192 {
193 return self.compile_expr_fastcall_n(
194 expr,
195 target,
196 target_count,
197 target_top,
198 mult_ret,
199 regs,
200 bfid,
201 -1,
202 );
203 }
204 }
205 }
206
207 if expr_ref.self_ {
208 let fi =
209 luaur_ast::rtti::ast_node_as::<AstExprIndexName>(expr_ref.func as *mut AstNode);
210 LUAU_ASSERT!(!fi.is_null());
211 let reg = self.get_expr_local_reg((*fi).expr);
212 if reg >= 0 {
213 selfreg = reg as u8;
214 } else {
215 selfreg = regs;
216 self.compile_expr_temp_top((*fi).expr, selfreg);
217 }
218 } else if bfid < 0 {
219 self.compile_expr_temp_top(expr_ref.func, regs);
220 }
221
222 let mut mult_call = false;
223 for i in 0..expr_ref.args.size {
224 let arg = *expr_ref.args.data.add(i);
225 if i + 1 == expr_ref.args.size {
226 mult_call = self.compile_expr_temp_mult_ret(
227 arg,
228 regs + 1 + (expr_ref.self_ as u8) + i as u8,
229 );
230 } else {
231 self.compile_expr_temp_top(arg, regs + 1 + (expr_ref.self_ as u8) + i as u8);
232 }
233 }
234
235 self.set_debug_line_end(expr_ref.func as *mut AstNode);
236
237 if expr_ref.self_ {
238 let fi =
239 luaur_ast::rtti::ast_node_as::<AstExprIndexName>(expr_ref.func as *mut AstNode);
240 self.set_debug_line_location(&(*fi).index_location);
241 let iname = sref_ast_name((*fi).index);
242 let cid = (*self.bytecode).add_constant_string(iname);
243 (*self.bytecode).emit_abc(
244 LuauOpcode::LOP_NAMECALL,
245 regs,
246 selfreg,
247 bytecode_builder_get_string_hash(iname) as u8,
248 );
249 (*self.bytecode).emit_aux(cid as u32);
250 self.hint_temporary_expr_reg_type(
251 (*fi).expr,
252 selfreg as i32,
253 LuauBytecodeType(4),
254 2,
255 );
256 } else if bfid >= 0 {
257 let fastcall_label = (*self.bytecode).emit_label();
258 (*self.bytecode).emit_abc(LuauOpcode::LOP_FASTCALL, bfid as u8, 0, 0);
259 self.compile_expr_temp(expr_ref.func, regs);
260 let call_label = (*self.bytecode).emit_label();
261 (*self.bytecode).patch_skip_c(fastcall_label, call_label);
262 }
263
264 if luaur_common::FFlag::LuauEmitCallFeedback.get()
268 && bfid < 0
269 && (*self.current_function).function_depth != 0
270 && !mult_call
271 && !mult_ret
272 {
273 let fb_slot = (*self.bytecode).add_fb_slot(LuauFeedbackType::LFT_CALLTARGET);
274 (*self.bytecode).emit_abc(
275 LuauOpcode::LOP_CALLFB,
276 regs,
277 if mult_call {
278 0
279 } else {
280 (expr_ref.self_ as u8) + expr_ref.args.size as u8 + 1
281 },
282 if mult_ret { 0 } else { target_count + 1 },
283 );
284 (*self.bytecode).emit_aux(fb_slot);
285 } else {
286 (*self.bytecode).emit_abc(
287 LuauOpcode::LOP_CALL,
288 regs,
289 if mult_call {
290 0
291 } else {
292 (expr_ref.self_ as u8) + expr_ref.args.size as u8 + 1
293 },
294 if mult_ret { 0 } else { target_count + 1 },
295 );
296 }
297
298 if !target_top {
299 for i in 0..target_count {
300 (*self.bytecode).emit_abc(LuauOpcode::LOP_MOVE, target + i, regs + i, 0);
301 }
302 }
303 }
304 }
305}