1extern crate radix_wasmi_arena as wasmi_arena;
2
3use super::{
4 engine::DedupFuncType,
5 AsContext,
6 Extern,
7 Func,
8 Global,
9 Memory,
10 Module,
11 StoreContext,
12 Stored,
13 Table,
14};
15use crate::{
16 func::FuncError,
17 module::FuncIdx,
18 Error,
19 ExternType,
20 TypedFunc,
21 WasmParams,
22 WasmResults,
23};
24use alloc::{
25 boxed::Box,
26 collections::{btree_map, BTreeMap},
27 sync::Arc,
28 vec::Vec,
29};
30use core::iter::FusedIterator;
31use wasmi_arena::ArenaIndex;
32
33#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
35pub struct InstanceIdx(u32);
36
37impl ArenaIndex for InstanceIdx {
38 fn into_usize(self) -> usize {
39 self.0 as usize
40 }
41
42 fn from_usize(value: usize) -> Self {
43 let value = value.try_into().unwrap_or_else(|error| {
44 panic!("index {value} is out of bounds as instance index: {error}")
45 });
46 Self(value)
47 }
48}
49
50#[derive(Debug, Clone)]
52pub struct InstanceEntity {
53 initialized: bool,
54 func_types: Arc<[DedupFuncType]>,
55 tables: Box<[Table]>,
56 funcs: Box<[Func]>,
57 memories: Box<[Memory]>,
58 globals: Box<[Global]>,
59 exports: BTreeMap<Box<str>, Extern>,
60}
61
62impl InstanceEntity {
63 pub(crate) fn uninitialized() -> InstanceEntity {
65 Self {
66 initialized: false,
67 func_types: Arc::new([]),
68 tables: [].into(),
69 funcs: [].into(),
70 memories: [].into(),
71 globals: [].into(),
72 exports: BTreeMap::new(),
73 }
74 }
75
76 pub(crate) fn build(module: &Module) -> InstanceEntityBuilder {
78 InstanceEntityBuilder::new(module)
79 }
80
81 pub(crate) fn is_initialized(&self) -> bool {
83 self.initialized
84 }
85
86 pub(crate) fn get_memory(&self, index: u32) -> Option<Memory> {
88 self.memories.get(index as usize).copied()
89 }
90
91 pub(crate) fn get_table(&self, index: u32) -> Option<Table> {
93 self.tables.get(index as usize).copied()
94 }
95
96 pub(crate) fn get_global(&self, index: u32) -> Option<Global> {
98 self.globals.get(index as usize).copied()
99 }
100
101 pub(crate) fn get_func(&self, index: u32) -> Option<Func> {
103 self.funcs.get(index as usize).copied()
104 }
105
106 pub(crate) fn get_signature(&self, index: u32) -> Option<DedupFuncType> {
108 self.func_types.get(index as usize).copied()
109 }
110
111 pub(crate) fn get_export(&self, name: &str) -> Option<Extern> {
113 self.exports.get(name).copied()
114 }
115
116 pub fn exports(&self) -> ExportsIter {
120 ExportsIter::new(self.exports.iter())
121 }
122}
123
124#[derive(Debug, Clone)]
129pub struct Export<'instance> {
130 name: &'instance str,
132 definition: Extern,
134}
135
136impl<'instance> Export<'instance> {
137 pub(crate) fn new(name: &'instance str, definition: Extern) -> Export<'instance> {
139 Self { name, definition }
140 }
141
142 pub fn name(&self) -> &'instance str {
144 self.name
145 }
146
147 pub fn ty(&self, ctx: impl AsContext) -> ExternType {
153 self.definition.ty(ctx)
154 }
155
156 pub fn into_extern(self) -> Extern {
158 self.definition
159 }
160
161 pub fn into_func(self) -> Option<Func> {
163 self.definition.into_func()
164 }
165
166 pub fn into_table(self) -> Option<Table> {
168 self.definition.into_table()
169 }
170
171 pub fn into_memory(self) -> Option<Memory> {
173 self.definition.into_memory()
174 }
175
176 pub fn into_global(self) -> Option<Global> {
178 self.definition.into_global()
179 }
180}
181
182#[derive(Debug)]
184pub struct ExportsIter<'instance> {
185 iter: btree_map::Iter<'instance, Box<str>, Extern>,
186}
187
188impl<'instance> ExportsIter<'instance> {
189 fn new(iter: btree_map::Iter<'instance, Box<str>, Extern>) -> Self {
191 Self { iter }
192 }
193
194 #[allow(clippy::borrowed_box)]
196 fn convert_item((name, export): (&'instance Box<str>, &'instance Extern)) -> Export {
197 Export::new(name, *export)
198 }
199}
200
201impl<'instance> Iterator for ExportsIter<'instance> {
202 type Item = Export<'instance>;
203
204 fn size_hint(&self) -> (usize, Option<usize>) {
205 self.iter.size_hint()
206 }
207
208 fn next(&mut self) -> Option<Self::Item> {
209 self.iter.next().map(Self::convert_item)
210 }
211}
212
213impl DoubleEndedIterator for ExportsIter<'_> {
214 fn next_back(&mut self) -> Option<Self::Item> {
215 self.iter.next_back().map(Self::convert_item)
216 }
217}
218
219impl ExactSizeIterator for ExportsIter<'_> {
220 fn len(&self) -> usize {
221 self.iter.len()
222 }
223}
224
225impl FusedIterator for ExportsIter<'_> {}
226
227#[derive(Debug)]
229pub struct InstanceEntityBuilder {
230 func_types: Arc<[DedupFuncType]>,
231 tables: Vec<Table>,
232 funcs: Vec<Func>,
233 memories: Vec<Memory>,
234 globals: Vec<Global>,
235 start_fn: Option<FuncIdx>,
236 exports: BTreeMap<Box<str>, Extern>,
237}
238
239impl InstanceEntityBuilder {
240 pub fn new(module: &Module) -> Self {
242 fn vec_with_capacity_exact<T>(capacity: usize) -> Vec<T> {
243 let mut v = Vec::new();
244 v.reserve_exact(capacity);
245 v
246 }
247 let mut len_funcs = module.len_funcs();
248 let mut len_globals = module.len_globals();
249 let mut len_tables = module.len_tables();
250 let mut len_memories = module.len_memories();
251 for import in module.imports() {
252 match import.ty() {
253 ExternType::Func(_) => {
254 len_funcs += 1;
255 }
256 ExternType::Table(_) => {
257 len_tables += 1;
258 }
259 ExternType::Memory(_) => {
260 len_memories += 1;
261 }
262 ExternType::Global(_) => {
263 len_globals += 1;
264 }
265 }
266 }
267 Self {
268 func_types: Arc::new([]),
269 tables: vec_with_capacity_exact(len_tables),
270 funcs: vec_with_capacity_exact(len_funcs),
271 memories: vec_with_capacity_exact(len_memories),
272 globals: vec_with_capacity_exact(len_globals),
273 start_fn: None,
274 exports: BTreeMap::default(),
275 }
276 }
277
278 pub fn set_start(&mut self, start_fn: FuncIdx) {
284 match &mut self.start_fn {
285 Some(_) => panic!("already set start function"),
286 None => {
287 self.start_fn = Some(start_fn);
288 }
289 }
290 }
291
292 pub fn get_start(&self) -> Option<FuncIdx> {
294 self.start_fn
295 }
296
297 pub fn get_memory(&self, index: u32) -> Memory {
303 self.memories
304 .get(index as usize)
305 .copied()
306 .unwrap_or_else(|| panic!("missing `Memory` at index: {index}"))
307 }
308
309 pub fn get_table(&self, index: u32) -> Table {
315 self.tables
316 .get(index as usize)
317 .copied()
318 .unwrap_or_else(|| panic!("missing `Table` at index: {index}"))
319 }
320
321 pub fn get_global(&self, index: u32) -> Global {
327 self.globals
328 .get(index as usize)
329 .copied()
330 .unwrap_or_else(|| panic!("missing `Global` at index: {index}"))
331 }
332
333 pub fn get_func(&self, index: u32) -> Func {
339 self.funcs
340 .get(index as usize)
341 .copied()
342 .unwrap_or_else(|| panic!("missing `Func` at index: {index}"))
343 }
344
345 pub fn push_memory(&mut self, memory: Memory) {
347 self.memories.push(memory);
348 }
349
350 pub fn push_table(&mut self, table: Table) {
352 self.tables.push(table);
353 }
354
355 pub fn push_global(&mut self, global: Global) {
357 self.globals.push(global);
358 }
359
360 pub fn push_func(&mut self, func: Func) {
362 self.funcs.push(func);
363 }
364
365 pub fn set_func_types(&mut self, func_types: &Arc<[DedupFuncType]>) {
370 self.func_types = func_types.clone();
371 }
372
373 pub fn push_export(&mut self, name: &str, new_value: Extern) {
379 if let Some(old_value) = self.exports.get(name) {
380 panic!(
381 "tried to register {new_value:?} for name {name} \
382 but name is already used by {old_value:?}",
383 )
384 }
385 self.exports.insert(name.into(), new_value);
386 }
387
388 pub fn finish(self) -> InstanceEntity {
390 InstanceEntity {
391 initialized: true,
392 func_types: self.func_types,
393 tables: self.tables.into(),
394 funcs: self.funcs.into(),
395 memories: self.memories.into(),
396 globals: self.globals.into(),
397 exports: self.exports,
398 }
399 }
400}
401
402#[derive(Debug, Copy, Clone, PartialEq, Eq)]
414#[repr(transparent)]
415pub struct Instance(Stored<InstanceIdx>);
416
417impl Instance {
418 pub(super) fn from_inner(stored: Stored<InstanceIdx>) -> Self {
426 Self(stored)
427 }
428
429 pub(super) fn into_inner(self) -> Stored<InstanceIdx> {
431 self.0
432 }
433
434 pub(crate) fn get_func_by_index(&self, store: impl AsContext, index: u32) -> Option<Func> {
440 store
441 .as_context()
442 .store
443 .resolve_instance(*self)
444 .get_func(index)
445 }
446
447 pub fn get_export(&self, store: impl AsContext, name: &str) -> Option<Extern> {
453 store
454 .as_context()
455 .store
456 .resolve_instance(*self)
457 .get_export(name)
458 }
459
460 pub fn get_func(&self, store: impl AsContext, name: &str) -> Option<Func> {
469 self.get_export(store, name)?.into_func()
470 }
471
472 pub fn get_typed_func<Params, Results>(
487 &self,
488 store: impl AsContext,
489 name: &str,
490 ) -> Result<TypedFunc<Params, Results>, Error>
491 where
492 Params: WasmParams,
493 Results: WasmResults,
494 {
495 self.get_export(&store, name)
496 .and_then(Extern::into_func)
497 .ok_or_else(|| Error::Func(FuncError::ExportedFuncNotFound))?
498 .typed::<Params, Results>(store)
499 }
500
501 pub fn get_global(&self, store: impl AsContext, name: &str) -> Option<Global> {
510 self.get_export(store, name)?.into_global()
511 }
512
513 pub fn get_table(&self, store: impl AsContext, name: &str) -> Option<Table> {
522 self.get_export(store, name)?.into_table()
523 }
524
525 pub fn get_memory(&self, store: impl AsContext, name: &str) -> Option<Memory> {
534 self.get_export(store, name)?.into_memory()
535 }
536
537 pub fn exports<'ctx, T: 'ctx>(
545 &self,
546 store: impl Into<StoreContext<'ctx, T>>,
547 ) -> ExportsIter<'ctx> {
548 store.into().store.resolve_instance(*self).exports()
549 }
550}