Skip to main content

luaur_bytecode/methods/
call_inliner_validate_cfg.rs

1use crate::enums::bc_block_flag::BcBlockFlag;
2use crate::enums::bc_op_kind::BcOpKind;
3use crate::records::bc_block::BcBlock;
4use crate::records::bc_block_edge::BcBlockEdge;
5use crate::records::call_inliner::CallInliner;
6use crate::type_aliases::bc_edges::BcEdges;
7
8impl<'a> CallInliner<'a> {
9    pub fn validate_cfg(&self) -> bool {
10        let validate_edges =
11            |from: u32, edges: &BcEdges, mirror_dir: fn(&BcBlock) -> &BcEdges| -> bool {
12                for edge in edges {
13                    if edge.target.kind != BcOpKind::Block
14                        || edge.target.index as usize >= self.caller.blocks.len()
15                    {
16                        return false;
17                    }
18
19                    let other = &self.caller.blocks[edge.target.index as usize];
20
21                    if (other.flags & BcBlockFlag::Dead as u8) != 0 {
22                        return false;
23                    }
24
25                    let mirror = mirror_dir(other);
26                    if !mirror.iter().any(|e| {
27                        e.kind == edge.kind
28                            && e.target.kind == BcOpKind::Block
29                            && e.target.index == from
30                    }) {
31                        return false;
32                    }
33                }
34                true
35            };
36
37        for i in 0..self.caller.blocks.len() {
38            let block = &self.caller.blocks[i];
39
40            if (block.flags & BcBlockFlag::Dead as u8) != 0 {
41                continue;
42            }
43
44            if !validate_edges(i as u32, &block.successors, |b| &b.predecessors) {
45                return false;
46            }
47
48            if !validate_edges(i as u32, &block.predecessors, |b| &b.successors) {
49                return false;
50            }
51        }
52
53        true
54    }
55}