wasmtime_environ/
stack_map.rs1use cranelift_bitset::ScalarBitSet;
2use object::{Bytes, LittleEndian, U32};
3
4struct StackMapSection<'a> {
5 pcs: &'a [U32<LittleEndian>],
6 pointers_to_stack_map: &'a [U32<LittleEndian>],
7 stack_map_data: &'a [U32<LittleEndian>],
8}
9
10impl<'a> StackMapSection<'a> {
11 fn parse(section: &'a [u8]) -> Option<StackMapSection<'a>> {
12 let mut section = Bytes(section);
13 let pc_count = section.read::<U32<LittleEndian>>().ok()?;
16 let pc_count = usize::try_from(pc_count.get(LittleEndian)).ok()?;
17 let (pcs, section) =
18 object::slice_from_bytes::<U32<LittleEndian>>(section.0, pc_count).ok()?;
19 let (pointers_to_stack_map, section) =
20 object::slice_from_bytes::<U32<LittleEndian>>(section, pc_count).ok()?;
21 let stack_map_data = object::slice_from_all_bytes::<U32<LittleEndian>>(section).ok()?;
22 Some(StackMapSection {
23 pcs,
24 pointers_to_stack_map,
25 stack_map_data,
26 })
27 }
28
29 fn lookup(&self, pc: u32) -> Option<StackMap<'a>> {
30 let pc_index = self
31 .pcs
32 .binary_search_by_key(&pc, |v| v.get(LittleEndian))
33 .ok()?;
34 self.get(pc_index)
35 }
36
37 fn into_iter(self) -> impl Iterator<Item = (u32, StackMap<'a>)> + 'a {
38 self.pcs
39 .iter()
40 .enumerate()
41 .map(move |(i, pc)| (pc.get(LittleEndian), self.get(i).unwrap()))
42 }
43
44 fn get(&self, i: usize) -> Option<StackMap<'a>> {
46 let pointer_to_stack_map = self.pointers_to_stack_map[i].get(LittleEndian) as usize;
47 let data = self.stack_map_data.get(pointer_to_stack_map..)?;
48
49 let (frame_size, data) = data.split_first()?;
50 let (count, data) = data.split_first()?;
51 let data = data.get(..count.get(LittleEndian) as usize)?;
52
53 Some(StackMap {
54 frame_size: frame_size.get(LittleEndian),
55 data,
56 })
57 }
58}
59
60pub struct StackMap<'a> {
66 frame_size: u32,
67 data: &'a [U32<LittleEndian>],
68}
69
70impl<'a> StackMap<'a> {
71 pub fn lookup(pc: u32, section: &'a [u8]) -> Option<StackMap<'a>> {
77 StackMapSection::parse(section)?.lookup(pc)
78 }
79
80 pub fn iter(section: &'a [u8]) -> Option<impl Iterator<Item = (u32, StackMap<'a>)> + 'a> {
89 Some(StackMapSection::parse(section)?.into_iter())
90 }
91
92 pub fn frame_size(&self) -> u32 {
94 self.frame_size
95 }
96
97 pub unsafe fn sp(&self, fp: *mut usize) -> *mut usize {
104 let frame_size = usize::try_from(self.frame_size).unwrap();
105 unsafe { fp.byte_sub(frame_size) }
106 }
107
108 pub unsafe fn live_gc_refs(&self, sp: *mut usize) -> impl Iterator<Item = *mut u32> + '_ {
116 self.offsets().map(move |i| {
117 log::trace!("Live GC ref in frame at frame offset {i:#x}");
118 let i = usize::try_from(i).unwrap();
119 let ptr_to_gc_ref = unsafe { sp.byte_add(i) };
120
121 assert!({
123 let delta = ptr_to_gc_ref as usize - sp as usize;
124 let frame_size = usize::try_from(self.frame_size).unwrap();
125 delta < frame_size
126 });
127
128 ptr_to_gc_ref.cast::<u32>()
129 })
130 }
131
132 pub fn offsets(&self) -> impl Iterator<Item = u32> + '_ {
134 let bit_positions = self.data.iter().enumerate().flat_map(|(i, word)| {
137 ScalarBitSet(word.get(LittleEndian))
138 .iter()
139 .map(move |bit| (i as u32) * 32 + u32::from(bit))
140 });
141
142 bit_positions.map(|pos| pos * 4)
143 }
144}