use super::Instruction;
use alloc::vec::Vec;
use wasmi_arena::ArenaIndex;
#[derive(Debug, Copy, Clone)]
pub struct FuncBody(usize);
impl ArenaIndex for FuncBody {
fn into_usize(self) -> usize {
self.0
}
fn from_usize(value: usize) -> Self {
FuncBody(value)
}
}
#[derive(Debug, Copy, Clone)]
pub struct InstructionsRef {
start: usize,
}
#[derive(Debug, Copy, Clone)]
pub struct FuncHeader {
iref: InstructionsRef,
len_locals: usize,
max_stack_height: usize,
}
impl FuncHeader {
pub fn iref(&self) -> InstructionsRef {
self.iref
}
pub fn len_locals(&self) -> usize {
self.len_locals
}
pub fn max_stack_height(&self) -> usize {
self.max_stack_height
}
}
#[derive(Debug, Default)]
pub struct CodeMap {
headers: Vec<FuncHeader>,
insts: Vec<Instruction>,
}
impl CodeMap {
pub fn alloc<I>(&mut self, len_locals: usize, max_stack_height: usize, insts: I) -> FuncBody
where
I: IntoIterator<Item = Instruction>,
{
let start = self.insts.len();
self.insts.extend(insts);
let iref = InstructionsRef { start };
let header = FuncHeader {
iref,
len_locals,
max_stack_height: len_locals + max_stack_height,
};
let header_index = self.headers.len();
self.headers.push(header);
FuncBody(header_index)
}
#[inline]
pub fn instr_ptr(&self, iref: InstructionsRef) -> InstructionPtr {
InstructionPtr::new(self.insts[iref.start..].as_ptr())
}
pub fn header(&self, func_body: FuncBody) -> &FuncHeader {
&self.headers[func_body.0]
}
#[cfg(test)]
pub fn get_instr(&self, func_body: FuncBody, index: usize) -> Option<&Instruction> {
let header = self.header(func_body);
let start = header.iref.start;
let end = self.instr_end(func_body);
let instrs = &self.insts[start..end];
instrs.get(index)
}
#[cfg(test)]
pub fn instr_end(&self, func_body: FuncBody) -> usize {
self.headers
.get(func_body.0 + 1)
.map(|header| header.iref.start)
.unwrap_or(self.insts.len())
}
}
#[derive(Debug, Copy, Clone)]
pub struct InstructionPtr {
ptr: *const Instruction,
}
unsafe impl Send for InstructionPtr {}
impl InstructionPtr {
#[inline]
pub fn new(ptr: *const Instruction) -> Self {
Self { ptr }
}
#[inline(always)]
pub unsafe fn offset(&mut self, by: isize) {
self.ptr = self.ptr.offset(by);
}
#[inline(always)]
pub unsafe fn get(&self) -> &Instruction {
&*self.ptr
}
}