1use crate::{
4 wasm::{ToLSBytes, Type},
5 Error, Result,
6};
7use smallvec::SmallVec;
8use wasmparser::ValType;
9
10#[derive(Debug, PartialEq, Eq)]
12pub enum LocalSlotType {
13 Parameter,
15 Variable,
17}
18
19#[derive(Debug)]
24pub struct LocalSlot {
25 inner: ValType,
27 ty: LocalSlotType,
29
30 pub sp: usize,
32}
33
34impl LocalSlot {
35 pub fn new(inner: ValType, ty: LocalSlotType, sp: usize) -> Self {
37 Self { inner, ty, sp }
38 }
39
40 pub fn ty(&self) -> &LocalSlotType {
42 &self.ty
43 }
44
45 pub fn val_ty(&self) -> &ValType {
47 &self.inner
48 }
49}
50
51impl Type for LocalSlot {
52 fn size(&self) -> usize {
53 self.inner.size()
54 }
55}
56
57#[derive(Default, Debug)]
60pub struct Locals {
61 inner: SmallVec<[LocalSlot; 16]>,
62}
63
64impl Locals {
65 pub fn get(&self, index: usize) -> Result<&LocalSlot> {
67 self.inner
68 .get(index)
69 .ok_or_else(|| Error::InvalidLocalIndex(index))
70 }
71
72 pub fn get_mut(&mut self, index: usize) -> Result<&mut LocalSlot> {
74 self.inner
75 .get_mut(index)
76 .ok_or_else(|| Error::InvalidLocalIndex(index))
77 }
78
79 pub fn offset_of(&self, index: usize) -> Result<SmallVec<[u8; 32]>> {
86 let local = self.get(index)?;
87 let offset = if local.ty() == &LocalSlotType::Parameter {
88 self.inner[..index].iter().fold(0, |acc, x| acc + x.align())
89 } else {
90 self.inner[..index]
91 .iter()
92 .filter(|x| x.ty() == &LocalSlotType::Variable)
93 .fold(0, |acc, x| acc + x.align())
94 }
95 .to_ls_bytes()
96 .to_vec()
97 .into();
98
99 Ok(offset)
100 }
101
102 pub fn push(&mut self, slot: impl Into<LocalSlot>) {
104 self.inner.push(slot.into())
105 }
106
107 pub fn len(&self) -> usize {
109 self.inner.len()
110 }
111
112 pub fn is_empty(&self) -> bool {
114 self.inner.is_empty()
115 }
116}