radix_wasmi/module/
mod.rs

1mod builder;
2mod compile;
3mod data;
4mod element;
5mod error;
6mod export;
7mod global;
8mod import;
9mod init_expr;
10mod instantiate;
11mod parser;
12mod read;
13mod utils;
14
15pub(crate) use self::init_expr::InitExpr;
16use self::{
17    builder::ModuleBuilder,
18    data::DataSegment,
19    element::ElementSegment,
20    export::ExternIdx,
21    global::Global,
22    import::{ExternTypeIdx, Import},
23    parser::parse,
24    read::ReadError,
25};
26pub use self::{
27    builder::ModuleResources,
28    compile::BlockType,
29    error::ModuleError,
30    export::{ExportType, FuncIdx, MemoryIdx, ModuleExportsIter, TableIdx},
31    global::GlobalIdx,
32    import::{FuncTypeIdx, ImportName},
33    instantiate::{InstancePre, InstantiationError},
34    parser::ReusableAllocations,
35    read::Read,
36};
37use crate::{
38    engine::{DedupFuncType, FuncBody},
39    Engine,
40    Error,
41    ExternType,
42    FuncType,
43    GlobalType,
44    MemoryType,
45    TableType,
46};
47use alloc::{boxed::Box, collections::BTreeMap, sync::Arc, vec::Vec};
48use core::{iter, slice::Iter as SliceIter};
49
50/// A parsed and validated WebAssembly module.
51#[derive(Debug)]
52pub struct Module {
53    engine: Engine,
54    func_types: Arc<[DedupFuncType]>,
55    imports: ModuleImports,
56    funcs: Box<[DedupFuncType]>,
57    tables: Box<[TableType]>,
58    memories: Box<[MemoryType]>,
59    globals: Box<[GlobalType]>,
60    globals_init: Box<[InitExpr]>,
61    exports: BTreeMap<Box<str>, ExternIdx>,
62    start: Option<FuncIdx>,
63    func_bodies: Box<[FuncBody]>,
64    element_segments: Box<[ElementSegment]>,
65    data_segments: Box<[DataSegment]>,
66}
67
68/// The index of the default Wasm linear memory.
69pub(crate) const DEFAULT_MEMORY_INDEX: u32 = 0;
70
71/// The index of the default Wasm table.
72pub(crate) const DEFAULT_TABLE_INDEX: u32 = 0;
73
74/// An imported item declaration in the [`Module`].
75#[derive(Debug)]
76pub enum Imported {
77    /// The name of an imported [`Func`].
78    ///
79    /// [`Func`]: [`crate::Func`]
80    Func(ImportName),
81    /// The name of an imported [`Table`].
82    ///
83    /// [`Table`]: [`crate::Table`]
84    Table(ImportName),
85    /// The name of an imported [`Memory`].
86    ///
87    /// [`Memory`]: [`crate::Memory`]
88    Memory(ImportName),
89    /// The name of an imported [`Global`].
90    Global(ImportName),
91}
92
93/// The import names of the [`Module`] imports.
94#[derive(Debug)]
95pub struct ModuleImports {
96    /// All names and types of all imported items.
97    items: Box<[Imported]>,
98    /// The amount of imported [`Func`].
99    ///
100    /// [`Func`]: [`crate::Func`]
101    len_funcs: usize,
102    /// The amount of imported [`Global`].
103    len_globals: usize,
104    /// The amount of imported [`Memory`].
105    ///
106    /// [`Memory`]: [`crate::Memory`]
107    len_memories: usize,
108    /// The amount of imported [`Table`].
109    ///
110    /// [`Table`]: [`crate::Table`]
111    len_tables: usize,
112}
113
114impl ModuleImports {
115    /// Creates a new [`ModuleImports`] from the [`ModuleBuilder`] definitions.
116    fn from_builder(imports: builder::ModuleImports) -> Self {
117        let len_funcs = imports.funcs.len();
118        let len_globals = imports.globals.len();
119        let len_memories = imports.memories.len();
120        let len_tables = imports.tables.len();
121        let funcs = imports.funcs.into_iter().map(Imported::Func);
122        let tables = imports.tables.into_iter().map(Imported::Table);
123        let memories = imports.memories.into_iter().map(Imported::Memory);
124        let globals = imports.globals.into_iter().map(Imported::Global);
125        let items = funcs
126            .chain(tables)
127            .chain(memories)
128            .chain(globals)
129            .collect::<Vec<_>>()
130            .into();
131        Self {
132            items,
133            len_funcs,
134            len_globals,
135            len_memories,
136            len_tables,
137        }
138    }
139}
140
141impl Module {
142    /// Creates a new Wasm [`Module`] from the given byte stream.
143    ///
144    /// # Errors
145    ///
146    /// - If the `stream` cannot be decoded into a valid Wasm module.
147    /// - If unsupported Wasm proposals are encountered.
148    pub fn new(engine: &Engine, stream: impl Read) -> Result<Self, Error> {
149        parse(engine, stream).map_err(Into::into)
150    }
151
152    /// Returns the [`Engine`] used during creation of the [`Module`].
153    pub fn engine(&self) -> &Engine {
154        &self.engine
155    }
156
157    /// Creates a new [`Module`] from the [`ModuleBuilder`].
158    fn from_builder(builder: ModuleBuilder) -> Self {
159        Self {
160            engine: builder.engine.clone(),
161            func_types: builder.func_types.into(),
162            imports: ModuleImports::from_builder(builder.imports),
163            funcs: builder.funcs.into(),
164            tables: builder.tables.into(),
165            memories: builder.memories.into(),
166            globals: builder.globals.into(),
167            globals_init: builder.globals_init.into(),
168            exports: builder.exports,
169            start: builder.start,
170            func_bodies: builder.func_bodies.into(),
171            element_segments: builder.element_segments.into(),
172            data_segments: builder.data_segments.into(),
173        }
174    }
175
176    /// Returns the number of non-imported functions of the [`Module`].
177    pub(crate) fn len_funcs(&self) -> usize {
178        self.funcs.len()
179    }
180    /// Returns the number of non-imported tables of the [`Module`].
181    pub(crate) fn len_tables(&self) -> usize {
182        self.tables.len()
183    }
184    /// Returns the number of non-imported linear memories of the [`Module`].
185    pub(crate) fn len_memories(&self) -> usize {
186        self.memories.len()
187    }
188    /// Returns the number of non-imported global variables of the [`Module`].
189    pub(crate) fn len_globals(&self) -> usize {
190        self.memories.len()
191    }
192
193    /// Returns an iterator over the imports of the [`Module`].
194    pub fn imports(&self) -> ModuleImportsIter {
195        let len_imported_funcs = self.imports.len_funcs;
196        let len_imported_globals = self.imports.len_globals;
197        ModuleImportsIter {
198            engine: &self.engine,
199            names: self.imports.items.iter(),
200            funcs: self.funcs[..len_imported_funcs].iter(),
201            tables: self.tables.iter(),
202            memories: self.memories.iter(),
203            globals: self.globals[..len_imported_globals].iter(),
204        }
205    }
206
207    /// Returns an iterator over the internally defined [`Func`].
208    ///
209    /// [`Func`]: [`crate::Func`]
210    pub(crate) fn internal_funcs(&self) -> InternalFuncsIter {
211        let len_imported = self.imports.len_funcs;
212        // We skip the first `len_imported` elements in `funcs`
213        // since they refer to imported and not internally defined
214        // functions.
215        let funcs = &self.funcs[len_imported..];
216        let func_bodies = &self.func_bodies[..];
217        assert_eq!(funcs.len(), func_bodies.len());
218        InternalFuncsIter {
219            iter: funcs.iter().zip(func_bodies),
220        }
221    }
222
223    /// Returns an iterator over the [`MemoryType`] of internal linear memories.
224    fn internal_memories(&self) -> SliceIter<MemoryType> {
225        let len_imported = self.imports.len_memories;
226        // We skip the first `len_imported` elements in `memories`
227        // since they refer to imported and not internally defined
228        // linear memories.
229        let memories = &self.memories[len_imported..];
230        memories.iter()
231    }
232
233    /// Returns an iterator over the [`TableType`] of internal tables.
234    fn internal_tables(&self) -> SliceIter<TableType> {
235        let len_imported = self.imports.len_tables;
236        // We skip the first `len_imported` elements in `memories`
237        // since they refer to imported and not internally defined
238        // linear memories.
239        let tables = &self.tables[len_imported..];
240        tables.iter()
241    }
242
243    /// Returns an iterator over the internally defined [`Global`].
244    fn internal_globals(&self) -> InternalGlobalsIter {
245        let len_imported = self.imports.len_globals;
246        // We skip the first `len_imported` elements in `globals`
247        // since they refer to imported and not internally defined
248        // global variables.
249        let globals = self.globals[len_imported..].iter();
250        let global_inits = self.globals_init.iter();
251        InternalGlobalsIter {
252            iter: globals.zip(global_inits),
253        }
254    }
255
256    /// Returns an iterator over the exports of the [`Module`].
257    pub fn exports(&self) -> ModuleExportsIter {
258        ModuleExportsIter::new(self)
259    }
260
261    /// Looks up an export in this [`Module`] by its `name`.
262    ///
263    /// Returns `None` if no export with the name was found.
264    ///
265    /// # Note
266    ///
267    /// This function will return the type of an export with the given `name`.
268    pub fn get_export(&self, name: &str) -> Option<ExternType> {
269        let idx = self.exports.get(name).copied()?;
270        let ty = self.get_extern_type(idx);
271        Some(ty)
272    }
273
274    /// Returns the [`ExternType`] for a given [`ExternIdx`].
275    ///
276    /// # Note
277    ///
278    /// This function assumes that the given [`ExternType`] is valid.
279    fn get_extern_type(&self, idx: ExternIdx) -> ExternType {
280        match idx {
281            ExternIdx::Func(index) => {
282                let dedup = self.funcs[index.into_usize()];
283                let func_type = self.engine.resolve_func_type(dedup, Clone::clone);
284                ExternType::Func(func_type)
285            }
286            ExternIdx::Table(index) => {
287                let table_type = self.tables[index.into_u32() as usize];
288                ExternType::Table(table_type)
289            }
290            ExternIdx::Memory(index) => {
291                let memory_type = self.memories[index.into_u32() as usize];
292                ExternType::Memory(memory_type)
293            }
294            ExternIdx::Global(index) => {
295                let global_type = self.globals[index.into_usize()];
296                ExternType::Global(global_type)
297            }
298        }
299    }
300}
301
302/// An iterator over the imports of a [`Module`].
303#[derive(Debug)]
304pub struct ModuleImportsIter<'a> {
305    engine: &'a Engine,
306    names: SliceIter<'a, Imported>,
307    funcs: SliceIter<'a, DedupFuncType>,
308    tables: SliceIter<'a, TableType>,
309    memories: SliceIter<'a, MemoryType>,
310    globals: SliceIter<'a, GlobalType>,
311}
312
313impl<'a> Iterator for ModuleImportsIter<'a> {
314    type Item = ImportType<'a>;
315
316    fn next(&mut self) -> Option<Self::Item> {
317        let import = match self.names.next() {
318            None => return None,
319            Some(imported) => match imported {
320                Imported::Func(name) => {
321                    let func_type = self.funcs.next().unwrap_or_else(|| {
322                        panic!("unexpected missing imported function for {name:?}")
323                    });
324                    let func_type = self.engine.resolve_func_type(*func_type, FuncType::clone);
325                    ImportType::new(name, func_type)
326                }
327                Imported::Table(name) => {
328                    let table_type = self.tables.next().unwrap_or_else(|| {
329                        panic!("unexpected missing imported table for {name:?}")
330                    });
331                    ImportType::new(name, *table_type)
332                }
333                Imported::Memory(name) => {
334                    let memory_type = self.memories.next().unwrap_or_else(|| {
335                        panic!("unexpected missing imported linear memory for {name:?}")
336                    });
337                    ImportType::new(name, *memory_type)
338                }
339                Imported::Global(name) => {
340                    let global_type = self.globals.next().unwrap_or_else(|| {
341                        panic!("unexpected missing imported global variable for {name:?}")
342                    });
343                    ImportType::new(name, *global_type)
344                }
345            },
346        };
347        Some(import)
348    }
349
350    fn size_hint(&self) -> (usize, Option<usize>) {
351        self.names.size_hint()
352    }
353}
354
355impl<'a> ExactSizeIterator for ModuleImportsIter<'a> {
356    fn len(&self) -> usize {
357        ExactSizeIterator::len(&self.names)
358    }
359}
360
361/// A descriptor for an imported value into a Wasm [`Module`].
362///
363/// This type is primarily accessed from the [`Module::imports`] method.
364/// Each [`ImportType`] describes an import into the Wasm module with the `module/name`
365/// that it is imported from as well as the type of item that is being imported.
366#[derive(Debug)]
367pub struct ImportType<'module> {
368    /// The name of the imported item.
369    name: &'module ImportName,
370    /// The external item type.
371    ty: ExternType,
372}
373
374impl<'module> ImportType<'module> {
375    /// Creates a new [`ImportType`].
376    pub(crate) fn new<T>(name: &'module ImportName, ty: T) -> Self
377    where
378        T: Into<ExternType>,
379    {
380        Self {
381            name,
382            ty: ty.into(),
383        }
384    }
385
386    /// Returns the import name.
387    pub(crate) fn import_name(&self) -> &ImportName {
388        self.name
389    }
390
391    /// Returns the module import name.
392    pub fn module(&self) -> &'module str {
393        self.name.module()
394    }
395
396    /// Returns the field import name.
397    pub fn name(&self) -> &'module str {
398        self.name.name()
399    }
400
401    /// Returns the import item type.
402    pub fn ty(&self) -> &ExternType {
403        &self.ty
404    }
405}
406
407/// An iterator over the internally defined functions of a [`Module`].
408#[derive(Debug)]
409pub struct InternalFuncsIter<'a> {
410    iter: iter::Zip<SliceIter<'a, DedupFuncType>, SliceIter<'a, FuncBody>>,
411}
412
413impl<'a> Iterator for InternalFuncsIter<'a> {
414    type Item = (DedupFuncType, FuncBody);
415
416    fn next(&mut self) -> Option<Self::Item> {
417        self.iter
418            .next()
419            .map(|(func_type, func_body)| (*func_type, *func_body))
420    }
421
422    fn size_hint(&self) -> (usize, Option<usize>) {
423        self.iter.size_hint()
424    }
425}
426
427impl<'a> ExactSizeIterator for InternalFuncsIter<'a> {
428    fn len(&self) -> usize {
429        ExactSizeIterator::len(&self.iter)
430    }
431}
432
433/// An iterator over the internally defined functions of a [`Module`].
434#[derive(Debug)]
435pub struct InternalGlobalsIter<'a> {
436    iter: iter::Zip<SliceIter<'a, GlobalType>, SliceIter<'a, InitExpr>>,
437}
438
439impl<'a> Iterator for InternalGlobalsIter<'a> {
440    type Item = (&'a GlobalType, &'a InitExpr);
441
442    fn next(&mut self) -> Option<Self::Item> {
443        self.iter.next()
444    }
445
446    fn size_hint(&self) -> (usize, Option<usize>) {
447        self.iter.size_hint()
448    }
449}
450
451impl<'a> ExactSizeIterator for InternalGlobalsIter<'a> {
452    fn len(&self) -> usize {
453        ExactSizeIterator::len(&self.iter)
454    }
455}