wasmi/module/
mod.rs

1mod builder;
2mod data;
3mod element;
4mod export;
5mod global;
6mod import;
7mod init_expr;
8mod instantiate;
9mod parser;
10mod read;
11pub(crate) mod utils;
12
13use self::{
14    builder::ModuleBuilder,
15    export::ExternIdx,
16    global::Global,
17    import::{ExternTypeIdx, Import},
18    parser::ModuleParser,
19};
20pub(crate) use self::{
21    data::{DataSegment, DataSegments, InitDataSegment, PassiveDataSegmentBytes},
22    element::{ElementSegment, ElementSegmentItems, ElementSegmentKind},
23    init_expr::ConstExpr,
24    utils::WasmiValueType,
25};
26pub use self::{
27    export::{ExportType, FuncIdx, MemoryIdx, ModuleExportsIter, TableIdx},
28    global::GlobalIdx,
29    import::{FuncTypeIdx, ImportName},
30    instantiate::{InstancePre, InstantiationError},
31    read::{Read, ReadError},
32};
33use crate::{
34    collections::Map,
35    engine::{CompiledFunc, DedupFuncType, EngineWeak},
36    Engine,
37    Error,
38    ExternType,
39    FuncType,
40    GlobalType,
41    MemoryType,
42    TableType,
43};
44use core::{iter, slice::Iter as SliceIter};
45use std::{boxed::Box, collections::BTreeMap, sync::Arc};
46use wasmparser::{FuncValidatorAllocations, Parser, ValidPayload, Validator};
47
48/// A parsed and validated WebAssembly module.
49#[derive(Debug)]
50pub struct Module {
51    engine: Engine,
52    header: ModuleHeader,
53    data_segments: DataSegments,
54}
55
56/// A parsed and validated WebAssembly module header.
57#[derive(Debug, Clone)]
58pub struct ModuleHeader {
59    inner: Arc<ModuleHeaderInner>,
60}
61
62#[derive(Debug)]
63struct ModuleHeaderInner {
64    engine: EngineWeak,
65    func_types: Arc<[DedupFuncType]>,
66    imports: ModuleImports,
67    funcs: Box<[DedupFuncType]>,
68    tables: Box<[TableType]>,
69    memories: Box<[MemoryType]>,
70    globals: Box<[GlobalType]>,
71    globals_init: Box<[ConstExpr]>,
72    exports: Map<Box<str>, ExternIdx>,
73    start: Option<FuncIdx>,
74    compiled_funcs: Box<[CompiledFunc]>,
75    compiled_funcs_idx: BTreeMap<CompiledFunc, FuncIdx>,
76    element_segments: Box<[ElementSegment]>,
77}
78
79impl ModuleHeader {
80    /// Returns the [`Engine`] of the [`ModuleHeader`].
81    pub fn engine(&self) -> &EngineWeak {
82        &self.inner.engine
83    }
84
85    /// Returns the [`FuncType`] at the given index.
86    pub fn get_func_type(&self, func_type_idx: FuncTypeIdx) -> &DedupFuncType {
87        &self.inner.func_types[func_type_idx.into_u32() as usize]
88    }
89
90    /// Returns the [`FuncType`] of the indexed function.
91    pub fn get_type_of_func(&self, func_idx: FuncIdx) -> &DedupFuncType {
92        &self.inner.funcs[func_idx.into_u32() as usize]
93    }
94
95    /// Returns the [`GlobalType`] the the indexed global variable.
96    pub fn get_type_of_global(&self, global_idx: GlobalIdx) -> &GlobalType {
97        &self.inner.globals[global_idx.into_u32() as usize]
98    }
99
100    /// Returns the [`CompiledFunc`] for the given [`FuncIdx`].
101    ///
102    /// Returns `None` if [`FuncIdx`] refers to an imported function.
103    pub fn get_compiled_func(&self, func_idx: FuncIdx) -> Option<CompiledFunc> {
104        let index = func_idx.into_u32() as usize;
105        let len_imported = self.inner.imports.len_funcs();
106        let index = index.checked_sub(len_imported)?;
107        // Note: It is a bug if this index access is out of bounds
108        //       therefore we panic here instead of using `get`.
109        Some(self.inner.compiled_funcs[index])
110    }
111
112    /// Returns the [`FuncIdx`] for the given [`CompiledFunc`].
113    pub fn get_func_index(&self, func: CompiledFunc) -> Option<FuncIdx> {
114        self.inner.compiled_funcs_idx.get(&func).copied()
115    }
116
117    /// Returns the global variable type and optional initial value.
118    pub fn get_global(&self, global_idx: GlobalIdx) -> (&GlobalType, Option<&ConstExpr>) {
119        let index = global_idx.into_u32() as usize;
120        let len_imports = self.inner.imports.len_globals();
121        let global_type = self.get_type_of_global(global_idx);
122        if index < len_imports {
123            // The index refers to an imported global without init value.
124            (global_type, None)
125        } else {
126            // The index refers to an internal global with init value.
127            let init_expr = &self.inner.globals_init[index - len_imports];
128            (global_type, Some(init_expr))
129        }
130    }
131}
132
133/// The index of the default Wasm linear memory.
134pub(crate) const DEFAULT_MEMORY_INDEX: u32 = 0;
135
136/// An imported item declaration in the [`Module`].
137#[derive(Debug)]
138pub enum Imported {
139    /// The name of an imported [`Func`].
140    ///
141    /// [`Func`]: [`crate::Func`]
142    Func(ImportName),
143    /// The name of an imported [`Table`].
144    ///
145    /// [`Table`]: [`crate::Table`]
146    Table(ImportName),
147    /// The name of an imported [`Memory`].
148    ///
149    /// [`Memory`]: [`crate::Memory`]
150    Memory(ImportName),
151    /// The name of an imported [`Global`].
152    Global(ImportName),
153}
154
155/// The import names of the [`Module`] imports.
156#[derive(Debug)]
157pub struct ModuleImports {
158    /// All names and types of all imported items.
159    items: Box<[Imported]>,
160    /// The amount of imported [`Func`].
161    ///
162    /// [`Func`]: [`crate::Func`]
163    len_funcs: usize,
164    /// The amount of imported [`Global`].
165    len_globals: usize,
166    /// The amount of imported [`Memory`].
167    ///
168    /// [`Memory`]: [`crate::Memory`]
169    len_memories: usize,
170    /// The amount of imported [`Table`].
171    ///
172    /// [`Table`]: [`crate::Table`]
173    len_tables: usize,
174}
175
176impl ModuleImports {
177    /// Returns the number of imported global variables.
178    pub fn len_globals(&self) -> usize {
179        self.len_globals
180    }
181
182    /// Returns the number of imported functions.
183    pub fn len_funcs(&self) -> usize {
184        self.len_funcs
185    }
186}
187
188impl Module {
189    /// Creates a new Wasm [`Module`] from the given Wasm bytecode buffer.
190    ///
191    /// # Note
192    ///
193    /// This parses, validates and translates the buffered Wasm bytecode.
194    ///
195    /// # Errors
196    ///
197    /// - If the Wasm bytecode is malformed or fails to validate.
198    /// - If the Wasm bytecode violates restrictions
199    ///   set in the [`Config`] used by the `engine`.
200    /// - If Wasmi cannot translate the Wasm bytecode.
201    ///
202    /// [`Config`]: crate::Config
203    pub fn new(engine: &Engine, wasm: &[u8]) -> Result<Self, Error> {
204        ModuleParser::new(engine).parse_buffered(wasm)
205    }
206
207    /// Creates a new Wasm [`Module`] from the given Wasm bytecode stream.
208    ///
209    /// # Note
210    ///
211    /// This parses, validates and translates the Wasm bytecode yielded by `stream`.
212    ///
213    /// # Errors
214    ///
215    /// - If the Wasm bytecode is malformed or fails to validate.
216    /// - If the Wasm bytecode violates restrictions
217    ///   set in the [`Config`] used by the `engine`.
218    /// - If Wasmi cannot translate the Wasm bytecode.
219    ///
220    /// [`Config`]: crate::Config
221    pub fn new_streaming(engine: &Engine, stream: impl Read) -> Result<Self, Error> {
222        ModuleParser::new(engine).parse_streaming(stream)
223    }
224
225    /// Creates a new Wasm [`Module`] from the given Wasm bytecode buffer.
226    ///
227    /// # Note
228    ///
229    /// This parses and translates the buffered Wasm bytecode.
230    ///
231    /// # Safety
232    ///
233    /// - This does _not_ validate the Wasm bytecode.
234    /// - It is the caller's responsibility that the Wasm bytecode is valid.
235    /// - It is the caller's responsibility that the Wasm bytecode adheres
236    ///   to the restrictions set by the used [`Config`] of the `engine`.
237    /// - Violating the above rules is undefined behavior.
238    ///
239    /// # Errors
240    ///
241    /// - If the Wasm bytecode is malformed or contains invalid sections.
242    /// - If the Wasm bytecode fails to be compiled by Wasmi.
243    ///
244    /// [`Config`]: crate::Config
245    pub unsafe fn new_unchecked(engine: &Engine, wasm: &[u8]) -> Result<Self, Error> {
246        let parser = ModuleParser::new(engine);
247        unsafe { parser.parse_buffered_unchecked(wasm) }
248    }
249
250    /// Creates a new Wasm [`Module`] from the given byte stream.
251    ///
252    /// # Note
253    ///
254    /// This parses and translates the Wasm bytecode yielded by `stream`.
255    ///
256    /// # Safety
257    ///
258    /// - This does _not_ validate the Wasm bytecode.
259    /// - It is the caller's responsibility that the Wasm bytecode is valid.
260    /// - It is the caller's responsibility that the Wasm bytecode adheres
261    ///   to the restrictions set by the used [`Config`] of the `engine`.
262    /// - Violating the above rules is undefined behavior.
263    ///
264    /// # Errors
265    ///
266    /// - If the Wasm bytecode is malformed or contains invalid sections.
267    /// - If the Wasm bytecode fails to be compiled by Wasmi.
268    ///
269    /// [`Config`]: crate::Config
270    pub unsafe fn new_streaming_unchecked(
271        engine: &Engine,
272        stream: impl Read,
273    ) -> Result<Self, Error> {
274        let parser = ModuleParser::new(engine);
275        unsafe { parser.parse_streaming_unchecked(stream) }
276    }
277
278    /// Returns the [`Engine`] used during creation of the [`Module`].
279    pub fn engine(&self) -> &Engine {
280        &self.engine
281    }
282
283    /// Validates `wasm` as a WebAssembly binary given the configuration (via [`Config`]) in `engine`.
284    ///
285    /// This function performs Wasm validation of the binary input WebAssembly module and
286    /// returns either `Ok`` or `Err`` depending on the results of the validation.
287    /// The [`Config`] of the `engine` is used for Wasm validation which indicates which WebAssembly
288    /// features are valid and invalid for the validation.
289    ///
290    /// # Note
291    ///
292    /// - The input `wasm` must be in binary form, the text format is not accepted by this function.
293    /// - This will only validate the `wasm` but not try to translate it. Therefore `Module::new`
294    ///   might still fail if translation of the Wasm binary input fails to translate via the Wasmi
295    ///   [`Engine`].
296    /// - Validation automatically happens as part of [`Module::new`].
297    ///
298    /// # Errors
299    ///
300    /// If Wasm validation for `wasm` fails for the given [`Config`] provided via `engine`.
301    ///
302    /// [`Config`]: crate::Config
303    pub fn validate(engine: &Engine, wasm: &[u8]) -> Result<(), Error> {
304        let mut validator = Validator::new_with_features(engine.config().wasm_features());
305        for payload in Parser::new(0).parse_all(wasm) {
306            let payload = payload?;
307            if let ValidPayload::Func(func_to_validate, func_body) = validator.payload(&payload)? {
308                func_to_validate
309                    .into_validator(FuncValidatorAllocations::default())
310                    .validate(&func_body)?;
311            }
312        }
313        Ok(())
314    }
315
316    /// Returns the number of non-imported functions of the [`Module`].
317    pub(crate) fn len_funcs(&self) -> usize {
318        self.header.inner.funcs.len()
319    }
320    /// Returns the number of non-imported tables of the [`Module`].
321    pub(crate) fn len_tables(&self) -> usize {
322        self.header.inner.tables.len()
323    }
324    /// Returns the number of non-imported linear memories of the [`Module`].
325    pub(crate) fn len_memories(&self) -> usize {
326        self.header.inner.memories.len()
327    }
328    /// Returns the number of non-imported global variables of the [`Module`].
329    pub(crate) fn len_globals(&self) -> usize {
330        self.header.inner.globals.len()
331    }
332
333    /// Returns a slice to the function types of the [`Module`].
334    ///
335    /// # Note
336    ///
337    /// The slice is stored in a `Arc` so that this operation is very cheap.
338    pub(crate) fn func_types_cloned(&self) -> Arc<[DedupFuncType]> {
339        self.header.inner.func_types.clone()
340    }
341
342    /// Returns an iterator over the imports of the [`Module`].
343    pub fn imports(&self) -> ModuleImportsIter {
344        let len_imported_funcs = self.header.inner.imports.len_funcs;
345        let len_imported_globals = self.header.inner.imports.len_globals;
346        ModuleImportsIter {
347            engine: self.engine(),
348            names: self.header.inner.imports.items.iter(),
349            funcs: self.header.inner.funcs[..len_imported_funcs].iter(),
350            tables: self.header.inner.tables.iter(),
351            memories: self.header.inner.memories.iter(),
352            globals: self.header.inner.globals[..len_imported_globals].iter(),
353        }
354    }
355
356    /// Returns an iterator over the internally defined [`Func`].
357    ///
358    /// [`Func`]: [`crate::Func`]
359    pub(crate) fn internal_funcs(&self) -> InternalFuncsIter {
360        let len_imported = self.header.inner.imports.len_funcs;
361        // We skip the first `len_imported` elements in `funcs`
362        // since they refer to imported and not internally defined
363        // functions.
364        let funcs = &self.header.inner.funcs[len_imported..];
365        let compiled_funcs = &self.header.inner.compiled_funcs[..];
366        assert_eq!(funcs.len(), compiled_funcs.len());
367        InternalFuncsIter {
368            iter: funcs.iter().zip(compiled_funcs),
369        }
370    }
371
372    /// Returns an iterator over the [`MemoryType`] of internal linear memories.
373    fn internal_memories(&self) -> SliceIter<MemoryType> {
374        let len_imported = self.header.inner.imports.len_memories;
375        // We skip the first `len_imported` elements in `memories`
376        // since they refer to imported and not internally defined
377        // linear memories.
378        let memories = &self.header.inner.memories[len_imported..];
379        memories.iter()
380    }
381
382    /// Returns an iterator over the [`TableType`] of internal tables.
383    fn internal_tables(&self) -> SliceIter<TableType> {
384        let len_imported = self.header.inner.imports.len_tables;
385        // We skip the first `len_imported` elements in `memories`
386        // since they refer to imported and not internally defined
387        // linear memories.
388        let tables = &self.header.inner.tables[len_imported..];
389        tables.iter()
390    }
391
392    /// Returns an iterator over the internally defined [`Global`].
393    fn internal_globals(&self) -> InternalGlobalsIter {
394        let len_imported = self.header.inner.imports.len_globals;
395        // We skip the first `len_imported` elements in `globals`
396        // since they refer to imported and not internally defined
397        // global variables.
398        let globals = self.header.inner.globals[len_imported..].iter();
399        let global_inits = self.header.inner.globals_init.iter();
400        InternalGlobalsIter {
401            iter: globals.zip(global_inits),
402        }
403    }
404
405    /// Returns an iterator over the exports of the [`Module`].
406    pub fn exports(&self) -> ModuleExportsIter {
407        ModuleExportsIter::new(self)
408    }
409
410    /// Looks up an export in this [`Module`] by its `name`.
411    ///
412    /// Returns `None` if no export with the name was found.
413    ///
414    /// # Note
415    ///
416    /// This function will return the type of an export with the given `name`.
417    pub fn get_export(&self, name: &str) -> Option<ExternType> {
418        let idx = self.header.inner.exports.get(name).copied()?;
419        let ty = self.get_extern_type(idx);
420        Some(ty)
421    }
422
423    /// Returns the [`ExternType`] for a given [`ExternIdx`].
424    ///
425    /// # Note
426    ///
427    /// This function assumes that the given [`ExternType`] is valid.
428    fn get_extern_type(&self, idx: ExternIdx) -> ExternType {
429        match idx {
430            ExternIdx::Func(index) => {
431                let dedup = &self.header.inner.funcs[index.into_u32() as usize];
432                let func_type = self.engine().resolve_func_type(dedup, Clone::clone);
433                ExternType::Func(func_type)
434            }
435            ExternIdx::Table(index) => {
436                let table_type = self.header.inner.tables[index.into_u32() as usize];
437                ExternType::Table(table_type)
438            }
439            ExternIdx::Memory(index) => {
440                let memory_type = self.header.inner.memories[index.into_u32() as usize];
441                ExternType::Memory(memory_type)
442            }
443            ExternIdx::Global(index) => {
444                let global_type = self.header.inner.globals[index.into_u32() as usize];
445                ExternType::Global(global_type)
446            }
447        }
448    }
449}
450
451/// An iterator over the imports of a [`Module`].
452#[derive(Debug)]
453pub struct ModuleImportsIter<'a> {
454    engine: &'a Engine,
455    names: SliceIter<'a, Imported>,
456    funcs: SliceIter<'a, DedupFuncType>,
457    tables: SliceIter<'a, TableType>,
458    memories: SliceIter<'a, MemoryType>,
459    globals: SliceIter<'a, GlobalType>,
460}
461
462impl<'a> Iterator for ModuleImportsIter<'a> {
463    type Item = ImportType<'a>;
464
465    fn next(&mut self) -> Option<Self::Item> {
466        let import = match self.names.next() {
467            None => return None,
468            Some(imported) => match imported {
469                Imported::Func(name) => {
470                    let func_type = self.funcs.next().unwrap_or_else(|| {
471                        panic!("unexpected missing imported function for {name:?}")
472                    });
473                    let func_type = self.engine.resolve_func_type(func_type, FuncType::clone);
474                    ImportType::new(name, func_type)
475                }
476                Imported::Table(name) => {
477                    let table_type = self.tables.next().unwrap_or_else(|| {
478                        panic!("unexpected missing imported table for {name:?}")
479                    });
480                    ImportType::new(name, *table_type)
481                }
482                Imported::Memory(name) => {
483                    let memory_type = self.memories.next().unwrap_or_else(|| {
484                        panic!("unexpected missing imported linear memory for {name:?}")
485                    });
486                    ImportType::new(name, *memory_type)
487                }
488                Imported::Global(name) => {
489                    let global_type = self.globals.next().unwrap_or_else(|| {
490                        panic!("unexpected missing imported global variable for {name:?}")
491                    });
492                    ImportType::new(name, *global_type)
493                }
494            },
495        };
496        Some(import)
497    }
498
499    fn size_hint(&self) -> (usize, Option<usize>) {
500        self.names.size_hint()
501    }
502}
503
504impl<'a> ExactSizeIterator for ModuleImportsIter<'a> {
505    fn len(&self) -> usize {
506        ExactSizeIterator::len(&self.names)
507    }
508}
509
510/// A descriptor for an imported value into a Wasm [`Module`].
511///
512/// This type is primarily accessed from the [`Module::imports`] method.
513/// Each [`ImportType`] describes an import into the Wasm module with the `module/name`
514/// that it is imported from as well as the type of item that is being imported.
515#[derive(Debug)]
516pub struct ImportType<'module> {
517    /// The name of the imported item.
518    name: &'module ImportName,
519    /// The external item type.
520    ty: ExternType,
521}
522
523impl<'module> ImportType<'module> {
524    /// Creates a new [`ImportType`].
525    pub(crate) fn new<T>(name: &'module ImportName, ty: T) -> Self
526    where
527        T: Into<ExternType>,
528    {
529        Self {
530            name,
531            ty: ty.into(),
532        }
533    }
534
535    /// Returns the import name.
536    pub(crate) fn import_name(&self) -> &ImportName {
537        self.name
538    }
539
540    /// Returns the module import name.
541    pub fn module(&self) -> &'module str {
542        self.name.module()
543    }
544
545    /// Returns the field import name.
546    pub fn name(&self) -> &'module str {
547        self.name.name()
548    }
549
550    /// Returns the import item type.
551    pub fn ty(&self) -> &ExternType {
552        &self.ty
553    }
554}
555
556/// An iterator over the internally defined functions of a [`Module`].
557#[derive(Debug)]
558pub struct InternalFuncsIter<'a> {
559    iter: iter::Zip<SliceIter<'a, DedupFuncType>, SliceIter<'a, CompiledFunc>>,
560}
561
562impl<'a> Iterator for InternalFuncsIter<'a> {
563    type Item = (DedupFuncType, CompiledFunc);
564
565    fn next(&mut self) -> Option<Self::Item> {
566        self.iter
567            .next()
568            .map(|(func_type, func_body)| (*func_type, *func_body))
569    }
570
571    fn size_hint(&self) -> (usize, Option<usize>) {
572        self.iter.size_hint()
573    }
574}
575
576impl<'a> ExactSizeIterator for InternalFuncsIter<'a> {
577    fn len(&self) -> usize {
578        ExactSizeIterator::len(&self.iter)
579    }
580}
581
582/// An iterator over the internally defined functions of a [`Module`].
583#[derive(Debug)]
584pub struct InternalGlobalsIter<'a> {
585    iter: iter::Zip<SliceIter<'a, GlobalType>, SliceIter<'a, ConstExpr>>,
586}
587
588impl<'a> Iterator for InternalGlobalsIter<'a> {
589    type Item = (&'a GlobalType, &'a ConstExpr);
590
591    fn next(&mut self) -> Option<Self::Item> {
592        self.iter.next()
593    }
594
595    fn size_hint(&self) -> (usize, Option<usize>) {
596        self.iter.size_hint()
597    }
598}
599
600impl<'a> ExactSizeIterator for InternalGlobalsIter<'a> {
601    fn len(&self) -> usize {
602        ExactSizeIterator::len(&self.iter)
603    }
604}