1#![deny(missing_docs)]
4#![deny(missing_debug_implementations)]
5
6mod graph_impl;
7
8use frozen::Frozen;
9use std::cmp;
10use std::collections::btree_map;
11use std::collections::{BTreeMap, BTreeSet};
12use std::ops;
13use std::slice;
14use std::u32;
15
16#[derive(Debug)]
18pub struct ItemsBuilder {
19 size: u32,
20 size_added: u32,
21 parsed: BTreeSet<Id>,
22 items: BTreeMap<Id, Item>,
23 edges: BTreeMap<Id, BTreeSet<Id>>,
24 roots: BTreeSet<Id>,
25
26 data: BTreeMap<u32, (Id, u32)>,
29}
30
31impl ItemsBuilder {
32 pub fn new(size: u32) -> ItemsBuilder {
34 ItemsBuilder {
35 size,
36 size_added: 0,
37 parsed: Default::default(),
38 items: Default::default(),
39 edges: Default::default(),
40 roots: Default::default(),
41 data: Default::default(),
42 }
43 }
44
45 pub fn add_item(&mut self, item: Item) -> Id {
48 let id = item.id;
49 self.size_added += item.size;
50 self.items.insert(id, item);
51
52 let old_value = self.parsed.insert(id);
53 assert!(
54 old_value,
55 "should not parse the same key into multiple items"
56 );
57
58 id
59 }
60
61 pub fn add_root(&mut self, item: Item) -> Id {
64 let id = self.add_item(item);
65 self.roots.insert(id);
66 id
67 }
68
69 pub fn add_edge(&mut self, from: Id, to: Id) {
72 debug_assert!(self.items.contains_key(&from), "`from` is not known");
73 debug_assert!(self.items.contains_key(&to), "`to` is not known");
74
75 self.edges
76 .entry(from)
77 .or_insert_with(BTreeSet::new)
78 .insert(to);
79 }
80
81 pub fn link_data(&mut self, offset: i64, len: usize, id: Id) {
83 if offset >= 0 && offset <= i64::from(u32::MAX) && offset as usize + len < u32::MAX as usize
84 {
85 self.data.insert(offset as u32, (id, len as u32));
86 }
87 }
88
89 pub fn get_data(&self, offset: u32) -> Option<Id> {
91 self.data
92 .range(offset..)
93 .next()
94 .and_then(
95 |(start, &(id, len))| {
96 if offset < start + len {
97 Some(id)
98 } else {
99 None
100 }
101 },
102 )
103 }
104
105 pub fn size_added(&self) -> u32 {
107 self.size_added
108 }
109
110 pub fn finish(mut self) -> Items {
112 let meta_root_id = Id::root();
113 let meta_root = Item::new(meta_root_id, "<meta root>", 0, Misc::new());
114 self.items.insert(meta_root_id, meta_root);
115 self.edges.insert(meta_root_id, self.roots.clone());
116
117 Items {
118 size: self.size,
119 dominator_tree: None,
120 retained_sizes: None,
121 predecessors: None,
122 immediate_dominators: None,
123 items: Frozen::freeze(self.items),
124 edges: Frozen::freeze(
125 self.edges
126 .into_iter()
127 .map(|(from, tos)| (from, tos.into_iter().collect::<Vec<_>>()))
128 .collect(),
129 ),
130 roots: Frozen::freeze(self.roots),
131 meta_root: meta_root_id,
132 }
133 }
134}
135
136#[derive(Debug)]
141pub struct Items {
142 size: u32,
143 dominator_tree: Option<BTreeMap<Id, Vec<Id>>>,
144 immediate_dominators: Option<BTreeMap<Id, Id>>,
145 retained_sizes: Option<BTreeMap<Id, u32>>,
146 predecessors: Option<BTreeMap<Id, Vec<Id>>>,
147 items: Frozen<BTreeMap<Id, Item>>,
148 edges: Frozen<BTreeMap<Id, Vec<Id>>>,
149 roots: Frozen<BTreeSet<Id>>,
150 meta_root: Id,
151}
152
153impl ops::Index<Id> for Items {
154 type Output = Item;
155
156 fn index(&self, id: Id) -> &Item {
157 &self.items[&id]
158 }
159}
160
161impl Items {
162 pub fn iter(&self) -> Iter {
164 Iter {
165 inner: self.items.iter(),
166 }
167 }
168
169 pub fn neighbors(&self, id: Id) -> Neighbors {
171 Neighbors {
172 inner: self
173 .edges
174 .get(&id)
175 .map_or_else(|| [].iter(), |edges| edges.iter()),
176 }
177 }
178
179 pub fn predecessors(&self, id: Id) -> Predecessors {
181 Predecessors {
182 inner: self
183 .predecessors
184 .as_ref()
185 .expect("To access predecessors, must have already called compute_predecessors")
186 .get(&id)
187 .map_or_else(|| [].iter(), |edges| edges.iter()),
188 }
189 }
190
191 pub fn size(&self) -> u32 {
193 self.size
194 }
195
196 pub fn meta_root(&self) -> Id {
199 self.meta_root
200 }
201
202 pub fn compute_predecessors(&mut self) {
204 if self.predecessors.is_some() {
205 return;
206 }
207
208 let mut predecessors = BTreeMap::new();
209
210 for (from, tos) in self.edges.iter() {
211 for to in tos {
212 predecessors
213 .entry(*to)
214 .or_insert_with(BTreeSet::new)
215 .insert(*from);
216 }
217 }
218
219 self.predecessors = Some(
220 predecessors
221 .into_iter()
222 .map(|(k, v)| (k, v.into_iter().collect()))
223 .collect(),
224 );
225 }
226
227 pub fn compute_dominators(&mut self) {
229 if self.immediate_dominators.is_some() {
230 return;
231 }
232
233 let mut immediate_dominators = BTreeMap::new();
234 let dominators = petgraph::algo::dominators::simple_fast(&*self, self.meta_root);
235
236 for item in self.iter() {
237 if let Some(idom) = dominators.immediate_dominator(item.id()) {
238 immediate_dominators.insert(item.id(), idom);
239 }
240 }
241
242 self.immediate_dominators = Some(immediate_dominators);
243 }
244
245 pub fn immediate_dominators(&self) -> &BTreeMap<Id, Id> {
247 self.immediate_dominators
248 .as_ref()
249 .expect("must call compute_immediate_dominators before calling immediate_dominators")
250 }
251
252 pub fn compute_dominator_tree(&mut self) {
254 if self.dominator_tree.is_some() {
255 return;
256 }
257
258 let mut dominator_tree = BTreeMap::new();
259 let dominators = petgraph::algo::dominators::simple_fast(&*self, self.meta_root);
260 for item in self.iter() {
261 if let Some(idom) = dominators.immediate_dominator(item.id()) {
262 dominator_tree
263 .entry(idom)
264 .or_insert_with(BTreeSet::new)
265 .insert(item.id());
266 }
267 }
268
269 self.dominator_tree = Some(
270 dominator_tree
271 .into_iter()
272 .map(|(k, v)| (k, v.into_iter().collect()))
273 .collect(),
274 );
275 }
276
277 pub fn dominator_tree(&self) -> &BTreeMap<Id, Vec<Id>> {
281 self.dominator_tree
282 .as_ref()
283 .expect("must call compute_dominator_tree before calling dominator_tree")
284 }
285
286 pub fn compute_retained_sizes(&mut self) {
288 if self.retained_sizes.is_some() {
289 return;
290 }
291 self.compute_dominator_tree();
292
293 fn recursive_retained_size(
294 retained_sizes: &mut BTreeMap<Id, u32>,
295 items: &Items,
296 item: &Item,
297 dominator_tree: &BTreeMap<Id, Vec<Id>>,
298 ) -> u32 {
299 if let Some(rsize) = retained_sizes.get(&item.id()) {
304 return *rsize;
305 }
306
307 let mut rsize = item.size();
308 if let Some(children) = dominator_tree.get(&item.id()) {
309 for child in children {
310 rsize += recursive_retained_size(
311 retained_sizes,
312 items,
313 &items[*child],
314 dominator_tree,
315 );
316 }
317 }
318
319 let old_value = retained_sizes.insert(item.id(), rsize);
320 assert!(old_value.is_none());
323 rsize
324 }
325
326 let mut retained_sizes = BTreeMap::new();
327 {
328 let dominator_tree = self.dominator_tree.as_ref().unwrap();
329 for item in self.iter() {
330 recursive_retained_size(&mut retained_sizes, self, item, dominator_tree);
331 }
332 }
333 self.retained_sizes = Some(retained_sizes);
334 }
335
336 pub fn retained_size(&self, id: Id) -> u32 {
338 self.retained_sizes
339 .as_ref()
340 .expect(
341 "Cannot call retained_sizes unless compute_retained_sizes \
342 has already been called",
343 )
344 .get(&id)
345 .cloned()
346 .unwrap()
347 }
348
349 pub fn get_item_by_name(&self, name: &str) -> Option<&Item> {
351 for item in self.iter() {
352 if item.name() == name {
353 return Some(item);
354 }
355 }
356
357 None }
359}
360
361#[derive(Debug)]
363pub struct Neighbors<'a> {
364 inner: slice::Iter<'a, Id>,
365}
366
367impl<'a> Iterator for Neighbors<'a> {
368 type Item = Id;
369
370 #[inline]
371 fn next(&mut self) -> Option<Id> {
372 self.inner.next().cloned()
373 }
374}
375
376#[derive(Debug)]
378pub struct Predecessors<'a> {
379 inner: slice::Iter<'a, Id>,
380}
381
382impl<'a> Iterator for Predecessors<'a> {
383 type Item = Id;
384
385 #[inline]
386 fn next(&mut self) -> Option<Id> {
387 self.inner.next().cloned()
388 }
389}
390
391#[derive(Clone, Debug)]
393pub struct Iter<'a> {
394 inner: btree_map::Iter<'a, Id, Item>,
395}
396
397impl<'a> Iterator for Iter<'a> {
398 type Item = &'a Item;
399
400 fn next(&mut self) -> Option<Self::Item> {
401 self.inner.next().map(|(_, item)| item)
402 }
403}
404
405#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
408pub struct Id(u32, u32);
409
410impl Id {
411 pub fn section(section: usize) -> Id {
413 assert!(section < u32::MAX as usize);
414 Id(section as u32, u32::MAX)
415 }
416
417 pub fn entry(section: usize, index: usize) -> Id {
419 assert!(section < u32::MAX as usize);
420 assert!(index < u32::MAX as usize);
421 Id(section as u32, index as u32)
422 }
423
424 pub fn root() -> Id {
426 Id(u32::MAX, u32::MAX)
427 }
428
429 pub fn serializable(self) -> u64 {
431 let top = (u64::from(self.0)) << 32;
432 top | u64::from(self.1)
433 }
434}
435
436#[derive(Clone, Debug, PartialEq, Eq)]
438pub struct Item {
439 id: Id,
440 name: String,
441 size: u32,
442 kind: ItemKind,
443}
444
445impl Item {
446 pub fn new<S, K>(id: Id, name: S, size: u32, kind: K) -> Item
448 where
449 S: Into<String>,
450 K: Into<ItemKind>,
451 {
452 let name = name.into();
453 Item {
454 id,
455 name,
456 size,
457 kind: kind.into(),
458 }
459 }
460
461 #[inline]
463 pub fn id(&self) -> Id {
464 self.id
465 }
466
467 #[inline]
469 pub fn size(&self) -> u32 {
470 self.size
471 }
472
473 #[inline]
475 pub fn name(&self) -> &str {
476 if let ItemKind::Code(ref code) = self.kind {
477 code.demangled().unwrap_or(&self.name)
478 } else {
479 &self.name
480 }
481 }
482
483 #[inline]
485 pub fn kind(&self) -> &ItemKind {
486 &self.kind
487 }
488
489 #[inline]
492 pub fn monomorphization_of(&self) -> Option<&str> {
493 if let ItemKind::Code(ref code) = self.kind {
494 code.monomorphization_of()
495 } else {
496 None
497 }
498 }
499}
500
501impl PartialOrd for Item {
502 fn partial_cmp(&self, rhs: &Item) -> Option<cmp::Ordering> {
503 self.id.partial_cmp(&rhs.id)
504 }
505}
506
507impl Ord for Item {
508 fn cmp(&self, rhs: &Item) -> cmp::Ordering {
509 self.id.cmp(&rhs.id)
510 }
511}
512
513#[derive(Clone, Debug, PartialEq, Eq)]
515pub enum ItemKind {
516 Code(Code),
518
519 Data(Data),
522
523 Debug(DebugInfo),
525
526 Misc(Misc),
528}
529
530impl ItemKind {
531 pub fn is_data(&self) -> bool {
533 match self {
534 ItemKind::Data(_) => true,
535 _ => false,
536 }
537 }
538}
539
540impl From<Code> for ItemKind {
541 fn from(c: Code) -> ItemKind {
542 ItemKind::Code(c)
543 }
544}
545
546impl From<Data> for ItemKind {
547 fn from(d: Data) -> ItemKind {
548 ItemKind::Data(d)
549 }
550}
551
552impl From<DebugInfo> for ItemKind {
553 fn from(d: DebugInfo) -> ItemKind {
554 ItemKind::Debug(d)
555 }
556}
557
558impl From<Misc> for ItemKind {
559 fn from(m: Misc) -> ItemKind {
560 ItemKind::Misc(m)
561 }
562}
563
564#[derive(Clone, Debug, PartialEq, Eq)]
566pub struct Code {
567 demangled: Option<String>,
568 monomorphization_of: Option<String>,
569}
570
571impl Code {
572 pub fn new(name: &str) -> Code {
574 let demangled = Self::demangle(&name);
575 let monomorphization_of =
576 Self::extract_generic_function(demangled.as_ref().map(|s| s.as_str()).unwrap_or(name));
577 Code {
578 demangled,
579 monomorphization_of,
580 }
581 }
582
583 pub fn demangled(&self) -> Option<&str> {
585 self.demangled.as_ref().map(|s| s.as_str())
586 }
587
588 pub fn monomorphization_of(&self) -> Option<&str> {
591 self.monomorphization_of.as_ref().map(|s| s.as_str())
592 }
593
594 fn demangle(s: &str) -> Option<String> {
595 if let Ok(sym) = rustc_demangle::try_demangle(s) {
596 return Some(sym.to_string());
597 }
598
599 if !s.starts_with("_Z") && !s.starts_with("__Z") && !s.starts_with("_GLOBAL_") {
617 return Some(s.to_string());
618 }
619
620 if let Ok(sym) = cpp_demangle::Symbol::new(s) {
621 return Some(sym.to_string());
622 }
623
624 None
625 }
626
627 fn extract_generic_function(demangled: &str) -> Option<String> {
628 if let Some(idx) = demangled.rfind("::h") {
643 let idx2 = demangled.rfind("::").unwrap();
644 assert!(idx2 >= idx);
645 if idx2 == idx {
646 let generic = demangled[..idx].to_string();
647 return Some(generic);
648 }
649 }
650
651 let open_bracket = match demangled.char_indices().find(|&(_, ch)| ch == '<') {
655 None => return None,
656 Some((idx, _)) => idx,
657 };
658 let close_bracket = match demangled.char_indices().rev().find(|&(_, ch)| ch == '>') {
659 None => return None,
660 Some((idx, _)) => idx,
661 };
662
663 if close_bracket < open_bracket || open_bracket == 0 {
669 return None;
670 }
671
672 Some(demangled[..open_bracket].to_string())
675 }
676}
677
678#[derive(Clone, Debug, PartialEq, Eq)]
681pub struct Data {
682 ty: Option<String>,
683}
684
685impl Data {
686 pub fn new(ty: Option<String>) -> Data {
688 Data { ty }
689 }
690}
691
692#[derive(Clone, Debug, PartialEq, Eq, Default)]
694pub struct DebugInfo;
695
696impl DebugInfo {
697 pub fn new() -> DebugInfo {
699 DebugInfo
700 }
701}
702
703#[derive(Clone, Debug, PartialEq, Eq, Default)]
705pub struct Misc;
706
707impl Misc {
708 pub fn new() -> Misc {
710 Misc
711 }
712}