wasmtime_environ/stack_map.rs
1use cranelift_bitset::CompoundBitSet;
2use 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)]
10pub struct StackMap {
11 bits: CompoundBitSet,
12 frame_size: u32,
13}
14
15impl 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}