casper_wasmi/
module.rs

1use crate::{
2    func::{FuncBody, FuncInstance, FuncRef},
3    global::{GlobalInstance, GlobalRef},
4    host::Externals,
5    imports::ImportResolver,
6    memory::MemoryRef,
7    memory_units::Pages,
8    nan_preserving_float::{F32, F64},
9    runner::StackRecycler,
10    table::TableRef,
11    types::{GlobalDescriptor, MemoryDescriptor, TableDescriptor},
12    Error,
13    MemoryInstance,
14    Module,
15    RuntimeValue,
16    Signature,
17    TableInstance,
18    Trap,
19};
20use alloc::{
21    borrow::ToOwned,
22    collections::BTreeMap,
23    rc::Rc,
24    string::{String, ToString},
25    vec::Vec,
26};
27use casper_wasm::elements::{External, InitExpr, Instruction, Internal, ResizableLimits, Type};
28use core::{
29    cell::{Ref, RefCell},
30    fmt,
31};
32use validation::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
33
34/// Reference to a [`ModuleInstance`].
35///
36/// This reference has a reference-counting semantics.
37///
38/// All [`ModuleInstance`] have strong references to it's components (i.e.
39/// globals, memories, funcs, tables), however, this components have
40/// weak references to it's containing module. This might be a problem
41/// at execution time.
42///
43/// So if have to make sure that all modules which might be needed at execution time
44/// should be retained.
45///
46/// [`ModuleInstance`]: struct.ModuleInstance.html
47#[derive(Clone, Debug)]
48pub struct ModuleRef(pub(crate) Rc<ModuleInstance>);
49
50impl ::core::ops::Deref for ModuleRef {
51    type Target = ModuleInstance;
52    fn deref(&self) -> &ModuleInstance {
53        &self.0
54    }
55}
56
57/// An external value is the runtime representation of an entity
58/// that can be imported or exported.
59pub enum ExternVal {
60    /// [Function][`FuncInstance`].
61    ///
62    /// [`FuncInstance`]: struct.FuncInstance.html
63    Func(FuncRef),
64    /// [Table][`TableInstance`].
65    ///
66    /// [`TableInstance`]: struct.TableInstance.html
67    Table(TableRef),
68    /// [Memory][`MemoryInstance`].
69    ///
70    /// [`MemoryInstance`]: struct.MemoryInstance.html
71    Memory(MemoryRef),
72    /// [Global][`GlobalInstance`].
73    ///
74    /// Should be immutable.
75    ///
76    /// [`GlobalInstance`]: struct.GlobalInstance.html
77    Global(GlobalRef),
78}
79
80impl Clone for ExternVal {
81    fn clone(&self) -> Self {
82        match *self {
83            ExternVal::Func(ref func) => ExternVal::Func(func.clone()),
84            ExternVal::Table(ref table) => ExternVal::Table(table.clone()),
85            ExternVal::Memory(ref memory) => ExternVal::Memory(memory.clone()),
86            ExternVal::Global(ref global) => ExternVal::Global(global.clone()),
87        }
88    }
89}
90
91impl fmt::Debug for ExternVal {
92    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93        write!(
94            f,
95            "ExternVal {{ {} }}",
96            match *self {
97                ExternVal::Func(_) => "Func",
98                ExternVal::Table(_) => "Table",
99                ExternVal::Memory(_) => "Memory",
100                ExternVal::Global(_) => "Global",
101            }
102        )
103    }
104}
105
106impl ExternVal {
107    /// Get underlying function reference if this `ExternVal` contains
108    /// a function, or `None` if it is some other kind.
109    pub fn as_func(&self) -> Option<&FuncRef> {
110        match *self {
111            ExternVal::Func(ref func) => Some(func),
112            _ => None,
113        }
114    }
115
116    /// Get underlying table reference if this `ExternVal` contains
117    /// a table, or `None` if it is some other kind.
118    pub fn as_table(&self) -> Option<&TableRef> {
119        match *self {
120            ExternVal::Table(ref table) => Some(table),
121            _ => None,
122        }
123    }
124
125    /// Get underlying memory reference if this `ExternVal` contains
126    /// a memory, or `None` if it is some other kind.
127    pub fn as_memory(&self) -> Option<&MemoryRef> {
128        match *self {
129            ExternVal::Memory(ref memory) => Some(memory),
130            _ => None,
131        }
132    }
133
134    /// Get underlying global variable reference if this `ExternVal` contains
135    /// a global, or `None` if it is some other kind.
136    pub fn as_global(&self) -> Option<&GlobalRef> {
137        match *self {
138            ExternVal::Global(ref global) => Some(global),
139            _ => None,
140        }
141    }
142}
143
144/// A module instance is the runtime representation of a [module][`Module`].
145///
146/// It is created by instantiating a [module][`Module`], and collects runtime representations
147/// of all entities that are imported or defined by the module, namely:
148///
149/// - [functions][`FuncInstance`],
150/// - [memories][`MemoryInstance`],
151/// - [tables][`TableInstance`],
152/// - [globals][`GlobalInstance`],
153///
154/// In order to instantiate a module you need to provide entities to satisfy
155/// every module's imports (i.e. wasm modules don't have optional imports).
156///
157/// After module is instantiated you can start invoking it's exported functions with [`invoke_export`].
158///
159/// [`Module`]: struct.Module.html
160/// [`FuncInstance`]: struct.FuncInstance.html
161/// [`MemoryInstance`]: struct.MemoryInstance.html
162/// [`TableInstance`]: struct.TableInstance.html
163/// [`GlobalInstance`]: struct.GlobalInstance.html
164/// [`invoke_export`]: #method.invoke_export
165#[derive(Debug)]
166pub struct ModuleInstance {
167    signatures: RefCell<Vec<Rc<Signature>>>,
168    tables: RefCell<Vec<TableRef>>,
169    funcs: RefCell<Vec<FuncRef>>,
170    memories: RefCell<Vec<MemoryRef>>,
171    globals: RefCell<Vec<GlobalRef>>,
172    exports: RefCell<BTreeMap<String, ExternVal>>,
173}
174
175impl ModuleInstance {
176    fn default() -> Self {
177        ModuleInstance {
178            funcs: RefCell::new(Vec::new()),
179            signatures: RefCell::new(Vec::new()),
180            tables: RefCell::new(Vec::new()),
181            memories: RefCell::new(Vec::new()),
182            globals: RefCell::new(Vec::new()),
183            exports: RefCell::new(BTreeMap::new()),
184        }
185    }
186
187    pub(crate) fn memory_by_index(&self, idx: u32) -> Option<MemoryRef> {
188        self.memories.borrow_mut().get(idx as usize).cloned()
189    }
190
191    pub(crate) fn table_by_index(&self, idx: u32) -> Option<TableRef> {
192        self.tables.borrow_mut().get(idx as usize).cloned()
193    }
194
195    pub(crate) fn global_by_index(&self, idx: u32) -> Option<GlobalRef> {
196        self.globals.borrow_mut().get(idx as usize).cloned()
197    }
198
199    pub(crate) fn func_by_index(&self, idx: u32) -> Option<FuncRef> {
200        self.funcs.borrow().get(idx as usize).cloned()
201    }
202
203    pub(crate) fn signature_by_index(&self, idx: u32) -> Option<Rc<Signature>> {
204        self.signatures.borrow().get(idx as usize).cloned()
205    }
206
207    fn push_func(&self, func: FuncRef) {
208        self.funcs.borrow_mut().push(func);
209    }
210
211    fn push_signature(&self, signature: Rc<Signature>) {
212        self.signatures.borrow_mut().push(signature)
213    }
214
215    fn push_memory(&self, memory: MemoryRef) {
216        self.memories.borrow_mut().push(memory)
217    }
218
219    fn push_table(&self, table: TableRef) {
220        self.tables.borrow_mut().push(table)
221    }
222
223    fn push_global(&self, global: GlobalRef) {
224        self.globals.borrow_mut().push(global)
225    }
226
227    /// Access all globals. This is a non-standard API so it's unlikely to be
228    /// portable to other engines.
229    pub fn globals(&self) -> Ref<Vec<GlobalRef>> {
230        self.globals.borrow()
231    }
232
233    fn insert_export<N: Into<String>>(&self, name: N, extern_val: ExternVal) {
234        self.exports.borrow_mut().insert(name.into(), extern_val);
235    }
236
237    fn alloc_module<'i, I: Iterator<Item = &'i ExternVal>>(
238        loaded_module: &Module,
239        extern_vals: I,
240    ) -> Result<ModuleRef, Error> {
241        let module = loaded_module.module();
242        let instance = ModuleRef(Rc::new(ModuleInstance::default()));
243
244        for Type::Function(ty) in module.type_section().map(|ts| ts.types()).unwrap_or(&[]) {
245            let signature = Rc::new(Signature::from_elements(ty));
246            instance.push_signature(signature);
247        }
248
249        {
250            let mut imports = module
251                .import_section()
252                .map(|is| is.entries())
253                .unwrap_or(&[])
254                .iter();
255            let mut extern_vals = extern_vals;
256            loop {
257                // Iterate on imports and extern_vals in lockstep, a-la `Iterator:zip`.
258                // We can't use `Iterator::zip` since we want to check if lengths of both iterators are same and
259                // `Iterator::zip` just returns `None` if either of iterators return `None`.
260                let (import, extern_val) = match (imports.next(), extern_vals.next()) {
261                    (Some(import), Some(extern_val)) => (import, extern_val),
262                    (None, None) => break,
263                    (Some(_), None) | (None, Some(_)) => {
264                        return Err(Error::Instantiation(
265                            "extern_vals length is not equal to import section entries".to_owned(),
266                        ));
267                    }
268                };
269
270                match (import.external(), extern_val) {
271                    (&External::Function(fn_type_idx), ExternVal::Func(func)) => {
272                        let expected_fn_type = instance
273                            .signature_by_index(fn_type_idx)
274                            .expect("Due to validation function type should exists");
275                        let actual_fn_type = func.signature();
276                        if &*expected_fn_type != actual_fn_type {
277                            return Err(Error::Instantiation(format!(
278								"Expected function with type {:?}, but actual type is {:?} for entry {}",
279								expected_fn_type,
280								actual_fn_type,
281								import.field(),
282							)));
283                        }
284                        instance.push_func(func.clone())
285                    }
286                    (External::Table(tt), ExternVal::Table(table)) => {
287                        match_limits(table.limits(), tt.limits())?;
288                        instance.push_table(table.clone());
289                    }
290                    (External::Memory(mt), ExternVal::Memory(memory)) => {
291                        match_limits(memory.limits(), mt.limits())?;
292                        instance.push_memory(memory.clone());
293                    }
294                    (External::Global(gl), ExternVal::Global(global)) => {
295                        if gl.content_type() != global.elements_value_type() {
296                            return Err(Error::Instantiation(format!(
297                                "Expect global with {:?} type, but provided global with {:?} type",
298                                gl.content_type(),
299                                global.value_type(),
300                            )));
301                        }
302                        instance.push_global(global.clone());
303                    }
304                    (expected_import, actual_extern_val) => {
305                        return Err(Error::Instantiation(format!(
306                            "Expected {:?} type, but provided {:?} extern_val",
307                            expected_import, actual_extern_val
308                        )));
309                    }
310                }
311            }
312        }
313
314        let code = loaded_module.code();
315        {
316            let funcs = module
317                .function_section()
318                .map(|fs| fs.entries())
319                .unwrap_or(&[]);
320            let bodies = module.code_section().map(|cs| cs.bodies()).unwrap_or(&[]);
321            debug_assert!(
322                funcs.len() == bodies.len(),
323                "Due to validation func and body counts must match"
324            );
325
326            for (index, (ty, body)) in Iterator::zip(funcs.iter(), bodies.iter()).enumerate() {
327                let signature = instance
328                    .signature_by_index(ty.type_ref())
329                    .expect("Due to validation type should exists");
330                let code = code.get(index).expect(
331					"At func validation time labels are collected; Collected labels are added by index; qed",
332				).clone();
333                let func_body = FuncBody {
334                    locals: body.locals().to_vec(),
335                    code,
336                };
337                let func_instance =
338                    FuncInstance::alloc_internal(Rc::downgrade(&instance.0), signature, func_body);
339                instance.push_func(func_instance);
340            }
341        }
342
343        for table_type in module.table_section().map(|ts| ts.entries()).unwrap_or(&[]) {
344            let table =
345                TableInstance::alloc(table_type.limits().initial(), table_type.limits().maximum())?;
346            instance.push_table(table);
347        }
348
349        for memory_type in module
350            .memory_section()
351            .map(|ms| ms.entries())
352            .unwrap_or(&[])
353        {
354            let initial: Pages = Pages(memory_type.limits().initial() as usize);
355            let maximum: Option<Pages> = memory_type.limits().maximum().map(|m| Pages(m as usize));
356
357            let memory = MemoryInstance::alloc(initial, maximum)
358                .expect("Due to validation `initial` and `maximum` should be valid");
359            instance.push_memory(memory);
360        }
361
362        for global_entry in module
363            .global_section()
364            .map(|gs| gs.entries())
365            .unwrap_or(&[])
366        {
367            let init_val = eval_init_expr(global_entry.init_expr(), &instance);
368            let global = GlobalInstance::alloc(init_val, global_entry.global_type().is_mutable());
369            instance.push_global(global);
370        }
371
372        for export in module
373            .export_section()
374            .map(|es| es.entries())
375            .unwrap_or(&[])
376        {
377            let field = export.field();
378            let extern_val: ExternVal = match *export.internal() {
379                Internal::Function(idx) => {
380                    let func = instance
381                        .func_by_index(idx)
382                        .expect("Due to validation func should exists");
383                    ExternVal::Func(func)
384                }
385                Internal::Global(idx) => {
386                    let global = instance
387                        .global_by_index(idx)
388                        .expect("Due to validation global should exists");
389                    ExternVal::Global(global)
390                }
391                Internal::Memory(idx) => {
392                    let memory = instance
393                        .memory_by_index(idx)
394                        .expect("Due to validation memory should exists");
395                    ExternVal::Memory(memory)
396                }
397                Internal::Table(idx) => {
398                    let table = instance
399                        .table_by_index(idx)
400                        .expect("Due to validation table should exists");
401                    ExternVal::Table(table)
402                }
403            };
404            instance.insert_export(field, extern_val);
405        }
406
407        Ok(instance)
408    }
409
410    /// Instantiate a module with given [external values][ExternVal] as imports.
411    ///
412    /// See [new] for details.
413    ///
414    /// [new]: #method.new
415    /// [ExternVal]: https://webassembly.github.io/spec/core/exec/runtime.html#syntax-externval
416    pub fn with_externvals<'a, 'i, I: Iterator<Item = &'i ExternVal>>(
417        loaded_module: &'a Module,
418        extern_vals: I,
419    ) -> Result<NotStartedModuleRef<'a>, Error> {
420        let module = loaded_module.module();
421
422        let module_ref = ModuleInstance::alloc_module(loaded_module, extern_vals)?;
423
424        for element_segment in module
425            .elements_section()
426            .map(|es| es.entries())
427            .unwrap_or(&[])
428        {
429            let offset = element_segment
430                .offset()
431                .as_ref()
432                .expect("passive segments are rejected due to validation");
433            let offset_val = match eval_init_expr(offset, &module_ref) {
434                RuntimeValue::I32(v) => v as u32,
435                _ => panic!("Due to validation elem segment offset should evaluate to i32"),
436            };
437
438            let table_inst = module_ref
439                .table_by_index(DEFAULT_TABLE_INDEX)
440                .expect("Due to validation default table should exists");
441
442            // This check is not only for bailing out early, but also to check the case when
443            // segment consist of 0 members.
444            if offset_val as u64 + element_segment.members().len() as u64
445                > table_inst.current_size() as u64
446            {
447                return Err(Error::Instantiation(
448                    "elements segment does not fit".to_string(),
449                ));
450            }
451
452            for (j, func_idx) in element_segment.members().iter().enumerate() {
453                let func = module_ref
454                    .func_by_index(*func_idx)
455                    .expect("Due to validation funcs from element segments should exists");
456
457                table_inst.set(offset_val + j as u32, Some(func))?;
458            }
459        }
460
461        for data_segment in module.data_section().map(|ds| ds.entries()).unwrap_or(&[]) {
462            let offset = data_segment
463                .offset()
464                .as_ref()
465                .expect("passive segments are rejected due to validation");
466            let offset_val = match eval_init_expr(offset, &module_ref) {
467                RuntimeValue::I32(v) => v as u32,
468                _ => panic!("Due to validation data segment offset should evaluate to i32"),
469            };
470
471            let memory_inst = module_ref
472                .memory_by_index(DEFAULT_MEMORY_INDEX)
473                .expect("Due to validation default memory should exists");
474            memory_inst.set(offset_val, data_segment.value())?;
475        }
476
477        Ok(NotStartedModuleRef {
478            loaded_module,
479            instance: module_ref,
480        })
481    }
482
483    /// Instantiate a [module][`Module`].
484    ///
485    /// Note that in case of successful instantiation this function returns a reference to
486    /// a module which `start` function is not called.
487    /// In order to complete instantiatiation `start` function must be called. However, there are
488    /// situations where you might need to do additional setup before calling `start` function.
489    /// For such sitations this separation might be useful.
490    ///
491    /// See [`NotStartedModuleRef`] for details.
492    ///
493    /// # Errors
494    ///
495    /// Returns `Err` if the module cannot be instantiated.
496    ///
497    /// This can happen if one of the imports can't
498    /// be satisfied (e.g module isn't registered in `imports` [resolver][`ImportResolver`]) or
499    /// there is a mismatch between requested import and provided (e.g. module requested memory with no
500    /// maximum size limit, however, was provided memory with the maximum size limit).
501    ///
502    /// # Examples
503    ///
504    /// ```rust
505    /// use casper_wasmi::{ModuleInstance, ImportsBuilder, NopExternals};
506    /// # fn func() -> Result<(), ::casper_wasmi::Error> {
507    /// # let module = casper_wasmi::Module::from_buffer(&[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]).unwrap();
508    ///
509    /// // ModuleInstance::new returns instance which `start` function isn't called.
510    /// let not_started = ModuleInstance::new(
511    ///     &module,
512    ///     &ImportsBuilder::default()
513    /// )?;
514    /// // Call `start` function if any.
515    /// let instance = not_started.run_start(&mut NopExternals)?;
516    ///
517    /// # Ok(())
518    /// # }
519    /// ```
520    ///
521    /// If you sure that the module doesn't have `start` function you can use [`assert_no_start`] to get
522    /// instantiated module without calling `start` function.
523    ///
524    /// ```rust
525    /// use casper_wasmi::{ModuleInstance, ImportsBuilder, NopExternals};
526    /// # fn func() -> Result<(), ::casper_wasmi::Error> {
527    /// # let module = casper_wasmi::Module::from_buffer(&[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]).unwrap();
528    ///
529    /// // This will panic if the module actually contain `start` function.
530    /// let not_started = ModuleInstance::new(
531    ///     &module,
532    ///     &ImportsBuilder::default()
533    /// )?.assert_no_start();
534    ///
535    /// # Ok(())
536    /// # }
537    /// ```
538    ///
539    /// [`Module`]: struct.Module.html
540    /// [`NotStartedModuleRef`]: struct.NotStartedModuleRef.html
541    /// [`ImportResolver`]: trait.ImportResolver.html
542    /// [`assert_no_start`]: struct.NotStartedModuleRef.html#method.assert_no_start
543    #[allow(clippy::new_ret_no_self)]
544    pub fn new<'m, I: ImportResolver>(
545        loaded_module: &'m Module,
546        imports: &I,
547    ) -> Result<NotStartedModuleRef<'m>, Error> {
548        let module = loaded_module.module();
549
550        let mut extern_vals = Vec::new();
551        for import_entry in module.import_section().map(|s| s.entries()).unwrap_or(&[]) {
552            let module_name = import_entry.module();
553            let field_name = import_entry.field();
554            let extern_val = match *import_entry.external() {
555                External::Function(fn_ty_idx) => {
556                    let types = module.type_section().map(|s| s.types()).unwrap_or(&[]);
557                    let Type::Function(func_type) = types
558                        .get(fn_ty_idx as usize)
559                        .expect("Due to validation functions should have valid types");
560                    let signature = Signature::from_elements(func_type);
561                    let func = imports.resolve_func(module_name, field_name, &signature)?;
562                    ExternVal::Func(func)
563                }
564                External::Table(ref table_type) => {
565                    let table_descriptor = TableDescriptor::from_elements(table_type);
566                    let table =
567                        imports.resolve_table(module_name, field_name, &table_descriptor)?;
568                    ExternVal::Table(table)
569                }
570                External::Memory(ref memory_type) => {
571                    let memory_descriptor = MemoryDescriptor::from_elements(memory_type);
572                    let memory =
573                        imports.resolve_memory(module_name, field_name, &memory_descriptor)?;
574                    ExternVal::Memory(memory)
575                }
576                External::Global(ref global_type) => {
577                    let global_descriptor = GlobalDescriptor::from_elements(global_type);
578                    let global =
579                        imports.resolve_global(module_name, field_name, &global_descriptor)?;
580                    ExternVal::Global(global)
581                }
582            };
583            extern_vals.push(extern_val);
584        }
585
586        Self::with_externvals(loaded_module, extern_vals.iter())
587    }
588
589    /// Invoke exported function by a name.
590    ///
591    /// This function finds exported function by a name, and calls it with provided arguments and
592    /// external state.
593    ///
594    /// # Errors
595    ///
596    /// Returns `Err` if:
597    ///
598    /// - there are no export with a given name or this export is not a function,
599    /// - given arguments doesn't match to function signature,
600    /// - trap occurred at the execution time,
601    ///
602    /// # Examples
603    ///
604    /// Invoke a function that takes two numbers and returns sum of them.
605    ///
606    /// ```rust
607    /// # extern crate casper_wasmi;
608    /// # extern crate wat;
609    /// # use casper_wasmi::{ModuleInstance, ImportsBuilder, NopExternals, RuntimeValue};
610    /// # fn main() {
611    /// # let wasm_binary: Vec<u8> = wat::parse_str(
612    /// #   r#"
613    /// #   (module
614    /// #       (func (export "add") (param i32 i32) (result i32)
615    /// #           local.get 0
616    /// #           local.get 1
617    /// #           i32.add
618    /// #       )
619    /// #   )
620    /// #   "#,
621    /// # ).expect("failed to parse wat");
622    /// # let module = casper_wasmi::Module::from_buffer(&wasm_binary).expect("failed to load wasm");
623    /// # let instance = ModuleInstance::new(
624    /// # &module,
625    /// # &ImportsBuilder::default()
626    /// # ).expect("failed to instantiate wasm module").assert_no_start();
627    /// assert_eq!(
628    ///     instance.invoke_export(
629    ///         "add",
630    ///         &[RuntimeValue::I32(5), RuntimeValue::I32(3)],
631    ///         &mut NopExternals,
632    ///     ).expect("failed to execute export"),
633    ///     Some(RuntimeValue::I32(8)),
634    /// );
635    /// # }
636    /// ```
637    pub fn invoke_export<E: Externals>(
638        &self,
639        func_name: &str,
640        args: &[RuntimeValue],
641        externals: &mut E,
642    ) -> Result<Option<RuntimeValue>, Error> {
643        let func_instance = self.func_by_name(func_name)?;
644
645        FuncInstance::invoke(&func_instance, args, externals).map_err(Error::Trap)
646    }
647
648    /// Invoke exported function by a name using recycled stacks.
649    ///
650    /// # Errors
651    ///
652    /// Same as [`invoke_export`].
653    ///
654    /// [`invoke_export`]: #method.invoke_export
655    pub fn invoke_export_with_stack<E: Externals>(
656        &self,
657        func_name: &str,
658        args: &[RuntimeValue],
659        externals: &mut E,
660        stack_recycler: &mut StackRecycler,
661    ) -> Result<Option<RuntimeValue>, Error> {
662        let func_instance = self.func_by_name(func_name)?;
663
664        FuncInstance::invoke_with_stack(&func_instance, args, externals, stack_recycler)
665            .map_err(Error::Trap)
666    }
667
668    fn func_by_name(&self, func_name: &str) -> Result<FuncRef, Error> {
669        let extern_val = self
670            .export_by_name(func_name)
671            .ok_or_else(|| Error::Function(format!("Module doesn't have export {}", func_name)))?;
672
673        match extern_val {
674            ExternVal::Func(func_instance) => Ok(func_instance),
675            unexpected => Err(Error::Function(format!(
676                "Export {} is not a function, but {:?}",
677                func_name, unexpected
678            ))),
679        }
680    }
681
682    /// Find export by a name.
683    ///
684    /// Returns `None` if there is no export with such name.
685    pub fn export_by_name(&self, name: &str) -> Option<ExternVal> {
686        self.exports.borrow().get(name).cloned()
687    }
688}
689
690/// Mostly instantiated [`ModuleRef`].
691///
692/// At this point memory segments and tables are copied. However, `start` function (if any) is not called.
693/// To get [fully instantiated module instance][`ModuleRef`], [running `start` function][`run_start`] is required.
694///
695/// You can still access not fully initialized instance by calling [`not_started_instance`],
696/// but keep in mind, that this is sort of escape hatch: module really might depend on initialization
697/// done in `start` function. It's definitely not recommended to call any exports on [`ModuleRef`]
698/// returned by this function.
699///
700/// If you sure, that there is no `start` function (e.g. because you created it without one), you can
701/// call [`assert_no_start`] which returns [`ModuleRef`] without calling `start` function. However,
702/// it will panic if module contains `start` function.
703///
704/// [`ModuleRef`]: struct.ModuleRef.html
705/// [`run_start`]: #method.run_start
706/// [`assert_no_start`]: #method.assert_no_start
707/// [`not_started_instance`]: #method.not_started_instance
708pub struct NotStartedModuleRef<'a> {
709    loaded_module: &'a Module,
710    instance: ModuleRef,
711}
712
713impl NotStartedModuleRef<'_> {
714    /// Returns not fully initialized instance.
715    ///
716    /// To fully initialize the instance you need to call either [`run_start`] or
717    /// [`assert_no_start`]. See struct documentation for details.
718    ///
719    /// [`NotStartedModuleRef`]: struct.NotStartedModuleRef.html
720    /// [`ModuleRef`]: struct.ModuleRef.html
721    /// [`run_start`]: #method.run_start
722    /// [`assert_no_start`]: #method.assert_no_start
723    pub fn not_started_instance(&self) -> &ModuleRef {
724        &self.instance
725    }
726
727    /// Executes `start` function (if any) and returns fully instantiated module.
728    ///
729    /// # Errors
730    ///
731    /// Returns `Err` if start function traps.
732    pub fn run_start<E: Externals>(self, state: &mut E) -> Result<ModuleRef, Trap> {
733        if let Some(start_fn_idx) = self.loaded_module.module().start_section() {
734            let start_func = self
735                .instance
736                .func_by_index(start_fn_idx)
737                .expect("Due to validation start function should exists");
738            FuncInstance::invoke(&start_func, &[], state)?;
739        }
740        Ok(self.instance)
741    }
742
743    /// Executes `start` function (if any) and returns fully instantiated module.
744    ///
745    /// # Errors
746    ///
747    /// Returns `Err` if start function traps.
748    pub fn run_start_with_stack<E: Externals>(
749        self,
750        state: &mut E,
751        stack_recycler: &mut StackRecycler,
752    ) -> Result<ModuleRef, Trap> {
753        if let Some(start_fn_idx) = self.loaded_module.module().start_section() {
754            let start_func = self
755                .instance
756                .func_by_index(start_fn_idx)
757                .expect("Due to validation start function should exists");
758            FuncInstance::invoke_with_stack(&start_func, &[], state, stack_recycler)?;
759        }
760        Ok(self.instance)
761    }
762
763    /// Returns fully instantiated module without running `start` function.
764    ///
765    /// # Panics
766    ///
767    /// This function panics if original module contains `start` function.
768    pub fn assert_no_start(self) -> ModuleRef {
769        assert!(
770            self.loaded_module.module().start_section().is_none(),
771            "assert_no_start called on module with `start` function"
772        );
773        self.instance
774    }
775
776    /// Whether or not the module has a `start` function.
777    ///
778    /// Returns `true` if it has a `start` function.
779    pub fn has_start(&self) -> bool {
780        self.loaded_module.module().start_section().is_some()
781    }
782}
783
784fn eval_init_expr(init_expr: &InitExpr, module: &ModuleInstance) -> RuntimeValue {
785    let code = init_expr.code();
786    debug_assert!(
787        code.len() == 2,
788        "Due to validation `code`.len() should be 2"
789    );
790    match code[0] {
791        Instruction::I32Const(v) => v.into(),
792        Instruction::I64Const(v) => v.into(),
793        Instruction::F32Const(v) => F32::from_bits(v).into(),
794        Instruction::F64Const(v) => F64::from_bits(v).into(),
795        Instruction::GetGlobal(idx) => {
796            let global = module
797                .global_by_index(idx)
798                .expect("Due to validation global should exists in module");
799            global.get()
800        }
801        _ => panic!("Due to validation init should be a const expr"),
802    }
803}
804
805fn match_limits(l1: &ResizableLimits, l2: &ResizableLimits) -> Result<(), Error> {
806    if l1.initial() < l2.initial() {
807        return Err(Error::Instantiation(format!(
808            "trying to import with limits l1.initial={} and l2.initial={}",
809            l1.initial(),
810            l2.initial()
811        )));
812    }
813
814    match (l1.maximum(), l2.maximum()) {
815        (_, None) => (),
816        (Some(m1), Some(m2)) if m1 <= m2 => (),
817        _ => {
818            return Err(Error::Instantiation(format!(
819                "trying to import with limits l1.max={:?} and l2.max={:?}",
820                l1.maximum(),
821                l2.maximum()
822            )));
823        }
824    }
825
826    Ok(())
827}
828
829pub fn check_limits(limits: &ResizableLimits) -> Result<(), Error> {
830    if let Some(maximum) = limits.maximum() {
831        if maximum < limits.initial() {
832            return Err(Error::Instantiation(format!(
833                "maximum limit {} is less than minimum {}",
834                maximum,
835                limits.initial()
836            )));
837        }
838    }
839
840    Ok(())
841}
842
843#[cfg(test)]
844mod tests {
845    use super::{ExternVal, ModuleInstance};
846    use crate::{func::FuncInstance, imports::ImportsBuilder, types::Signature, Module, ValueType};
847
848    fn parse_wat(source: &str) -> Module {
849        let wasm_binary = wat::parse_str(source).expect("Failed to parse wat source");
850        Module::from_buffer(wasm_binary).expect("Failed to load parsed module")
851    }
852
853    #[should_panic]
854    #[test]
855    fn assert_no_start_panics_on_module_with_start() {
856        let module_with_start = parse_wat(
857            r#"
858			(module
859				(func $f)
860				(start $f))
861			"#,
862        );
863        let module = ModuleInstance::new(&module_with_start, &ImportsBuilder::default()).unwrap();
864        assert!(!module.has_start());
865        module.assert_no_start();
866    }
867
868    #[test]
869    fn imports_provided_by_externvals() {
870        let module_with_single_import = parse_wat(
871            r#"
872			(module
873				(import "foo" "bar" (func))
874				)
875			"#,
876        );
877
878        assert!(ModuleInstance::with_externvals(
879            &module_with_single_import,
880            [ExternVal::Func(FuncInstance::alloc_host(
881                Signature::new(&[][..], None),
882                0
883            ),)]
884            .iter(),
885        )
886        .is_ok());
887
888        // externval vector is longer than import count.
889        assert!(ModuleInstance::with_externvals(
890            &module_with_single_import,
891            [
892                ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 0)),
893                ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 1)),
894            ]
895            .iter(),
896        )
897        .is_err());
898
899        // externval vector is shorter than import count.
900        assert!(ModuleInstance::with_externvals(&module_with_single_import, [].iter(),).is_err());
901
902        // externval vector has an unexpected type.
903        assert!(ModuleInstance::with_externvals(
904            &module_with_single_import,
905            [ExternVal::Func(FuncInstance::alloc_host(
906                Signature::new(&[][..], Some(ValueType::I32)),
907                0
908            ),)]
909            .iter(),
910        )
911        .is_err());
912    }
913}