use crate::virtual_machine::Value; use prometeu_bytecode::v0::{FunctionMeta, DebugInfo}; use prometeu_bytecode::abi::TrapInfo; use std::sync::Arc; #[derive(Debug, Clone, Default)] pub struct ProgramImage { pub rom: Arc<[u8]>, pub constant_pool: Arc<[Value]>, pub functions: Arc<[FunctionMeta]>, pub debug_info: Option, } impl ProgramImage { pub fn new(rom: Vec, constant_pool: Vec, mut functions: Vec, debug_info: Option) -> Self { if functions.is_empty() && !rom.is_empty() { functions.push(FunctionMeta { code_offset: 0, code_len: rom.len() as u32, ..Default::default() }); } Self { rom: Arc::from(rom), constant_pool: Arc::from(constant_pool), functions: Arc::from(functions), debug_info, } } pub fn create_trap(&self, code: u32, opcode: u16, mut message: String, pc: u32) -> TrapInfo { let span = self.debug_info.as_ref().and_then(|di| { di.pc_to_span.iter().find(|(p, _)| *p == pc).map(|(_, s)| s.clone()) }); if let Some(func_idx) = self.find_function_index(pc) { if let Some(func_name) = self.get_function_name(func_idx) { message = format!("{} (in function {})", message, func_name); } } TrapInfo { code, opcode, message, pc, span, } } pub fn find_function_index(&self, pc: u32) -> Option { self.functions.iter().position(|f| { pc >= f.code_offset && pc < (f.code_offset + f.code_len) }) } pub fn get_function_name(&self, func_idx: usize) -> Option<&str> { self.debug_info.as_ref() .and_then(|di| di.function_names.iter().find(|(idx, _)| *idx as usize == func_idx)) .map(|(_, name)| name.as_str()) } }