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