luaur_bytecode/methods/
bytecode_builder_write_function.rs1use crate::enums::r#type::Type;
2use crate::functions::write_byte::write_byte;
3use crate::functions::write_double::write_double;
4use crate::functions::write_float::write_float;
5use crate::functions::write_int::write_int;
6use crate::functions::write_var_int::write_var_int;
7use crate::records::bytecode_builder::BytecodeBuilder;
8use crate::records::class_shape::ClassShape;
9use crate::records::constant::Constant;
10use crate::records::debug_local_bytecode_builder::DebugLocal;
11use crate::records::debug_upval::DebugUpval;
12use crate::records::function::Function;
13use crate::records::table_shape::TableShape;
14use crate::records::typed_local_bytecode_builder::TypedLocal;
15use crate::records::typed_upval::TypedUpval;
16use alloc::string::String;
17use alloc::vec::Vec;
18use core::cmp;
19use luaur_common::enums::luau_bytecode_tag::LuauBytecodeTag;
20use luaur_common::enums::luau_feedback_type::LuauFeedbackType;
21use luaur_common::macros::luau_assert::LUAU_ASSERT;
22use luaur_common::FFlag;
23
24impl BytecodeBuilder {
25 pub fn write_function(&mut self, ss: &mut String, id: u32, flags: u8) {
26 LUAU_ASSERT!(id < self.functions.len() as u32);
27 let func = &self.functions[id as usize];
28
29 write_byte(ss, func.maxstacksize);
31 write_byte(ss, func.numparams);
32 write_byte(ss, func.numupvalues);
33 write_byte(ss, if func.isvararg { 1 } else { 0 });
34
35 write_byte(ss, flags);
36
37 if !func.typeinfo.is_empty()
38 || !self.typed_upvals.is_empty()
39 || !self.typed_locals.is_empty()
40 {
41 self.temp_type_info.clear();
43 write_var_int(&mut self.temp_type_info, func.typeinfo.len() as u64);
44 write_var_int(&mut self.temp_type_info, self.typed_upvals.len() as u64);
45 write_var_int(&mut self.temp_type_info, self.typed_locals.len() as u64);
46
47 self.temp_type_info.push_str(&func.typeinfo);
48
49 for l in &self.typed_upvals {
50 write_byte(&mut self.temp_type_info, l.r#type.0 as u8);
51 }
52
53 for l in &self.typed_locals {
54 write_byte(&mut self.temp_type_info, l.r#type.0 as u8);
55 write_byte(&mut self.temp_type_info, l.reg);
56 write_var_int(&mut self.temp_type_info, l.startpc as u64);
57 LUAU_ASSERT!(l.endpc >= l.startpc);
58 write_var_int(&mut self.temp_type_info, (l.endpc - l.startpc) as u64);
59 }
60
61 write_var_int(ss, self.temp_type_info.len() as u64);
62 ss.push_str(&self.temp_type_info);
63 } else {
64 write_var_int(ss, 0);
65 }
66
67 write_var_int(ss, self.insns.len() as u64);
69
70 for &insn in &self.insns {
71 write_int(ss, insn as i32);
72 }
73
74 write_var_int(ss, self.constants.len() as u64);
76
77 for c in &self.constants {
78 match c.r#type {
79 Type::Type_Nil => {
80 write_byte(ss, LuauBytecodeTag::LBC_CONSTANT_NIL.0 as u8);
81 }
82 Type::Type_Boolean => {
83 write_byte(ss, LuauBytecodeTag::LBC_CONSTANT_BOOLEAN.0 as u8);
84 write_byte(ss, unsafe { c.value.valueBoolean } as u8);
85 }
86 Type::Type_Number => {
87 write_byte(ss, LuauBytecodeTag::LBC_CONSTANT_NUMBER.0 as u8);
88 write_double(ss, unsafe { c.value.valueNumber });
89 }
90 Type::Type_Integer => {
91 write_byte(ss, LuauBytecodeTag::LBC_CONSTANT_INTEGER.0 as u8);
92 let value = unsafe { c.value.valueInteger64 };
93 if value < 0 {
94 write_byte(ss, 1);
95 write_var_int(ss, (!(value as u64)).wrapping_add(1));
96 } else {
97 write_byte(ss, 0);
98 write_var_int(ss, value as u64);
99 }
100 }
101 Type::Type_Vector => {
102 write_byte(ss, LuauBytecodeTag::LBC_CONSTANT_VECTOR.0 as u8);
103 let vec = unsafe { c.value.valueVector };
104 write_float(ss, vec[0]);
105 write_float(ss, vec[1]);
106 write_float(ss, vec[2]);
107 write_float(ss, vec[3]);
108 }
109 Type::Type_String => {
110 write_byte(ss, LuauBytecodeTag::LBC_CONSTANT_STRING.0 as u8);
111 write_var_int(ss, unsafe { c.value.valueString } as u64);
112 }
113 Type::Type_Import => {
114 write_byte(ss, LuauBytecodeTag::LBC_CONSTANT_IMPORT.0 as u8);
115 write_int(ss, unsafe { c.value.valueImport } as i32);
116 }
117 Type::Type_Table => {
118 let shape = &self.table_shapes[unsafe { c.value.valueTable } as usize];
119 if FFlag::LuauCompileDuptableConstantPack2.get() && shape.hasConstants {
120 write_byte(
121 ss,
122 LuauBytecodeTag::LBC_CONSTANT_TABLE_WITH_CONSTANTS.0 as u8,
123 );
124 write_var_int(ss, shape.length as u64);
125 for i in 0..shape.length as usize {
126 write_var_int(ss, shape.keys[i] as u64);
127 write_int(ss, shape.constants[i]);
128 }
129 } else {
130 write_byte(ss, LuauBytecodeTag::LBC_CONSTANT_TABLE.0 as u8);
131 write_var_int(ss, shape.length as u64);
132 for i in 0..shape.length as usize {
133 write_var_int(ss, shape.keys[i] as u64);
134 }
135 }
136 }
137 Type::Type_Closure => {
138 write_byte(ss, LuauBytecodeTag::LBC_CONSTANT_CLOSURE.0 as u8);
139 write_var_int(ss, unsafe { c.value.valueClosure } as u64);
140 }
141 Type::Type_ClassShape => {
142 write_byte(ss, LuauBytecodeTag::LBC_CONSTANT_CLASS_SHAPE.0 as u8);
143 let cs = &self.class_shapes[unsafe { c.value.valueClassShape } as usize];
144 self.write_class_shape(ss, cs);
145 }
146 }
147 }
148
149 write_var_int(ss, self.protos.len() as u64);
151
152 for &child in &self.protos {
153 write_var_int(ss, child as u64);
154 }
155
156 write_var_int(ss, func.debuglinedefined as u64);
158 write_var_int(ss, func.debugname as u64);
159
160 let mut has_lines = true;
161
162 for &line in &self.lines {
163 if line == 0 {
164 has_lines = false;
165 break;
166 }
167 }
168
169 if has_lines {
170 write_byte(ss, 1);
171
172 self.write_line_info(ss);
173 } else {
174 write_byte(ss, 0);
175 }
176
177 let has_debug = !self.debug_locals.is_empty() || !self.debug_upvals.is_empty();
178
179 if has_debug {
180 write_byte(ss, 1);
181
182 write_var_int(ss, self.debug_locals.len() as u64);
183
184 for l in &self.debug_locals {
185 write_var_int(ss, l.name as u64);
186 write_var_int(ss, l.startpc as u64);
187 write_var_int(ss, l.endpc as u64);
188 write_byte(ss, l.reg);
189 }
190
191 write_var_int(ss, self.debug_upvals.len() as u64);
192
193 for l in &self.debug_upvals {
194 write_var_int(ss, l.name as u64);
195 }
196 } else {
197 write_byte(ss, 0);
198 }
199
200 if FFlag::LuauEmitCallFeedback.get() {
201 write_var_int(ss, self.fb_slots.len() as u64);
203 for &pc in &self.fb_slots {
204 write_byte(ss, LuauFeedbackType::LFT_CALLTARGET as u8);
205 write_var_int(ss, pc as u64);
206 }
207 }
208 }
209}