Skip to main content

luaur_bytecode/functions/
to_function_bytecode_bytecode_graph.rs

1use crate::enums::bc_vm_const_kind::BcVmConstKind;
2use crate::records::bytecode_builder::BytecodeBuilder;
3use crate::records::comp_time_bytecode_graph_serializer::CompTimeBytecodeGraphSerializer;
4use crate::records::string_ref::StringRef;
5use crate::type_aliases::comp_time_bc_function::CompTimeBcFunction;
6use alloc::string::String;
7use alloc::vec::Vec;
8use luaur_common::macros::luau_assert::LUAU_ASSERT;
9
10fn string_ref(value: &str) -> StringRef {
11    StringRef {
12        data: value.as_ptr() as *const i8,
13        length: value.len(),
14    }
15}
16
17pub fn to_function_bytecode_bytecode_builder_comp_time_bc_function(
18    bcb: &mut BytecodeBuilder,
19    fn_: &mut CompTimeBcFunction,
20) -> String {
21    let function_id = bcb.begin_function(fn_.numparams, fn_.is_vararg);
22
23    if !fn_.debugname.is_empty() {
24        bcb.set_debug_function_name(string_ref(&fn_.debugname));
25    }
26
27    bcb.set_debug_function_line_defined(fn_.linedefined as i32);
28    bcb.set_function_type_info(fn_.type_info.clone());
29
30    for t in &fn_.upvalue_types {
31        bcb.push_upval_type_info(*t);
32    }
33
34    for upval in &fn_.upvalue_names {
35        bcb.push_debug_upval(string_ref(upval));
36    }
37
38    let mut consts: Vec<u16> = Vec::with_capacity(fn_.constants.len());
39
40    for c in &fn_.constants {
41        match c.kind {
42            BcVmConstKind::Nil => consts.push(bcb.add_constant_nil() as u16),
43            BcVmConstKind::Boolean => {
44                consts.push(bcb.add_constant_boolean(unsafe { c.value.valueBoolean }) as u16)
45            }
46            BcVmConstKind::Number => {
47                consts.push(bcb.add_constant_number(unsafe { c.value.valueNumber }) as u16)
48            }
49            BcVmConstKind::Vector => {
50                let value = unsafe { c.value.valueVector };
51                consts.push(bcb.add_constant_vector(value[0], value[1], value[2], value[3]) as u16);
52            }
53            BcVmConstKind::String => consts
54                .push(bcb.add_constant_string(string_ref(unsafe { c.value.valueString })) as u16),
55            BcVmConstKind::Import => {
56                consts.push(bcb.add_import(unsafe { c.value.valueImport }) as u16)
57            }
58            BcVmConstKind::Table => {
59                let value_table = unsafe { c.value.valueTable };
60                LUAU_ASSERT!(value_table < fn_.table_shapes.len() as u32);
61                consts.push(bcb.add_constant_table(&fn_.table_shapes[value_table as usize]) as u16);
62            }
63            BcVmConstKind::Closure => {
64                consts.push(bcb.add_constant_closure(unsafe { c.value.valueClosure }) as u16)
65            }
66            BcVmConstKind::Integer => {
67                consts.push(bcb.add_constant_integer(unsafe { c.value.valueInteger }) as u16)
68            }
69        }
70    }
71
72    for fid in &fn_.protos {
73        bcb.add_child_function(*fid);
74    }
75
76    let mut serializer = CompTimeBytecodeGraphSerializer::comp_time_bytecode_graph_serializer_comp_time_bytecode_graph_serializer(bcb, fn_, &mut consts);
77    let insns_pc = serializer.emit_bytecode();
78
79    for local in &fn_.local_types {
80        let startpc = if local.startpc < insns_pc.len() as u32 {
81            insns_pc[local.startpc as usize]
82        } else {
83            bcb.get_debug_pc()
84        };
85        let endpc = if local.endpc < insns_pc.len() as u32 {
86            insns_pc[local.endpc as usize]
87        } else {
88            bcb.get_debug_pc()
89        };
90        bcb.push_local_type_info(local.r#type, local.reg, startpc, endpc);
91    }
92
93    for local in &fn_.locals {
94        let startpc = if local.startpc < insns_pc.len() as u32 {
95            insns_pc[local.startpc as usize]
96        } else {
97            bcb.get_debug_pc()
98        };
99        let endpc = if local.endpc < insns_pc.len() as u32 {
100            insns_pc[local.endpc as usize]
101        } else {
102            bcb.get_debug_pc()
103        };
104        bcb.push_debug_local(string_ref(local.varname), local.reg, startpc, endpc);
105    }
106
107    bcb.fold_jumps();
108    bcb.expand_jumps();
109    bcb.end_function(fn_.maxstacksize, fn_.nups, fn_.flags);
110
111    if serializer.error() {
112        return String::new();
113    }
114
115    bcb.get_function_data(function_id)
116}