//! Shared bytecode layout utilities, used by both compiler (emitter/linker) //! and the VM (verifier/loader). This ensures a single source of truth for //! how function ranges and jump targets are interpreted post-link. use crate::FunctionMeta; /// Returns the absolute end (exclusive) of the function at `func_idx`, /// defined as the minimum `code_offset` of any subsequent function, or /// `code_len_total` if this is the last function. #[inline] pub fn function_end_from_next(functions: &[FunctionMeta], func_idx: usize, code_len_total: usize) -> usize { let start = functions.get(func_idx).map(|f| f.code_offset as usize).unwrap_or(0); let mut end = code_len_total; for (j, other) in functions.iter().enumerate() { if j == func_idx { continue; } let other_start = other.code_offset as usize; if other_start > start && other_start < end { end = other_start; } } end } /// Returns the length (in bytes) of the function at `func_idx`, using /// the canonical definition: end = start of next function (exclusive), /// or total code len if last. #[inline] pub fn function_len_from_next(functions: &[FunctionMeta], func_idx: usize, code_len_total: usize) -> usize { let start = functions.get(func_idx).map(|f| f.code_offset as usize).unwrap_or(0); let end = function_end_from_next(functions, func_idx, code_len_total); end.saturating_sub(start) } /// Recomputes all `code_len` values in place from the next function start /// (exclusive end), using the combined code buffer length for the last one. pub fn recompute_function_lengths_in_place(functions: &mut [FunctionMeta], code_len_total: usize) { for i in 0..functions.len() { let start = functions[i].code_offset as usize; let end = function_end_from_next(functions, i, code_len_total); functions[i].code_len = end.saturating_sub(start) as u32; } } /// Finds the function index that contains `pc_abs` (absolute), using the /// canonical ranges (end = next start, exclusive). Returns `None` if none. pub fn function_index_by_pc(functions: &[FunctionMeta], code_len_total: usize, pc_abs: usize) -> Option { for i in 0..functions.len() { let start = functions[i].code_offset as usize; let end = function_end_from_next(functions, i, code_len_total); if pc_abs >= start && pc_abs < end { return Some(i); } } None }