wasmtime_environ/compile/
frame_table.rs1use crate::{
12 FrameInstPos, FrameStackShape, FrameStateSlotOffset, FrameTableDescriptorIndex, FrameValType,
13 FuncKey, WasmHeapTopType, WasmValType, prelude::*,
14};
15use object::{LittleEndian, U32Bytes};
16use std::collections::{HashMap, hash_map::Entry};
17
18pub struct FrameStateSlotBuilder {
20 func_key: FuncKey,
22
23 pointer_size: u32,
25
26 locals: Vec<(FrameValType, FrameStateSlotOffset)>,
28
29 stacks: Vec<(Option<FrameStackShape>, FrameValType, FrameStateSlotOffset)>,
31
32 stacks_dedup:
34 HashMap<(Option<FrameStackShape>, FrameValType, FrameStateSlotOffset), FrameStackShape>,
35
36 vmctx_size: u32,
38
39 locals_size: u32,
41
42 slot_size: u32,
44}
45
46impl From<WasmValType> for FrameValType {
47 fn from(ty: WasmValType) -> FrameValType {
48 match ty {
49 WasmValType::I32 => FrameValType::I32,
50 WasmValType::I64 => FrameValType::I64,
51 WasmValType::F32 => FrameValType::F32,
52 WasmValType::F64 => FrameValType::F64,
53 WasmValType::V128 => FrameValType::V128,
54 WasmValType::Ref(r) => match r.heap_type.top() {
55 WasmHeapTopType::Any => FrameValType::AnyRef,
56 WasmHeapTopType::Extern => FrameValType::ExternRef,
57 WasmHeapTopType::Func => FrameValType::FuncRef,
58 WasmHeapTopType::Exn => FrameValType::ExnRef,
59 WasmHeapTopType::Cont => FrameValType::ContRef,
60 },
61 }
62 }
63}
64
65impl FrameStateSlotBuilder {
66 pub fn new(func_key: FuncKey, pointer_size: u32) -> FrameStateSlotBuilder {
68 FrameStateSlotBuilder {
69 func_key,
70 pointer_size,
71 locals: vec![],
72 stacks: vec![],
73 stacks_dedup: HashMap::new(),
74 vmctx_size: pointer_size,
75 locals_size: 0,
76 slot_size: pointer_size,
77 }
78 }
79
80 pub fn add_local(&mut self, ty: FrameValType) -> FrameStateSlotOffset {
86 let offset = FrameStateSlotOffset(self.vmctx_size + self.locals_size);
89 let size = ty.storage_size(self.pointer_size);
90 self.locals_size += size;
91 self.slot_size += size;
92 self.locals.push((ty, offset));
93 offset
94 }
95
96 pub fn local_offset(&self, local: u32) -> FrameStateSlotOffset {
98 let index = usize::try_from(local).unwrap();
99 self.locals[index].1
100 }
101
102 pub fn push_stack(
105 &mut self,
106 parent: Option<FrameStackShape>,
107 ty: FrameValType,
108 ) -> (FrameStackShape, FrameStateSlotOffset) {
109 let offset = parent
110 .map(|parent| {
111 let (_, ty, offset) = self.stacks[parent.index()];
112 offset.add(ty.storage_size(self.pointer_size))
113 })
114 .unwrap_or(FrameStateSlotOffset(self.vmctx_size + self.locals_size));
118
119 self.slot_size = core::cmp::max(
120 self.slot_size,
121 offset.0 + ty.storage_size(self.pointer_size),
122 );
123
124 let shape = match self.stacks_dedup.entry((parent, ty, offset)) {
125 Entry::Occupied(o) => *o.get(),
126 Entry::Vacant(v) => {
127 let shape = FrameStackShape(u32::try_from(self.stacks.len()).unwrap());
128 self.stacks.push((parent, ty, offset));
129 *v.insert(shape)
130 }
131 };
132
133 (shape, offset)
134 }
135
136 pub fn stack_last_offset(&self, shape: FrameStackShape) -> FrameStateSlotOffset {
138 self.stacks[shape.index()].2
139 }
140
141 pub fn serialize(&self) -> Vec<u8> {
144 let mut buffer = vec![];
160 let (func_key_namespace, func_key_index) = self.func_key.into_parts();
161 buffer.extend_from_slice(&u32::to_le_bytes(func_key_namespace.into_raw()));
162 buffer.extend_from_slice(&u32::to_le_bytes(func_key_index.into_raw()));
163
164 buffer.extend_from_slice(&u32::to_le_bytes(u32::try_from(self.locals.len()).unwrap()));
165 buffer.extend_from_slice(&u32::to_le_bytes(u32::try_from(self.stacks.len()).unwrap()));
166
167 for (_, offset) in &self.locals {
168 buffer.extend_from_slice(&u32::to_le_bytes(offset.0));
169 }
170 for (parent, _, _) in &self.stacks {
171 let parent = parent.map(|p| p.0).unwrap_or(u32::MAX);
172 buffer.extend_from_slice(&u32::to_le_bytes(parent));
173 }
174 for (_, _, offset) in &self.stacks {
175 buffer.extend_from_slice(&u32::to_le_bytes(offset.0));
176 }
177 for (ty, _) in &self.locals {
178 buffer.push(*ty as u8);
179 }
180 for (_, ty, _) in &self.stacks {
181 buffer.push(*ty as u8);
182 }
183
184 buffer
185 }
186
187 pub fn size(&self) -> u32 {
189 self.slot_size
190 }
191}
192
193#[derive(Default)]
218pub struct FrameTableBuilder {
219 frame_descriptor_ranges: Vec<U32Bytes<LittleEndian>>,
222 frame_descriptor_data: Vec<u8>,
223
224 frame_descriptor_fp_offsets: Vec<U32Bytes<LittleEndian>>,
226
227 progpoint_pcs: Vec<U32Bytes<LittleEndian>>,
228 progpoint_descriptor_offsets: Vec<U32Bytes<LittleEndian>>,
229 progpoint_descriptor_data: Vec<U32Bytes<LittleEndian>>,
230}
231
232impl FrameTableBuilder {
233 pub fn add_frame_descriptor(
237 &mut self,
238 slot_to_fp_offset: u32,
239 data: &[u8],
240 ) -> FrameTableDescriptorIndex {
241 let start = u32::try_from(self.frame_descriptor_data.len()).unwrap();
242 self.frame_descriptor_data.extend(data.iter().cloned());
243 let end = u32::try_from(self.frame_descriptor_data.len()).unwrap();
244
245 let index = FrameTableDescriptorIndex(
246 u32::try_from(self.frame_descriptor_fp_offsets.len()).unwrap(),
247 );
248 self.frame_descriptor_fp_offsets
249 .push(U32Bytes::new(LittleEndian, slot_to_fp_offset));
250 self.frame_descriptor_ranges
251 .push(U32Bytes::new(LittleEndian, start));
252 self.frame_descriptor_ranges
253 .push(U32Bytes::new(LittleEndian, end));
254
255 index
256 }
257
258 pub fn add_program_point(
260 &mut self,
261 native_pc: u32,
262 pos: FrameInstPos,
263 frames: &[(u32, FrameTableDescriptorIndex, FrameStackShape)],
266 ) {
267 let pc_and_pos = FrameInstPos::encode(native_pc, pos);
268 while let Some(last) = self.progpoint_pcs.last()
271 && last.get(LittleEndian) == pc_and_pos
272 {
273 self.progpoint_pcs.pop();
274 self.progpoint_descriptor_offsets.pop();
275 self.progpoint_descriptor_data
276 .truncate(self.progpoint_descriptor_data.len() - 3);
277 }
278
279 let start = u32::try_from(self.progpoint_descriptor_data.len()).unwrap();
280 self.progpoint_pcs
281 .push(U32Bytes::new(LittleEndian, pc_and_pos));
282 self.progpoint_descriptor_offsets
283 .push(U32Bytes::new(LittleEndian, start));
284
285 for (i, &(wasm_pc, frame_descriptor, stack_shape)) in frames.iter().enumerate() {
286 debug_assert!(wasm_pc < 0x8000_0000);
287 let not_last = i < (frames.len() - 1);
288 let wasm_pc = wasm_pc | if not_last { 0x8000_0000 } else { 0 };
289 self.progpoint_descriptor_data
290 .push(U32Bytes::new(LittleEndian, wasm_pc));
291 self.progpoint_descriptor_data
292 .push(U32Bytes::new(LittleEndian, frame_descriptor.0));
293 self.progpoint_descriptor_data
294 .push(U32Bytes::new(LittleEndian, stack_shape.0));
295 }
296 }
297
298 pub fn serialize<F: FnMut(&[u8])>(&mut self, mut f: F) {
301 while self.frame_descriptor_data.len() & 3 != 0 {
304 self.frame_descriptor_data.push(0);
305 }
306
307 let num_frame_descriptors = u32::try_from(self.frame_descriptor_fp_offsets.len()).unwrap();
308 f(&num_frame_descriptors.to_le_bytes());
309 let num_prog_points = u32::try_from(self.progpoint_pcs.len()).unwrap();
310 f(&num_prog_points.to_le_bytes());
311
312 let frame_descriptor_pool_length = u32::try_from(self.frame_descriptor_data.len()).unwrap();
313 f(&frame_descriptor_pool_length.to_le_bytes());
314 let progpoint_descriptor_pool_length =
315 u32::try_from(self.progpoint_descriptor_data.len()).unwrap();
316 f(&progpoint_descriptor_pool_length.to_le_bytes());
317
318 f(object::bytes_of_slice(&self.frame_descriptor_ranges));
319 f(object::bytes_of_slice(&self.frame_descriptor_fp_offsets));
320 f(object::bytes_of_slice(&self.progpoint_pcs));
321 f(object::bytes_of_slice(&self.progpoint_descriptor_offsets));
322 f(&self.frame_descriptor_data);
323 f(object::bytes_of_slice(&self.progpoint_descriptor_data));
324 }
325}