1 use cranelift_bitset::CompoundBitSet;
2 use serde_derive::{Deserialize, Serialize};
3 
4 /// A map for determining where live GC references live in a stack frame.
5 ///
6 /// Note that this is currently primarily documented as cranelift's
7 /// `binemit::StackMap`, so for detailed documentation about this please read
8 /// the docs over there.
9 #[derive(Debug, Serialize, Deserialize)]
10 pub struct StackMap {
11     bits: CompoundBitSet,
12     frame_size: u32,
13 }
14 
15 impl StackMap {
16     /// Creates a new `StackMap`, typically from a preexisting
17     /// `binemit::StackMap`.
18     pub fn new(frame_size: u32, bits: CompoundBitSet) -> StackMap {
19         StackMap { bits, frame_size }
20     }
21 
22     /// Returns the byte size of this stack map's frame.
23     pub fn frame_size(&self) -> u32 {
24         self.frame_size
25     }
26 
27     /// Given a frame pointer, get the stack pointer.
28     ///
29     /// # Safety
30     ///
31     /// The `fp` must be the frame pointer at the code offset that this stack
32     /// map is associated with.
33     pub unsafe fn sp(&self, fp: *mut usize) -> *mut usize {
34         let frame_size = usize::try_from(self.frame_size).unwrap();
35         fp.byte_sub(frame_size)
36     }
37 
38     /// Given the stack pointer, get a reference to each live GC reference in
39     /// the stack frame.
40     ///
41     /// # Safety
42     ///
43     /// The `sp` must be the stack pointer at the code offset that this stack
44     /// map is associated with.
45     pub unsafe fn live_gc_refs(&self, sp: *mut usize) -> impl Iterator<Item = *mut u32> + '_ {
46         self.bits.iter().map(move |i| {
47             log::trace!("Live GC ref in frame at frame offset {:#x}", i);
48             let ptr_to_gc_ref = sp.byte_add(i);
49 
50             // Assert that the pointer is inside this stack map's frame.
51             assert!({
52                 let delta = ptr_to_gc_ref as usize - sp as usize;
53                 let frame_size = usize::try_from(self.frame_size).unwrap();
54                 delta < frame_size
55             });
56 
57             ptr_to_gc_ref.cast::<u32>()
58         })
59     }
60 }
61