luaur_bytecode/methods/
call_inliner_validate_cfg.rs1use 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}