luaur_compiler/methods/
compiler_compile_function.rs1use crate::enums::type_compiler::Type as LoopJumpType;
2use crate::functions::model_cost_cost_model::model_cost_ast_node_ast_local_usize_dense_hash_map_ast_expr_call_i32_dense_hash_map_ast_expr_constant;
3use crate::records::compiler::Compiler;
4use crate::records::return_visitor::ReturnVisitor;
5use luaur_ast::records::ast_expr_function::AstExprFunction;
6use luaur_ast::records::ast_node::AstNode;
7use luaur_ast::records::ast_stat::AstStat;
8use luaur_common::enums::luau_bytecode_type::LBC_TYPE_ANY;
9use luaur_common::enums::luau_opcode::LuauOpcode;
10use luaur_common::macros::luau_assert::LUAU_ASSERT;
11use luaur_common::macros::luau_timetrace_argument::LUAU_TIMETRACE_ARGUMENT;
12use luaur_common::macros::luau_timetrace_scope::LUAU_TIMETRACE_SCOPE;
13
14impl Compiler {
15 pub fn compile_function(&mut self, func: *mut AstExprFunction, protoflags: &mut u8) -> u32 {
16 LUAU_TIMETRACE_SCOPE!("Compiler::compileFunction", "Compiler");
17 unsafe {
18 let func_ref = &*func;
19 if !func_ref.debugname.value.is_null() {
20 LUAU_TIMETRACE_ARGUMENT!("name", func_ref.debugname.value);
21 }
22
23 LUAU_ASSERT!(!self.functions.contains(&func));
24 LUAU_ASSERT!(
25 self.reg_top == 0
26 && self.stack_size == 0
27 && self.local_stack.is_empty()
28 && self.upvals.is_empty()
29 );
30 if luaur_common::FFlag::LuauExportValueSyntax.get() {
31 self.current_function = func;
32 }
33
34 let mut rs = self.reg_scope_compiler();
35 let self_ = if !func_ref.self_.is_null() { 1 } else { 0 };
36 let fid = (*self.bytecode)
37 .begin_function((self_ + func_ref.args.size) as u8, func_ref.vararg);
38
39 self.set_debug_line_ast_node(func as *mut AstNode);
40
41 if func_ref.vararg {
42 (*self.bytecode).emit_abc(
43 LuauOpcode::LOP_PREPVARARGS,
44 (self_ + func_ref.args.size) as u8,
45 0,
46 0,
47 );
48 }
49
50 let args = self.alloc_reg(func as *mut AstNode, (self_ + func_ref.args.size) as u32);
51 if !func_ref.self_.is_null() {
52 self.push_local(func_ref.self_, args, 0);
53 }
54 for i in 0..func_ref.args.size {
55 self.push_local(*func_ref.args.data.add(i), args + self_ as u8 + i as u8, 0);
56 }
57
58 self.arg_count = self.local_stack.len();
59 let stat = func_ref.body;
60 let mut terminates_early = false;
61 self.current_function = func;
62
63 for i in 0..(*stat).body.size {
64 let body_stat = *(*stat).body.data.add(i);
65 self.compile_stat(body_stat);
66 if self.always_terminates(body_stat) {
67 terminates_early = true;
68 break;
69 }
70 }
71
72 if luaur_common::FFlag::LuauExportValueSyntax.get() {
73 self.set_debug_line_end(stat as *mut AstNode);
74 if (!self.exported_locals.is_empty() || !self.exported_classes.is_empty())
75 && self.at_top_level()
76 {
77 self.compile_export_table();
78 } else if !terminates_early {
79 self.close_locals(0);
80 (*self.bytecode).emit_abc(LuauOpcode::LOP_RETURN, 0, 1, 0);
81 }
82 } else if !terminates_early {
83 self.set_debug_line_end(stat as *mut AstNode);
84 self.close_locals(0);
85 (*self.bytecode).emit_abc(LuauOpcode::LOP_RETURN, 0, 1, 0);
86 }
87
88 if self.options.optimization_level >= 1 && self.options.debug_level >= 2 {
89 self.gather_const_upvals(func);
90 }
91
92 (*self.bytecode)
93 .set_debug_function_line_defined(func_ref.base.base.location.begin.line as i32 + 1);
94
95 if self.options.debug_level >= 1 && !func_ref.debugname.value.is_null() {
96 (*self.bytecode).set_debug_function_name(
97 crate::functions::sref_compiler::sref_ast_name(func_ref.debugname),
98 );
99 }
100
101 if self.options.debug_level >= 2 {
102 for &l in &self.upvals {
103 (*self.bytecode).push_debug_upval(
104 crate::functions::sref_compiler::sref_ast_name((*l).name),
105 );
106 }
107 }
108
109 if self.options.type_info_level >= 1 {
110 for &l in &self.upvals {
111 let ty = self.local_types.find(&l).copied().unwrap_or(LBC_TYPE_ANY);
112 (*self.bytecode).push_upval_type_info(ty);
113 }
114 }
115
116 if self.options.optimization_level >= 1 {
117 (*self.bytecode).fold_jumps();
118 }
119 (*self.bytecode).expand_jumps();
120 self.pop_locals(0);
121
122 if (*self.bytecode).get_instruction_count() > 1000000 {
123 crate::records::compile_error::CompileError::raise(
124 &func_ref.base.base.location,
125 format_args!("Exceeded function instruction limit; split the function into parts to compile"),
126 );
127 }
128
129 if let Some(func_type) = self.function_types.find(&func) {
130 (*self.bytecode).set_function_type_info(func_type.clone());
131 }
132
133 if func_ref.function_depth == 0 && !self.has_loops {
134 *protoflags |= 2; }
136 if func_ref.has_native_attribute() {
137 *protoflags |= 4; }
139
140 let is_inlinable = !func_ref.vararg && !self.getfenv_used && !self.setfenv_used;
144 if luaur_common::FFlag::LuauEmitCallFeedback.get()
145 && is_inlinable
146 && self.upvals.len() == 0
147 {
148 *protoflags |= 8; }
150
151 (*self.bytecode).end_function(
152 self.stack_size as u8,
153 self.upvals.len() as u8,
154 *protoflags,
155 );
156
157 {
158 let f = self.functions.get_or_insert(func);
159 f.id = fid;
160 f.upvals = self.upvals.clone();
161 }
162
163 if self.options.optimization_level >= 2
164 && !func_ref.vararg
165 && func_ref.self_.is_null()
166 && !self.getfenv_used
167 && !self.setfenv_used
168 {
169 let cost_model = model_cost_ast_node_ast_local_usize_dense_hash_map_ast_expr_call_i32_dense_hash_map_ast_expr_constant(
170 func_ref.body as *mut AstNode,
171 func_ref.args.data as *const _,
172 func_ref.args.size,
173 &*self.builtins_fold,
174 &self.constants,
175 );
176 let returns_one = if self.always_terminates(func_ref.body as *mut AstStat) {
177 let mut rv = self.return_visitor_return_visitor();
178 luaur_ast::visit::ast_stat_block_visit(&*func_ref.body, &mut rv);
179 Some(rv.returns_one)
180 } else {
181 None
182 };
183
184 let f = self.functions.get_or_insert(func);
185 f.can_inline = !(luaur_common::FFlag::DebugLuauNoInline.get()
187 && !func_ref
188 .get_attribute(luaur_ast::records::ast_attr::AstAttrType::DebugNoinline)
189 .is_null());
190 f.stack_size = self.stack_size as u32;
191 f.cost_model = cost_model;
192 if let Some(returns_one) = returns_one {
193 f.returns_one = returns_one;
194 }
195 }
196
197 self.upvals.clear();
198 self.stack_size = 0;
199 self.arg_count = 0;
200 self.has_loops = false;
201 self.current_function = core::ptr::null_mut();
202 fid
203 }
204 }
205}