use crate::{
wasm::{ToLSBytes, Type},
Error, Result,
};
use smallvec::SmallVec;
use wasmparser::ValType;
#[derive(Debug, PartialEq, Eq)]
pub enum LocalSlotType {
Parameter,
Variable,
}
#[derive(Debug)]
pub struct LocalSlot {
inner: ValType,
ty: LocalSlotType,
pub sp: usize,
}
impl LocalSlot {
pub fn new(inner: ValType, ty: LocalSlotType, sp: usize) -> Self {
Self { inner, ty, sp }
}
pub fn ty(&self) -> &LocalSlotType {
&self.ty
}
pub fn val_ty(&self) -> &ValType {
&self.inner
}
}
impl Type for LocalSlot {
fn size(&self) -> usize {
self.inner.size()
}
}
#[derive(Default, Debug)]
pub struct Locals {
inner: SmallVec<[LocalSlot; 16]>,
}
impl Locals {
pub fn get(&self, index: usize) -> Result<&LocalSlot> {
self.inner
.get(index)
.ok_or_else(|| Error::InvalidLocalIndex(index))
}
pub fn get_mut(&mut self, index: usize) -> Result<&mut LocalSlot> {
self.inner
.get_mut(index)
.ok_or_else(|| Error::InvalidLocalIndex(index))
}
pub fn offset_of(&self, index: usize) -> Result<SmallVec<[u8; 32]>> {
let local = self.get(index)?;
let offset = if local.ty() == &LocalSlotType::Parameter {
self.inner[..index].iter().fold(0, |acc, x| acc + x.align())
} else {
self.inner[..index]
.iter()
.filter(|x| x.ty() == &LocalSlotType::Variable)
.fold(0, |acc, x| acc + x.align())
}
.to_ls_bytes()
.to_vec()
.into();
Ok(offset)
}
pub fn push(&mut self, slot: impl Into<LocalSlot>) {
self.inner.push(slot.into())
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
}