1pub mod default;
2pub mod graph;
3
4use crate::utils::source::get_fn_name_byid;
5use rustc_hir::def_id::DefId;
6use std::fmt::{self, Display};
7
8use crate::compat::{FxHashMap, FxHashSet};
9use graph::{InlineBinding, PathGraph};
10
11pub fn format_path_annotated(path: &[usize], graph: &PathGraph<'_>) -> String {
16 let blocks: Vec<String> = path
17 .iter()
18 .map(|&b| {
19 if graph.is_cleanup_block(b) {
20 format!("{}*", b)
21 } else {
22 b.to_string()
23 }
24 })
25 .collect();
26 format!("[{}]", blocks.join(", "))
27}
28
29#[derive(Debug, Clone)]
45pub struct PathTree {
46 root: Option<PathNode>,
47 len: usize,
48 block_fn: Vec<(DefId, usize)>,
52 inline_bindings: FxHashMap<usize, InlineBinding>,
54 inline_parents: FxHashMap<usize, DefId>,
59 inlined_call_blocks: FxHashSet<usize>,
61 truncated: bool,
64}
65
66#[derive(Debug, Clone)]
73pub struct PathNode {
74 pub block: usize,
75 pub children: Vec<PathNode>,
76 pub is_path_end: bool,
77}
78
79impl PathNode {
80 fn from_path(path: &[usize]) -> Self {
81 let mut node = PathNode {
82 block: path[0],
83 children: Vec::new(),
84 is_path_end: path.len() == 1,
85 };
86 if path.len() > 1 {
87 node.children.push(PathNode::from_path(&path[1..]));
88 }
89 node
90 }
91}
92
93impl PathTree {
94 pub fn new() -> Self {
95 PathTree {
96 root: None,
97 len: 0,
98 block_fn: Vec::new(),
99 inline_bindings: FxHashMap::default(),
100 inline_parents: FxHashMap::default(),
101 inlined_call_blocks: FxHashSet::default(),
102 truncated: false,
103 }
104 }
105
106 pub fn len(&self) -> usize {
107 self.len
108 }
109
110 pub fn is_truncated(&self) -> bool {
111 self.truncated
112 }
113
114 pub fn mark_truncated(&mut self) {
115 self.truncated = true;
116 }
117
118 pub fn is_empty(&self) -> bool {
119 self.len == 0
120 }
121
122 pub fn root(&self) -> Option<&PathNode> {
123 self.root.as_ref()
124 }
125
126 pub fn set_block_fn(
129 &mut self,
130 map: Vec<(DefId, usize)>,
131 bindings: FxHashMap<usize, InlineBinding>,
132 parents: FxHashMap<usize, DefId>,
133 inlined_calls: FxHashSet<usize>,
134 ) {
135 self.block_fn = map;
136 self.inline_bindings = bindings;
137 self.inline_parents = parents;
138 self.inlined_call_blocks = inlined_calls;
139 }
140
141 pub fn block_fn_of(&self, block: usize) -> Option<(DefId, usize)> {
144 self.block_fn.get(block).copied()
145 }
146
147 pub fn block_fns(&self) -> &[(DefId, usize)] {
149 &self.block_fn
150 }
151
152 pub fn inline_binding(&self, block: usize) -> Option<&InlineBinding> {
154 self.inline_bindings.get(&block)
155 }
156
157 pub fn inline_parent(&self, block: usize) -> Option<DefId> {
159 self.inline_parents.get(&block).copied()
160 }
161
162 pub fn is_inlined_call(&self, block: usize) -> bool {
164 self.inlined_call_blocks.contains(&block)
165 }
166
167 pub fn insert(&mut self, path: &[usize]) -> bool {
170 if path.is_empty() {
171 return false;
172 }
173
174 match &mut self.root {
175 None => {
176 self.root = Some(PathNode::from_path(path));
177 self.len = 1;
178 true
179 }
180 Some(root) => {
181 if root.block != path[0] {
182 return false;
183 }
184 if Self::insert_into(root, &path[1..]) {
185 self.len += 1;
186 true
187 } else {
188 false
189 }
190 }
191 }
192 }
193
194 fn insert_into(node: &mut PathNode, suffix: &[usize]) -> bool {
195 if suffix.is_empty() {
196 if node.is_path_end {
197 return false;
198 }
199 node.is_path_end = true;
200 return true;
201 }
202
203 let target = suffix[0];
204 for child in &mut node.children {
205 if child.block == target {
206 return Self::insert_into(child, &suffix[1..]);
207 }
208 }
209
210 node.children.push(PathNode::from_path(suffix));
211 true
212 }
213
214 pub fn contains(&self, path: &[usize]) -> bool {
216 let mut node = match self.root.as_ref() {
217 Some(n) => n,
218 None => return false,
219 };
220 if node.block != path[0] {
221 return false;
222 }
223 for &block in &path[1..] {
224 node = match node.children.iter().find(|c| c.block == block) {
225 Some(n) => n,
226 None => return false,
227 };
228 }
229 node.is_path_end
230 }
231
232 pub fn iter(&self) -> PathTreeIter<'_> {
234 PathTreeIter {
235 stack: self
236 .root
237 .as_ref()
238 .map(|r| vec![(r, vec![r.block])])
239 .unwrap_or_default(),
240 }
241 }
242
243 pub fn to_vecs(&self) -> Vec<Vec<usize>> {
245 self.iter().collect()
246 }
247
248 pub fn walk_prefixes<F>(&self, target_block: usize, f: &mut F) -> Result<(), ()>
256 where
257 F: FnMut(&[usize]) -> bool,
258 {
259 let Some(root) = self.root.as_ref() else {
260 return Ok(());
261 };
262 let mut path = Vec::new();
263 Self::walk_prefixes_impl(root, &mut path, target_block, false, f)
264 }
265
266 pub fn walk_all_prefixes<F>(&self, target_block: usize, f: &mut F) -> Result<(), ()>
270 where
271 F: FnMut(&[usize]) -> bool,
272 {
273 let Some(root) = self.root.as_ref() else {
274 return Ok(());
275 };
276 let mut path = Vec::new();
277 Self::walk_prefixes_impl(root, &mut path, target_block, true, f)
278 }
279
280 fn walk_prefixes_impl<F>(
281 node: &PathNode,
282 path: &mut Vec<usize>,
283 target_block: usize,
284 continue_past_target: bool,
285 f: &mut F,
286 ) -> Result<(), ()>
287 where
288 F: FnMut(&[usize]) -> bool,
289 {
290 path.push(node.block);
291 if node.block == target_block {
292 let cont = f(path);
293 if !cont {
294 path.pop();
295 return Err(());
296 }
297 if !continue_past_target {
298 path.pop();
299 return Ok(());
300 }
301 }
302 for child in &node.children {
303 Self::walk_prefixes_impl(child, path, target_block, continue_past_target, f)?;
304 }
305 path.pop();
306 Ok(())
307 }
308}
309
310impl Default for PathTree {
311 fn default() -> Self {
312 Self::new()
313 }
314}
315
316pub struct PathTreeIter<'a> {
322 stack: Vec<(&'a PathNode, Vec<usize>)>,
323}
324
325impl<'a> Iterator for PathTreeIter<'a> {
326 type Item = Vec<usize>;
327
328 fn next(&mut self) -> Option<Self::Item> {
329 loop {
330 let (node, path) = self.stack.pop()?;
331 for child in node.children.iter().rev() {
332 let mut child_path = path.clone();
333 child_path.push(child.block);
334 self.stack.push((child, child_path));
335 }
336 if node.is_path_end {
337 return Some(path);
338 }
339 }
340 }
341}
342
343pub struct PathMapWrapper<'a, 'tcx>(
346 pub FxHashMap<DefId, PathTree>,
347 pub &'a FxHashMap<DefId, PathGraph<'tcx>>,
348);
349
350impl Display for PathMapWrapper<'_, '_> {
351 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352 writeln!(f, "=== Print path analysis results ===")?;
353 for (def_id, paths) in &self.0 {
354 let fn_name = get_fn_name_byid(def_id);
355 if fn_name.contains("__raw_ptr_deref_dummy") {
356 continue;
357 }
358 writeln!(f, "Function: {:?}:", fn_name)?;
359 let graph = self.1.get(def_id);
360 for path in paths.iter() {
361 if let Some(g) = graph {
362 writeln!(f, " Path {}", format_path_annotated(&path, g))?;
363 } else {
364 writeln!(f, " Path {:?}", path)?;
365 }
366 }
367 }
368 Ok(())
369 }
370}