1 //! Constants 2 //! 3 //! The constant pool defined here allows Cranelift to avoid emitting the same constant multiple 4 //! times. As constants are inserted in the pool, a handle is returned; the handle is a Cranelift 5 //! Entity. Inserting the same data multiple times will always return the same handle. 6 //! 7 //! Future work could include: 8 //! - ensuring alignment of constants within the pool, 9 //! - bucketing constants by size. 10 11 use crate::ir::immediates::{IntoBytes, V128Imm}; 12 use crate::ir::Constant; 13 use alloc::collections::BTreeMap; 14 use alloc::vec::Vec; 15 use core::fmt; 16 use core::iter::FromIterator; 17 use core::slice::Iter; 18 use core::str::{from_utf8, FromStr}; 19 use cranelift_entity::EntityRef; 20 21 #[cfg(feature = "enable-serde")] 22 use serde::{Deserialize, Serialize}; 23 24 /// This type describes the actual constant data. Note that the bytes stored in this structure are 25 /// expected to be in little-endian order; this is due to ease-of-use when interacting with 26 /// WebAssembly values, which are [little-endian by design]. 27 /// 28 /// [little-endian by design]: https://github.com/WebAssembly/design/blob/master/Portability.md 29 #[derive(Clone, Hash, Eq, PartialEq, Debug, Default, PartialOrd, Ord)] 30 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 31 pub struct ConstantData(Vec<u8>); 32 33 impl FromIterator<u8> for ConstantData { 34 fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Self { 35 let v = iter.into_iter().collect(); 36 Self(v) 37 } 38 } 39 40 impl From<Vec<u8>> for ConstantData { 41 fn from(v: Vec<u8>) -> Self { 42 Self(v) 43 } 44 } 45 46 impl From<&[u8]> for ConstantData { 47 fn from(v: &[u8]) -> Self { 48 Self(v.to_vec()) 49 } 50 } 51 52 impl From<V128Imm> for ConstantData { 53 fn from(v: V128Imm) -> Self { 54 Self(v.to_vec()) 55 } 56 } 57 58 impl ConstantData { 59 /// Return the number of bytes in the constant. 60 pub fn len(&self) -> usize { 61 self.0.len() 62 } 63 64 /// Check if the constant contains any bytes. 65 pub fn is_empty(&self) -> bool { 66 self.0.is_empty() 67 } 68 69 /// Return the data as a slice. 70 pub fn as_slice(&self) -> &[u8] { 71 self.0.as_slice() 72 } 73 74 /// Convert the data to a vector. 75 pub fn into_vec(self) -> Vec<u8> { 76 self.0 77 } 78 79 /// Iterate over the constant's bytes. 80 pub fn iter(&self) -> Iter<u8> { 81 self.0.iter() 82 } 83 84 /// Add new bytes to the constant data. 85 pub fn append(mut self, bytes: impl IntoBytes) -> Self { 86 let mut to_add = bytes.into_bytes(); 87 self.0.append(&mut to_add); 88 self 89 } 90 91 /// Expand the size of the constant data to `expected_size` number of bytes by adding zeroes 92 /// in the high-order byte slots. 93 pub fn expand_to(mut self, expected_size: usize) -> Self { 94 if self.len() > expected_size { 95 panic!( 96 "The constant data is already expanded beyond {} bytes", 97 expected_size 98 ) 99 } 100 self.0.resize(expected_size, 0); 101 self 102 } 103 } 104 105 impl fmt::Display for ConstantData { 106 /// Print the constant data in hexadecimal format, e.g. 0x000102030405060708090a0b0c0d0e0f. 107 /// This function will flip the stored order of bytes--little-endian--to the more readable 108 /// big-endian ordering. 109 /// 110 /// ``` 111 /// use cranelift_codegen::ir::ConstantData; 112 /// let data = ConstantData::from([3, 2, 1, 0, 0].as_ref()); // note the little-endian order 113 /// assert_eq!(data.to_string(), "0x0000010203"); 114 /// ``` 115 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 116 if !self.is_empty() { 117 write!(f, "0x")?; 118 for b in self.0.iter().rev() { 119 write!(f, "{:02x}", b)?; 120 } 121 } 122 Ok(()) 123 } 124 } 125 126 impl FromStr for ConstantData { 127 type Err = &'static str; 128 129 /// Parse a hexadecimal string to `ConstantData`. This is the inverse of `Display::fmt`. 130 /// 131 /// ``` 132 /// use cranelift_codegen::ir::ConstantData; 133 /// let c: ConstantData = "0x000102".parse().unwrap(); 134 /// assert_eq!(c.into_vec(), [2, 1, 0]); 135 /// ``` 136 fn from_str(s: &str) -> Result<Self, &'static str> { 137 if s.len() <= 2 || &s[0..2] != "0x" { 138 return Err("Expected a hexadecimal string, e.g. 0x1234"); 139 } 140 141 // clean and check the string 142 let cleaned: Vec<u8> = s[2..] 143 .as_bytes() 144 .iter() 145 .filter(|&&b| b as char != '_') 146 .cloned() 147 .collect(); // remove 0x prefix and any intervening _ characters 148 149 if cleaned.is_empty() { 150 Err("Hexadecimal string must have some digits") 151 } else if cleaned.len() % 2 != 0 { 152 Err("Hexadecimal string must have an even number of digits") 153 } else if cleaned.len() > 32 { 154 Err("Hexadecimal string has too many digits to fit in a 128-bit vector") 155 } else { 156 let mut buffer = Vec::with_capacity((s.len() - 2) / 2); 157 for i in (0..cleaned.len()).step_by(2) { 158 let pair = from_utf8(&cleaned[i..i + 2]) 159 .or_else(|_| Err("Unable to parse hexadecimal pair as UTF-8"))?; 160 let byte = u8::from_str_radix(pair, 16) 161 .or_else(|_| Err("Unable to parse as hexadecimal"))?; 162 buffer.insert(0, byte); 163 } 164 Ok(Self(buffer)) 165 } 166 } 167 } 168 169 /// Maintains the mapping between a constant handle (i.e. [`Constant`](crate::ir::Constant)) and 170 /// its constant data (i.e. [`ConstantData`](crate::ir::ConstantData)). 171 #[derive(Clone, PartialEq, Hash)] 172 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 173 pub struct ConstantPool { 174 /// This mapping maintains the insertion order as long as Constants are created with 175 /// sequentially increasing integers. 176 /// 177 /// It is important that, by construction, no entry in that list gets removed. If that ever 178 /// need to happen, don't forget to update the `Constant` generation scheme. 179 handles_to_values: BTreeMap<Constant, ConstantData>, 180 181 /// Mapping of hashed `ConstantData` to the index into the other hashmap. 182 /// 183 /// This allows for deduplication of entries into the `handles_to_values` mapping. 184 values_to_handles: BTreeMap<ConstantData, Constant>, 185 } 186 187 impl ConstantPool { 188 /// Create a new constant pool instance. 189 pub fn new() -> Self { 190 Self { 191 handles_to_values: BTreeMap::new(), 192 values_to_handles: BTreeMap::new(), 193 } 194 } 195 196 /// Empty the constant pool of all data. 197 pub fn clear(&mut self) { 198 self.handles_to_values.clear(); 199 self.values_to_handles.clear(); 200 } 201 202 /// Insert constant data into the pool, returning a handle for later referencing; when constant 203 /// data is inserted that is a duplicate of previous constant data, the existing handle will be 204 /// returned. 205 pub fn insert(&mut self, constant_value: ConstantData) -> Constant { 206 if let Some(cst) = self.values_to_handles.get(&constant_value) { 207 return *cst; 208 } 209 210 let constant_handle = Constant::new(self.len()); 211 self.set(constant_handle, constant_value); 212 constant_handle 213 } 214 215 /// Retrieve the constant data given a handle. 216 pub fn get(&self, constant_handle: Constant) -> &ConstantData { 217 assert!(self.handles_to_values.contains_key(&constant_handle)); 218 self.handles_to_values.get(&constant_handle).unwrap() 219 } 220 221 /// Link a constant handle to its value. This does not de-duplicate data but does avoid 222 /// replacing any existing constant values. use `set` to tie a specific `const42` to its value; 223 /// use `insert` to add a value and return the next available `const` entity. 224 pub fn set(&mut self, constant_handle: Constant, constant_value: ConstantData) { 225 let replaced = self 226 .handles_to_values 227 .insert(constant_handle, constant_value.clone()); 228 assert!( 229 replaced.is_none(), 230 "attempted to overwrite an existing constant {:?}: {:?} => {:?}", 231 constant_handle, 232 &constant_value, 233 replaced.unwrap() 234 ); 235 self.values_to_handles 236 .insert(constant_value, constant_handle); 237 } 238 239 /// Iterate over the constants in insertion order. 240 pub fn iter(&self) -> impl Iterator<Item = (&Constant, &ConstantData)> { 241 self.handles_to_values.iter() 242 } 243 244 /// Iterate over mutable entries in the constant pool in insertion order. 245 pub fn entries_mut(&mut self) -> impl Iterator<Item = &mut ConstantData> { 246 self.handles_to_values.values_mut() 247 } 248 249 /// Return the number of constants in the pool. 250 pub fn len(&self) -> usize { 251 self.handles_to_values.len() 252 } 253 254 /// Return the combined size of all of the constant values in the pool. 255 pub fn byte_size(&self) -> usize { 256 self.handles_to_values.values().map(|c| c.len()).sum() 257 } 258 } 259 260 #[cfg(test)] 261 mod tests { 262 use super::*; 263 use std::string::ToString; 264 265 #[test] 266 fn empty() { 267 let sut = ConstantPool::new(); 268 assert_eq!(sut.len(), 0); 269 } 270 271 #[test] 272 fn insert() { 273 let mut sut = ConstantPool::new(); 274 sut.insert(vec![1, 2, 3].into()); 275 sut.insert(vec![4, 5, 6].into()); 276 assert_eq!(sut.len(), 2); 277 } 278 279 #[test] 280 fn insert_duplicate() { 281 let mut sut = ConstantPool::new(); 282 let a = sut.insert(vec![1, 2, 3].into()); 283 sut.insert(vec![4, 5, 6].into()); 284 let b = sut.insert(vec![1, 2, 3].into()); 285 assert_eq!(a, b); 286 } 287 288 #[test] 289 fn clear() { 290 let mut sut = ConstantPool::new(); 291 sut.insert(vec![1, 2, 3].into()); 292 assert_eq!(sut.len(), 1); 293 294 sut.clear(); 295 assert_eq!(sut.len(), 0); 296 } 297 298 #[test] 299 fn iteration_order() { 300 let mut sut = ConstantPool::new(); 301 sut.insert(vec![1, 2, 3].into()); 302 sut.insert(vec![4, 5, 6].into()); 303 sut.insert(vec![1, 2, 3].into()); 304 let data = sut.iter().map(|(_, v)| v).collect::<Vec<&ConstantData>>(); 305 assert_eq!(data, vec![&vec![1, 2, 3].into(), &vec![4, 5, 6].into()]); 306 } 307 308 #[test] 309 fn get() { 310 let mut sut = ConstantPool::new(); 311 let data = vec![1, 2, 3]; 312 let handle = sut.insert(data.clone().into()); 313 assert_eq!(sut.get(handle), &data.into()); 314 } 315 316 #[test] 317 fn set() { 318 let mut sut = ConstantPool::new(); 319 let handle = Constant::with_number(42).unwrap(); 320 let data = vec![1, 2, 3]; 321 sut.set(handle, data.clone().into()); 322 assert_eq!(sut.get(handle), &data.into()); 323 } 324 325 #[test] 326 #[should_panic] 327 fn disallow_overwriting_constant() { 328 let mut sut = ConstantPool::new(); 329 let handle = Constant::with_number(42).unwrap(); 330 sut.set(handle, vec![].into()); 331 sut.set(handle, vec![1].into()); 332 } 333 334 #[test] 335 #[should_panic] 336 fn get_nonexistent_constant() { 337 let sut = ConstantPool::new(); 338 let a = Constant::with_number(42).unwrap(); 339 sut.get(a); // panics, only use constants returned by ConstantPool 340 } 341 342 #[test] 343 fn display_constant_data() { 344 assert_eq!(ConstantData::from([0].as_ref()).to_string(), "0x00"); 345 assert_eq!(ConstantData::from([42].as_ref()).to_string(), "0x2a"); 346 assert_eq!( 347 ConstantData::from([3, 2, 1, 0].as_ref()).to_string(), 348 "0x00010203" 349 ); 350 assert_eq!( 351 ConstantData::from(3735928559u32.to_le_bytes().as_ref()).to_string(), 352 "0xdeadbeef" 353 ); 354 assert_eq!( 355 ConstantData::from(0x0102030405060708u64.to_le_bytes().as_ref()).to_string(), 356 "0x0102030405060708" 357 ); 358 } 359 360 #[test] 361 fn iterate_over_constant_data() { 362 let c = ConstantData::from([1, 2, 3].as_ref()); 363 let mut iter = c.iter(); 364 assert_eq!(iter.next(), Some(&1)); 365 assert_eq!(iter.next(), Some(&2)); 366 assert_eq!(iter.next(), Some(&3)); 367 assert_eq!(iter.next(), None); 368 } 369 370 #[test] 371 fn add_to_constant_data() { 372 let d = ConstantData::from([1, 2].as_ref()); 373 let e = d.append(i16::from(3u8)); 374 assert_eq!(e.into_vec(), vec![1, 2, 3, 0]) 375 } 376 377 #[test] 378 fn extend_constant_data() { 379 let d = ConstantData::from([1, 2].as_ref()); 380 assert_eq!(d.expand_to(4).into_vec(), vec![1, 2, 0, 0]) 381 } 382 383 #[test] 384 #[should_panic] 385 fn extend_constant_data_to_invalid_length() { 386 ConstantData::from([1, 2].as_ref()).expand_to(1); 387 } 388 389 #[test] 390 fn parse_constant_data_and_restringify() { 391 // Verify that parsing of `from` succeeds and stringifies to `to`. 392 fn parse_ok(from: &str, to: &str) { 393 let parsed = from.parse::<ConstantData>().unwrap(); 394 assert_eq!(parsed.to_string(), to); 395 } 396 397 // Verify that parsing of `from` fails with `error_msg`. 398 fn parse_err(from: &str, error_msg: &str) { 399 let parsed = from.parse::<ConstantData>(); 400 assert!( 401 parsed.is_err(), 402 "Expected a parse error but parsing succeeded: {}", 403 from 404 ); 405 assert_eq!(parsed.err().unwrap(), error_msg); 406 } 407 408 parse_ok("0x00", "0x00"); 409 parse_ok("0x00000042", "0x00000042"); 410 parse_ok( 411 "0x0102030405060708090a0b0c0d0e0f00", 412 "0x0102030405060708090a0b0c0d0e0f00", 413 ); 414 parse_ok("0x_0000_0043_21", "0x0000004321"); 415 416 parse_err("", "Expected a hexadecimal string, e.g. 0x1234"); 417 parse_err("0x", "Expected a hexadecimal string, e.g. 0x1234"); 418 parse_err( 419 "0x042", 420 "Hexadecimal string must have an even number of digits", 421 ); 422 parse_err( 423 "0x00000000000000000000000000000000000000000000000000", 424 "Hexadecimal string has too many digits to fit in a 128-bit vector", 425 ); 426 parse_err("0xrstu", "Unable to parse as hexadecimal"); 427 parse_err("0x__", "Hexadecimal string must have some digits"); 428 } 429 430 #[test] 431 fn verify_stored_bytes_in_constant_data() { 432 assert_eq!("0x01".parse::<ConstantData>().unwrap().into_vec(), [1]); 433 assert_eq!(ConstantData::from([1, 0].as_ref()).0, [1, 0]); 434 assert_eq!(ConstantData::from(vec![1, 0, 0, 0]).0, [1, 0, 0, 0]); 435 } 436 437 #[test] 438 fn check_constant_data_endianness_as_uimm128() { 439 fn parse_to_uimm128(from: &str) -> Vec<u8> { 440 from.parse::<ConstantData>() 441 .unwrap() 442 .expand_to(16) 443 .into_vec() 444 } 445 446 assert_eq!( 447 parse_to_uimm128("0x42"), 448 [0x42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 449 ); 450 assert_eq!( 451 parse_to_uimm128("0x00"), 452 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 453 ); 454 assert_eq!( 455 parse_to_uimm128("0x12345678"), 456 [0x78, 0x56, 0x34, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 457 ); 458 assert_eq!( 459 parse_to_uimm128("0x1234_5678"), 460 [0x78, 0x56, 0x34, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 461 ); 462 } 463 } 464