1 //! Jump table representation. 2 //! 3 //! Jump tables are declared in the preamble and assigned an `ir::entities::JumpTable` reference. 4 //! The actual table of destinations is stored in a `JumpTableData` struct defined in this module. 5 6 use crate::ir::entities::Block; 7 use alloc::vec::Vec; 8 use core::fmt::{self, Display, Formatter}; 9 use core::slice::{Iter, IterMut}; 10 11 /// Contents of a jump table. 12 /// 13 /// All jump tables use 0-based indexing and are densely populated. 14 #[derive(Clone)] 15 pub struct JumpTableData { 16 // Table entries. 17 table: Vec<Block>, 18 } 19 20 impl JumpTableData { 21 /// Create a new empty jump table. new() -> Self22 pub fn new() -> Self { 23 Self { table: Vec::new() } 24 } 25 26 /// Create a new empty jump table with the specified capacity. with_capacity(capacity: usize) -> Self27 pub fn with_capacity(capacity: usize) -> Self { 28 Self { 29 table: Vec::with_capacity(capacity), 30 } 31 } 32 33 /// Get the number of table entries. len(&self) -> usize34 pub fn len(&self) -> usize { 35 self.table.len() 36 } 37 38 /// Append a table entry. push_entry(&mut self, dest: Block)39 pub fn push_entry(&mut self, dest: Block) { 40 self.table.push(dest) 41 } 42 43 /// Checks if any of the entries branch to `block`. branches_to(&self, block: Block) -> bool44 pub fn branches_to(&self, block: Block) -> bool { 45 self.table.iter().any(|target_block| *target_block == block) 46 } 47 48 /// Access the whole table as a slice. as_slice(&self) -> &[Block]49 pub fn as_slice(&self) -> &[Block] { 50 self.table.as_slice() 51 } 52 53 /// Access the whole table as a mutable slice. as_mut_slice(&mut self) -> &mut [Block]54 pub fn as_mut_slice(&mut self) -> &mut [Block] { 55 self.table.as_mut_slice() 56 } 57 58 /// Returns an iterator over the table. iter(&self) -> Iter<Block>59 pub fn iter(&self) -> Iter<Block> { 60 self.table.iter() 61 } 62 63 /// Returns an iterator that allows modifying each value. iter_mut(&mut self) -> IterMut<Block>64 pub fn iter_mut(&mut self) -> IterMut<Block> { 65 self.table.iter_mut() 66 } 67 } 68 69 impl Display for JumpTableData { fmt(&self, fmt: &mut Formatter) -> fmt::Result70 fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { 71 write!(fmt, "jump_table [")?; 72 match self.table.first() { 73 None => (), 74 Some(first) => write!(fmt, "{}", first)?, 75 } 76 for block in self.table.iter().skip(1) { 77 write!(fmt, ", {}", block)?; 78 } 79 write!(fmt, "]") 80 } 81 } 82 83 #[cfg(test)] 84 mod tests { 85 use super::JumpTableData; 86 use crate::entity::EntityRef; 87 use crate::ir::Block; 88 use alloc::string::ToString; 89 90 #[test] empty()91 fn empty() { 92 let jt = JumpTableData::new(); 93 94 assert_eq!(jt.as_slice().get(0), None); 95 assert_eq!(jt.as_slice().get(10), None); 96 97 assert_eq!(jt.to_string(), "jump_table []"); 98 99 let v = jt.as_slice(); 100 assert_eq!(v, []); 101 } 102 103 #[test] insert()104 fn insert() { 105 let e1 = Block::new(1); 106 let e2 = Block::new(2); 107 108 let mut jt = JumpTableData::new(); 109 110 jt.push_entry(e1); 111 jt.push_entry(e2); 112 jt.push_entry(e1); 113 114 assert_eq!(jt.to_string(), "jump_table [block1, block2, block1]"); 115 116 let v = jt.as_slice(); 117 assert_eq!(v, [e1, e2, e1]); 118 } 119 } 120