linera_wasmer_compiler/engine/trap/
frame_info.rs1use core::ops::Deref;
15use rkyv::vec::ArchivedVec;
16use std::cmp;
17use std::collections::BTreeMap;
18use std::sync::{Arc, RwLock};
19use wasmer_types::compilation::address_map::{
20 ArchivedFunctionAddressMap, ArchivedInstructionAddressMap,
21};
22use wasmer_types::compilation::function::ArchivedCompiledFunctionFrameInfo;
23use wasmer_types::entity::{BoxedSlice, EntityRef, PrimaryMap};
24use wasmer_types::{
25 CompiledFunctionFrameInfo, FrameInfo, FunctionAddressMap, InstructionAddressMap,
26 LocalFunctionIndex, ModuleInfo, SourceLoc, TrapInformation,
27};
28use wasmer_vm::FunctionBodyPtr;
29
30use crate::ArtifactBuildFromArchive;
31
32lazy_static::lazy_static! {
33 pub static ref FRAME_INFO: RwLock<GlobalFrameInfo> = Default::default();
39}
40
41#[derive(Default)]
42pub struct GlobalFrameInfo {
43 ranges: BTreeMap<usize, ModuleInfoFrameInfo>,
53}
54
55#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
58pub struct GlobalFrameInfoRegistration {
59 key: usize,
62}
63
64#[derive(Debug)]
65struct ModuleInfoFrameInfo {
66 start: usize,
67 functions: BTreeMap<usize, FunctionInfo>,
68 module: Arc<ModuleInfo>,
69 frame_infos: FrameInfosVariant,
70}
71
72impl ModuleInfoFrameInfo {
73 fn function_debug_info(
74 &self,
75 local_index: LocalFunctionIndex,
76 ) -> CompiledFunctionFrameInfoVariant {
77 self.frame_infos.get(local_index).unwrap()
78 }
79
80 fn function_info(&self, pc: usize) -> Option<&FunctionInfo> {
82 let (end, func) = self.functions.range(pc..).next()?;
83 if func.start <= pc && pc <= *end {
84 Some(func)
85 } else {
86 None
87 }
88 }
89}
90
91#[derive(Debug)]
92struct FunctionInfo {
93 start: usize,
94 local_index: LocalFunctionIndex,
95}
96
97impl GlobalFrameInfo {
98 pub fn lookup_frame_info(&self, pc: usize) -> Option<FrameInfo> {
103 let module = self.module_info(pc)?;
104 let func = module.function_info(pc)?;
105
106 let rel_pos = pc - func.start;
110 let debug_info = module.function_debug_info(func.local_index);
111 let instr_map = debug_info.address_map();
112 let pos = match instr_map.instructions().code_offset_by_key(rel_pos) {
113 Ok(pos) => Some(pos),
115
116 Err(0) => None,
119
120 Err(n) => {
126 let instr = &instr_map.instructions().get(n - 1);
127 if instr.code_offset <= rel_pos && rel_pos < instr.code_offset + instr.code_len {
128 Some(n - 1)
129 } else {
130 None
131 }
132 }
133 };
134
135 let instr = match pos {
136 Some(pos) => instr_map.instructions().get(pos).srcloc,
137 None => instr_map.start_srcloc(),
142 };
143 let func_index = module.module.func_index(func.local_index);
144 Some(FrameInfo::new(
145 module.module.name(),
146 func_index.index() as u32,
147 module.module.function_names.get(&func_index).cloned(),
148 instr_map.start_srcloc(),
149 instr,
150 ))
151 }
152
153 pub fn lookup_trap_info(&self, pc: usize) -> Option<TrapInformation> {
155 let module = self.module_info(pc)?;
156 let func = module.function_info(pc)?;
157 let debug_info = module.function_debug_info(func.local_index);
158 let traps = debug_info.traps();
159 let idx = traps
160 .binary_search_by_key(&((pc - func.start) as u32), |info| info.code_offset)
161 .ok()?;
162 Some(traps[idx])
163 }
164
165 fn module_info(&self, pc: usize) -> Option<&ModuleInfoFrameInfo> {
167 let (end, module_info) = self.ranges.range(pc..).next()?;
168 if module_info.start <= pc && pc <= *end {
169 Some(module_info)
170 } else {
171 None
172 }
173 }
174}
175
176impl Drop for GlobalFrameInfoRegistration {
177 fn drop(&mut self) {
178 if let Ok(mut info) = FRAME_INFO.write() {
179 info.ranges.remove(&self.key);
180 }
181 }
182}
183
184#[derive(Debug)]
187#[repr(C)]
188pub struct FunctionExtent {
189 pub ptr: FunctionBodyPtr,
192 pub length: usize,
194}
195
196#[derive(Debug)]
199pub enum FrameInfosVariant {
200 Owned(PrimaryMap<LocalFunctionIndex, CompiledFunctionFrameInfo>),
202 Archived(ArtifactBuildFromArchive),
204}
205
206impl FrameInfosVariant {
207 pub fn get(&self, index: LocalFunctionIndex) -> Option<CompiledFunctionFrameInfoVariant> {
209 match self {
210 Self::Owned(map) => map.get(index).map(CompiledFunctionFrameInfoVariant::Ref),
211 Self::Archived(archive) => archive
212 .get_frame_info_ref()
213 .get(index)
214 .map(CompiledFunctionFrameInfoVariant::Archived),
215 }
216 }
217}
218
219#[derive(Debug)]
221pub enum CompiledFunctionFrameInfoVariant<'a> {
222 Ref(&'a CompiledFunctionFrameInfo),
224 Archived(&'a ArchivedCompiledFunctionFrameInfo),
226}
227
228impl CompiledFunctionFrameInfoVariant<'_> {
229 pub fn address_map(&self) -> FunctionAddressMapVariant<'_> {
231 match self {
232 CompiledFunctionFrameInfoVariant::Ref(info) => {
233 FunctionAddressMapVariant::Ref(&info.address_map)
234 }
235 CompiledFunctionFrameInfoVariant::Archived(info) => {
236 FunctionAddressMapVariant::Archived(&info.address_map)
237 }
238 }
239 }
240
241 pub fn traps(&self) -> VecTrapInformationVariant {
243 match self {
244 CompiledFunctionFrameInfoVariant::Ref(info) => {
245 VecTrapInformationVariant::Ref(&info.traps)
246 }
247 CompiledFunctionFrameInfoVariant::Archived(info) => {
248 VecTrapInformationVariant::Archived(&info.traps)
249 }
250 }
251 }
252}
253
254#[derive(Debug)]
256pub enum VecTrapInformationVariant<'a> {
257 Ref(&'a Vec<TrapInformation>),
258 Archived(&'a ArchivedVec<TrapInformation>),
259}
260
261impl Deref for VecTrapInformationVariant<'_> {
262 type Target = [TrapInformation];
263
264 fn deref(&self) -> &Self::Target {
265 match self {
266 VecTrapInformationVariant::Ref(traps) => traps,
267 VecTrapInformationVariant::Archived(traps) => traps,
268 }
269 }
270}
271
272#[derive(Debug)]
273pub enum FunctionAddressMapVariant<'a> {
274 Ref(&'a FunctionAddressMap),
275 Archived(&'a ArchivedFunctionAddressMap),
276}
277
278impl FunctionAddressMapVariant<'_> {
279 pub fn instructions(&self) -> FunctionAddressMapInstructionVariant {
280 match self {
281 FunctionAddressMapVariant::Ref(map) => {
282 FunctionAddressMapInstructionVariant::Owned(&map.instructions)
283 }
284 FunctionAddressMapVariant::Archived(map) => {
285 FunctionAddressMapInstructionVariant::Archived(&map.instructions)
286 }
287 }
288 }
289
290 pub fn start_srcloc(&self) -> SourceLoc {
291 match self {
292 FunctionAddressMapVariant::Ref(map) => map.start_srcloc,
293 FunctionAddressMapVariant::Archived(map) => map.start_srcloc,
294 }
295 }
296
297 pub fn end_srcloc(&self) -> SourceLoc {
298 match self {
299 FunctionAddressMapVariant::Ref(map) => map.end_srcloc,
300 FunctionAddressMapVariant::Archived(map) => map.end_srcloc,
301 }
302 }
303
304 pub fn body_offset(&self) -> usize {
305 match self {
306 FunctionAddressMapVariant::Ref(map) => map.body_offset,
307 FunctionAddressMapVariant::Archived(map) => map.body_offset as usize,
308 }
309 }
310
311 pub fn body_len(&self) -> usize {
312 match self {
313 FunctionAddressMapVariant::Ref(map) => map.body_len,
314 FunctionAddressMapVariant::Archived(map) => map.body_len as usize,
315 }
316 }
317}
318
319#[derive(Debug)]
320pub enum FunctionAddressMapInstructionVariant<'a> {
321 Owned(&'a Vec<InstructionAddressMap>),
322 Archived(&'a ArchivedVec<ArchivedInstructionAddressMap>),
323}
324
325impl FunctionAddressMapInstructionVariant<'_> {
326 pub fn code_offset_by_key(&self, key: usize) -> Result<usize, usize> {
327 match self {
328 FunctionAddressMapInstructionVariant::Owned(instructions) => {
329 instructions.binary_search_by_key(&key, |map| map.code_offset)
330 }
331 FunctionAddressMapInstructionVariant::Archived(instructions) => {
332 instructions.binary_search_by_key(&key, |map| map.code_offset as usize)
333 }
334 }
335 }
336
337 pub fn get(&self, index: usize) -> InstructionAddressMap {
338 match self {
339 FunctionAddressMapInstructionVariant::Owned(instructions) => instructions[index],
340 FunctionAddressMapInstructionVariant::Archived(instructions) => instructions
341 .get(index)
342 .map(|map| InstructionAddressMap {
343 srcloc: map.srcloc,
344 code_offset: map.code_offset as usize,
345 code_len: map.code_len as usize,
346 })
347 .unwrap(),
348 }
349 }
350}
351
352pub fn register(
359 module: Arc<ModuleInfo>,
360 finished_functions: &BoxedSlice<LocalFunctionIndex, FunctionExtent>,
361 frame_infos: FrameInfosVariant,
362) -> Option<GlobalFrameInfoRegistration> {
363 let mut min = usize::max_value();
364 let mut max = 0;
365 let mut functions = BTreeMap::new();
366 for (
367 i,
368 FunctionExtent {
369 ptr: start,
370 length: len,
371 },
372 ) in finished_functions.iter()
373 {
374 let start = **start as usize;
375 let end = start + len - 1;
377 min = cmp::min(min, start);
378 max = cmp::max(max, end);
379 let func = FunctionInfo {
380 start,
381 local_index: i,
382 };
383 assert!(functions.insert(end, func).is_none());
384 }
385 if functions.is_empty() {
386 return None;
387 }
388
389 let mut info = FRAME_INFO.write().unwrap();
390 if let Some((_, prev)) = info.ranges.range(max..).next() {
393 assert!(prev.start > max);
394 }
395 if let Some((prev_end, _)) = info.ranges.range(..=min).next_back() {
396 assert!(*prev_end < min);
397 }
398
399 let prev = info.ranges.insert(
401 max,
402 ModuleInfoFrameInfo {
403 start: min,
404 functions,
405 module,
406 frame_infos,
407 },
408 );
409 assert!(prev.is_none());
410 Some(GlobalFrameInfoRegistration { key: max })
411}