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