1mod abi;
4mod data;
5mod func;
6mod host;
7
8pub use self::{
9 abi::{ToLSBytes, Type},
10 data::Data,
11 func::{Function, Functions},
12 host::HostFunc,
13};
14use crate::{Error, Result};
15use host::CompilerLabel;
16use smallvec::SmallVec;
17use std::collections::BTreeMap;
18use wasmparser::Operator;
19use zabi::Abi;
20
21macro_rules! impl_deref {
22 ($doc:literal, $name:ident, $target:ty) => {
23 #[derive(Clone, Debug, Default)]
24 #[doc = concat!(" ", $doc)]
25 pub struct $name($target);
26
27 impl core::ops::Deref for $name {
28 type Target = $target;
29
30 fn deref(&self) -> &Self::Target {
31 &self.0
32 }
33 }
34
35 impl core::ops::DerefMut for $name {
36 fn deref_mut(&mut self) -> &mut Self::Target {
37 &mut self.0
38 }
39 }
40 };
41 ($(($doc:literal, $name:ident, $target:ty)),*) => {
42 $( impl_deref!($doc, $name, $target); )*
43 };
44}
45
46impl_deref! {
47 ("WASM import section", Imports, BTreeMap<u32, HostFunc>),
48 ("WASM export section", Exports, BTreeMap<u32, String>),
49 ("WASM slot registry", Slots, BTreeMap<u32, u32>),
50 ("WASM function registry", Funcs, BTreeMap<u32, (u32, u32)>)
51}
52
53#[derive(Clone, Debug, Default)]
55pub struct Env {
56 pub imports: Imports,
58 pub exports: Exports,
60 pub slots: Slots,
62 pub funcs: Funcs,
64 pub data: Data,
66 pub index: Option<u32>,
68}
69
70impl Env {
71 pub fn load_abis(&self, funs: &Functions<'_>) -> Result<Vec<Abi>> {
73 let mut abis: Vec<_> = Default::default();
74 for (_, fun) in funs.iter() {
75 abis.push(self.load_abi(fun)?);
76 }
77
78 Ok(abis)
79 }
80
81 pub fn load_abi(&self, fun: &Function<'_>) -> Result<Abi> {
83 let mut reader = fun.body.get_operators_reader()?;
84
85 let Operator::I32Const { value: offset } = reader.read()? else {
86 return Err(Error::InvalidSelector);
87 };
88 let Operator::I32Const { value: length } = reader.read()? else {
89 return Err(Error::InvalidSelector);
90 };
91
92 let Operator::Call {
94 function_index: index,
95 } = reader.read()?
96 else {
97 return Err(Error::InvalidSelector);
98 };
99
100 if !self.imports.is_emit_abi(index) {
101 return Err(Error::FuncNotImported("emit_abi".into()));
102 }
103
104 let abi = self.data.load(offset, length as usize)?;
105 Abi::from_hex(String::from_utf8_lossy(&abi)).map_err(Into::into)
106 }
107
108 pub fn query_func(&self, name: &str) -> Result<u32> {
110 for (index, export) in self.exports.iter() {
111 if export == name {
112 return Ok(*index);
113 }
114 }
115
116 Err(Error::FuncNotImported(name.into()))
117 }
118
119 pub fn is_external(&self, index: u32) -> bool {
121 let Some(name) = self.exports.get(&index) else {
122 return false;
123 };
124
125 let selector = name.to_owned() + "_selector";
126 self.exports.iter().any(|(_, n)| **n == selector)
127 }
128
129 pub fn is_main(&self, index: u32) -> bool {
134 self.imports.len() as u32 == index
135 }
136
137 pub fn with_index(&self, index: u32) -> Self {
139 let mut this = self.clone();
140 this.index = Some(index);
141 this
142 }
143
144 pub fn reserved(&self) -> u32 {
146 let Some(index) = self.index else {
147 return 0;
148 };
149
150 *self.slots.get(&index).unwrap_or(&0)
151 }
152
153 pub fn alloc(&self, index: u32) -> SmallVec<[u8; 4]> {
155 let slots = index + self.reserved();
156 tracing::debug!(
157 "allocating memory for local {index} of function {:?}, slot: {slots}",
158 self.index
159 );
160 (slots * 0x20).to_ls_bytes()
161 }
162}
163
164impl Imports {
165 pub fn is_emit_abi(&self, index: u32) -> bool {
167 self.get(&index) == Some(&HostFunc::EmitABI)
168 }
169
170 pub fn reserved(&self) -> u32 {
172 let mut reserved = 0;
173 for host_fn in self.0.values() {
174 match *host_fn {
175 HostFunc::Label(CompilerLabel::ReserveMemory32) => reserved = 1,
176 HostFunc::Label(CompilerLabel::ReserveMemory64) => {
177 return 2;
178 }
179 _ => {}
180 }
181 }
182
183 reserved
184 }
185}
186
187impl Exports {
188 pub fn selectors(&self) -> Vec<u32> {
190 self.iter()
191 .filter_map(|(index, export)| {
192 if export.ends_with("_selector") {
193 Some(*index)
194 } else {
195 None
196 }
197 })
198 .collect::<Vec<_>>()
199 }
200}