wasm/execution/store/
mod.rs

1use core::convert::Infallible;
2
3use crate::addrs::{
4    AddrVec, DataAddr, ElemAddr, FuncAddr, GlobalAddr, MemAddr, ModuleAddr, TableAddr,
5};
6use crate::config::Config;
7use crate::core::indices::{ElemIdx, IdxVec, TypeIdx};
8use crate::core::reader::span::Span;
9use crate::core::reader::types::data::{DataModeActive, DataSegment};
10use crate::core::reader::types::element::{ActiveElem, ElemItems, ElemMode, ElemType};
11use crate::core::reader::types::export::ExportDesc;
12use crate::core::reader::types::global::GlobalType;
13use crate::core::reader::types::{ExternType, FuncType, ImportSubTypeRelation, MemType, TableType};
14use crate::core::reader::WasmReader;
15use crate::core::utils::ToUsizeExt;
16use crate::execution::interpreter_loop::{self, memory_init, table_init};
17use crate::execution::value::{Ref, Value};
18use crate::execution::{run_const_span, Stack};
19use crate::resumable::{HostResumable, Resumable, RunState, WasmResumable};
20use crate::{RefType, RuntimeError, ValidationInfo};
21use alloc::borrow::ToOwned;
22use alloc::collections::btree_map::BTreeMap;
23use alloc::string::String;
24use alloc::vec;
25use alloc::vec::Vec;
26use instances::{
27    DataInst, ElemInst, FuncInst, GlobalInst, HostFuncInst, MemInst, ModuleInst, TableInst,
28    WasmFuncInst,
29};
30use linear_memory::LinearMemory;
31
32use super::interpreter_loop::{data_drop, elem_drop};
33use super::UnwrapValidatedExt;
34
35pub mod addrs;
36pub(crate) mod instances;
37pub(crate) mod linear_memory;
38
39/// The store represents all global state that can be manipulated by WebAssembly programs. It
40/// consists of the runtime representation of all instances of functions, tables, memories, and
41/// globals, element segments, and data segments that have been allocated during the life time of
42/// the abstract machine.
43/// <https://webassembly.github.io/spec/core/exec/runtime.html#store>
44///
45/// # Safety
46///
47/// All addresses contained in a store must be valid for their associated
48/// address vectors in the same store.
49pub struct Store<'b, T: Config> {
50    pub(crate) functions: AddrVec<FuncAddr, FuncInst<T>>,
51    pub(crate) tables: AddrVec<TableAddr, TableInst>,
52    pub(crate) memories: AddrVec<MemAddr, MemInst>,
53    pub(crate) globals: AddrVec<GlobalAddr, GlobalInst>,
54    pub(crate) elements: AddrVec<ElemAddr, ElemInst>,
55    pub(crate) data: AddrVec<DataAddr, DataInst>,
56
57    // fields outside of the spec but are convenient are below
58    /// An address space of modules instantiated within the context of this [`Store`].
59    ///
60    /// Although the WebAssembly Specification 2.0 does not specify module instances
61    /// to be part of the [`Store`], in reality they can be managed very similar to
62    /// other instance types. Therefore, we extend the [`Store`] by a module address
63    /// space along with a `ModuleAddr` index type.
64    pub(crate) modules: AddrVec<ModuleAddr, ModuleInst<'b>>,
65
66    pub user_data: T,
67}
68
69impl<'b, T: Config> Store<'b, T> {
70    /// Creates a new empty store with some user data
71    ///
72    /// See: WebAssembly Specification 2.0 - 7.1.4 - store_init
73    pub fn new(user_data: T) -> Self {
74        // 1. Return the empty store.
75        // For us the store is empty except for the user data, which we do not have control over.
76        Self {
77            functions: AddrVec::default(),
78            tables: AddrVec::default(),
79            memories: AddrVec::default(),
80            globals: AddrVec::default(),
81            elements: AddrVec::default(),
82            data: AddrVec::default(),
83            modules: AddrVec::default(),
84            user_data,
85        }
86    }
87
88    /// Instantiate a new module instance from a [`ValidationInfo`] in this [`Store`].
89    ///
90    /// Note that if this returns an `Err(_)`, the store might be left in an ill-defined state. This might cause further
91    /// operations to have unexpected results.
92    ///
93    /// See: WebAssembly Specification 2.0 - 7.1.5 - module_instantiate
94    ///
95    /// # Safety
96    ///
97    /// The caller has to guarantee that any address values contained in the
98    /// [`ExternVal`]s came from the current [`Store`] object.
99    pub unsafe fn module_instantiate(
100        &mut self,
101        validation_info: &ValidationInfo<'b>,
102        extern_vals: Vec<ExternVal>,
103        maybe_fuel: Option<u64>,
104    ) -> Result<InstantiationOutcome, RuntimeError> {
105        // instantiation: step 1
106        // The module is guaranteed to be valid, because only validation can
107        // produce `ValidationInfo`s.
108
109        // instantiation: step 3
110        if validation_info.imports.len() != extern_vals.len() {
111            return Err(RuntimeError::ExternValsLenMismatch);
112        }
113
114        // instantiation: step 4
115        let imports_as_extern_types = validation_info.imports.iter().map(|import| {
116            // SAFETY: `import` is part of the same `validation_info` and
117            // therefore it was created as part of the same `validation_info`.
118            unsafe { import.desc.extern_type(validation_info) }
119        });
120        for (extern_val, import_as_extern_type) in extern_vals.iter().zip(imports_as_extern_types) {
121            // instantiation: step 4a
122            // check that extern_val is valid in this Store, which should be guaranteed by the caller through a safety constraint in the future.
123            // TODO document this instantiation step properly
124
125            // instantiation: step 4b
126            let extern_type = extern_val.extern_type(self);
127
128            // instantiation: step 4c
129            if !extern_type.is_subtype_of(&import_as_extern_type) {
130                return Err(RuntimeError::InvalidImportType);
131            }
132        }
133
134        // instantiation: step 5
135        // module_inst_init is unfortunately circularly defined from parts of module_inst that would be defined in step 11, which uses module_inst_init again implicitly.
136        // therefore I am mimicking the reference interpreter code here, I will allocate functions in the store in this step instead of step 11.
137        // https://github.com/WebAssembly/spec/blob/8d6792e3d6709e8d3e90828f9c8468253287f7ed/interpreter/exec/eval.ml#L789
138        let module_inst = ModuleInst {
139            types: validation_info.types.clone(),
140            func_addrs: IdxVec::default(),
141            table_addrs: IdxVec::default(),
142            mem_addrs: IdxVec::default(),
143            // TODO This is weird hack with soundness holes.  Wasm defines a
144            // special `moduleinst_init`. Here, we want to use the `IdxVec` type
145            // safety, but at the same time only the imports can be populated at
146            // this point.
147            global_addrs: IdxVec::new(extern_vals.iter().globals().collect())
148                .expect(
149                    "that the number of imports and therefore also the number of imported globals is <= u32::MAX",
150                ),
151            elem_addrs: IdxVec::default(),
152            data_addrs: IdxVec::default(),
153            exports: BTreeMap::new(),
154            wasm_bytecode: validation_info.wasm,
155            sidetable: validation_info.sidetable.clone(),
156        };
157        let module_addr = self.modules.insert(module_inst);
158
159        let imported_functions = extern_vals.iter().funcs();
160        let local_func_addrs = validation_info
161            .functions
162            .iter_local_definitions()
163            .zip(validation_info.func_blocks_stps.iter())
164            .map(|(ty_idx, (span, stp))| {
165                // SAFETY: The module address is valid for the current store,
166                // because it was just created and the type index is valid for
167                // that same module because it came from that module's
168                // `ValidationInfo`.
169                unsafe { self.alloc_func((*ty_idx, (*span, *stp)), module_addr) }
170            });
171
172        let func_addrs = validation_info
173            .functions
174            .map(imported_functions.collect(), local_func_addrs.collect())
175            .expect(
176                "that the numbers of imported and local functions always \
177                match the respective numbers in the validation info. Step 3 and 4 \
178                check if the number of imported functions is correct and the number \
179                of local functions is a direct one-to-one mapping of \
180                `validation_info.func_blocks_stps`",
181            )
182            .into_inner();
183
184        // SAFETY: The module with this module address was just inserted into
185        // this `AddrVec`
186        let module_inst = unsafe { self.modules.get_mut(module_addr) };
187        module_inst.func_addrs = func_addrs;
188
189        // instantiation: this roughly matches step 6,7,8
190        // validation guarantees these will evaluate without errors.
191        let local_globals_init_vals: Vec<Value> = validation_info
192            .globals
193            .iter_local_definitions()
194            .map(|global| {
195                // SAFETY: All requirements are met:
196                // 1. Validation guarantees that the constant expression for
197                //    this global is valid.
198                // 2. The module with this module address was just inserted into
199                //    this store's `AddrVec`.
200                let const_expr_result = unsafe {
201                    run_const_span(validation_info.wasm, &global.init_expr, module_addr, self)
202                };
203                const_expr_result.transpose().unwrap_validated()
204            })
205            .collect::<Result<Vec<Value>, _>>()?;
206
207        // instantiation: this roughly matches step 9,10 and performs allocation
208        // step 6,12 already
209        let elem_addrs: IdxVec<ElemIdx, ElemAddr> = validation_info.elements.map(|elem| {
210            let refs = match &elem.init {
211                // shortcut of evaluation of "ref.func <func_idx>; end;"
212                // validation guarantees corresponding func_idx's existence
213                ElemItems::RefFuncs(ref_funcs) => {
214                    ref_funcs
215                        .iter()
216                        .map(|func_idx| {
217                            // SAFETY: The module with this module address was
218                            // just inserted into this `AddrVec`
219                            let module = unsafe { self.modules.get(module_addr) };
220                            // SAFETY: Both the function index and the module
221                            // instance's `func_addrs` come from the same
222                            // `ValidationInfo`, i.e. the one passed into this
223                            // function.
224                            let func_addr = unsafe { module.func_addrs.get(*func_idx) };
225
226                            Ref::Func(*func_addr)
227                        })
228                        .collect()
229                }
230                ElemItems::Exprs(_, exprs) => exprs
231                    .iter()
232                    .map(|expr| {
233                        // SAFETY: All requirements are met:
234                        // 1. Validation guarantees that all constant expressions
235                        //    for elements, including this one, are valid.
236                        // 2. The module with this module address was just inserted into
237                        //    this store's `AddrVec`.
238                        let const_expr_result = unsafe {
239                            run_const_span(validation_info.wasm, expr, module_addr, self)
240                        };
241                        const_expr_result
242                            .map(|res| res.unwrap_validated().try_into().unwrap_validated())
243                    })
244                    .collect::<Result<Vec<Ref>, RuntimeError>>()?,
245            };
246
247            // SAFETY: The initial values were retrieved by (1) resolving
248            // function indices or (2) running constant expressions in the
249            // context of the current store. Therefore, their results are also
250            // valid in the current store.
251            let elem = unsafe { self.alloc_elem(elem.ty(), refs) };
252            Ok::<_, RuntimeError>(elem)
253        })?;
254
255        // instantiation: step 11 - module allocation (except function allocation - which was made in step 5)
256        // https://webassembly.github.io/spec/core/exec/modules.html#alloc-module
257
258        // allocation: begin
259
260        // allocation: step 1
261        let module = validation_info;
262
263        // allocation: skip step 2 & 8 as it was done in instantiation step 5
264
265        // allocation: step 3, 9
266        let table_addrs_local: Vec<TableAddr> = module
267            .tables
268            .iter_local_definitions()
269            .map(|table_type| {
270                // SAFETY: The initial table value is null, which is not an
271                // address type and therefore not invalid in the current store.
272                unsafe { self.alloc_table(*table_type, Ref::Null(table_type.et)) }
273            })
274            .collect();
275        // allocation: step 4, 10
276        let mem_addrs_local: Vec<MemAddr> = module
277            .memories
278            .iter_local_definitions()
279            .map(|mem_type| self.alloc_mem(*mem_type))
280            .collect();
281        // allocation: step 5, 11
282        let global_addrs_local: Vec<GlobalAddr> = module
283            .globals
284            .iter_local_definitions()
285            .zip(local_globals_init_vals)
286            .map(|(global, val)| {
287                // SAFETY: The initial values were retrieved by running constant
288                // expressions within the current store context. Therefore,
289                // their results are also valid in the current store.
290                unsafe { self.alloc_global(global.ty, val) }
291            })
292            .collect();
293        // allocation: skip step 6, 12 as it was done in instantiation step 9, 10
294
295        // allocation: step 7, 13
296        let data_addrs = module
297            .data
298            .map::<DataAddr, Infallible>(|data_segment| Ok(self.alloc_data(&data_segment.init)))
299            .expect("infallible error type to never be constructed");
300
301        // allocation: skip step 14 as it was done in instantiation step 5
302
303        // allocation: step 15
304        let table_addrs = validation_info
305            .tables
306            .map(extern_vals.iter().tables().collect(), table_addrs_local)
307            .expect(
308                "that the numbers of imported and local tables always \
309                match the respective numbers in the validation info. Step 3 and 4 \
310                check if the number of imported tables is correct and the number \
311                of local tables is produced by iterating through all table \
312                definitions and performing one-to-one mapping on each one.",
313            )
314            .into_inner();
315
316        // allocation: step 16
317        let mem_addrs = validation_info
318            .memories
319            .map(extern_vals.iter().mems().collect(), mem_addrs_local)
320            .expect(
321                "that the number of imported and local memories always \
322            match the respective numbers in the validation info. Step 3 and 4 \
323            check if the number of imported memories is correct and the number \
324            of local memories is produced by iterating through all memory \
325            definitions and performing one-to-one mapping on each one.",
326            )
327            .into_inner();
328
329        // allocation step 17
330        let global_addrs = validation_info
331            .globals
332            .map(extern_vals.iter().globals().collect(), global_addrs_local)
333            .expect(
334                "that the number of imported and local globals always \
335            match the respective numbers in the validation info. Step 3 and 4 \
336            check if the number of imported globals is correct and the number \
337            of local globals is produced by iterating through all global \
338            definitions and performing one-to-one mapping on each one.",
339            )
340            .into_inner();
341
342        // allocation: step 18,19
343        let export_insts: BTreeMap<String, ExternVal> = module
344            .exports
345            .iter()
346            .map(|export| {
347                // SAFETY: The module with this module address was just inserted
348                // into this `AddrVec`
349                let module_inst = unsafe { self.modules.get(module_addr) };
350                let value = match export.desc {
351                    ExportDesc::Func(func_idx) => {
352                        // SAFETY: Both the function index and the functions
353                        // `IdxVec` come from the same module instance.
354                        // Because all indices are valid in their specific
355                        // module instance, this is sound.
356                        let func_addr = unsafe { module_inst.func_addrs.get(func_idx) };
357                        ExternVal::Func(*func_addr)
358                    }
359                    ExportDesc::Table(table_idx) => {
360                        // SAFETY: Both the table index and the tables `IdxVec`
361                        // come from the same module instance. Because all
362                        // indices are valid in their specific module instance,
363                        // this is sound.
364                        let table_addr = unsafe { table_addrs.get(table_idx) };
365                        ExternVal::Table(*table_addr)
366                    }
367                    ExportDesc::Mem(mem_idx) => {
368                        // SAFETY: Both the memory index and the memories
369                        // `IdxVec` come from the same module instance. Because
370                        // all indices are valid in their specific module
371                        // instance, this is sound.
372                        let mem_addr = unsafe { mem_addrs.get(mem_idx) };
373
374                        ExternVal::Mem(*mem_addr)
375                    }
376                    ExportDesc::Global(global_idx) => {
377                        // SAFETY: Both the global index and the globals
378                        // `ExtendedIdxVec` come from the same module instance.
379                        // Because all indices are valid in their specific
380                        // module instance, this is sound.
381                        let global_addr = unsafe { global_addrs.get(global_idx) };
382
383                        ExternVal::Global(*global_addr)
384                    }
385                };
386                (export.name.to_owned(), value)
387            })
388            .collect();
389
390        // allocation: step 20,21 initialize module (except functions to instantiation step 5, allocation step 14)
391
392        // SAFETY: The module with this module address was
393        // just inserted into this `AddrVec`
394        let module_inst = unsafe { self.modules.get_mut(module_addr) };
395        module_inst.table_addrs = table_addrs;
396        module_inst.mem_addrs = mem_addrs;
397        module_inst.global_addrs = global_addrs;
398        module_inst.elem_addrs = elem_addrs;
399        module_inst.data_addrs = data_addrs;
400        module_inst.exports = export_insts;
401
402        // allocation: end
403
404        // instantiation step 11 end: module_inst properly allocated after this point.
405
406        // instantiation: step 12-15
407        // TODO have to stray away from the spec a bit since our codebase does not lend itself well to freely executing instructions by themselves
408        for (
409            element_idx,
410            ElemType {
411                init: elem_items,
412                mode,
413            },
414        ) in validation_info.elements.iter_enumerated()
415        {
416            match mode {
417                ElemMode::Active(ActiveElem {
418                    table_idx: table_idx_i,
419                    init_expr: einstr_i,
420                }) => {
421                    let n = elem_items.len() as u32;
422                    // equivalent to init.len() in spec
423                    // instantiation step 14:
424                    // TODO (for now, we are doing hopefully what is equivalent to it)
425                    // execute:
426                    //   einstr_i
427                    //   i32.const 0
428                    //   i32.const n
429                    //   table.init table_idx_i i
430                    //   elem.drop i
431
432                    // SAFETY: The module with this module address was just
433                    // inserted into this `AddrVec`. Furthermore, the span comes
434                    // from an element contained in the same validation info the
435                    // Wasm bytecode is from. Therefore, the constant expression
436                    // in that span must be validated already.
437                    let const_expr_result = unsafe {
438                        run_const_span(validation_info.wasm, einstr_i, module_addr, self)?
439                    };
440                    let d: i32 = const_expr_result
441                        .unwrap_validated() // there is a return value
442                        .try_into()
443                        .unwrap_validated(); // return value has correct type
444
445                    let s = 0;
446                    // SAFETY: All requirements are met:
447                    // 1. The module address was just retrieved by inserting a
448                    //    new module instance into the current store. Therefore, it
449                    //    is valid in the current store.
450                    // 2. The table index is valid for the current module
451                    //    instance because it came from the validation info of the
452                    //    same module.
453                    // 3./5. The table and element addresses are valid because
454                    //       they come from a module instance that is part of the
455                    //       current store itself.
456                    // 4. The element index is valid for the current module
457                    //    instance because it came from the validation info of the
458                    //    same module.
459                    unsafe {
460                        table_init(
461                            &self.modules,
462                            &mut self.tables,
463                            &self.elements,
464                            module_addr,
465                            element_idx,
466                            *table_idx_i,
467                            n,
468                            s,
469                            d,
470                        )?
471                    };
472                    // SAFETY: All requirements are met:
473                    // 1. The module address was just retrieved by inserting a
474                    //    new module instance into the current store. Therefore, it
475                    //    is valid in the current store.
476                    // 2. The element index is valid for the current module
477                    //    instance because it came from the validation info of the
478                    //    same module.
479                    // 3. The element address is valid because it comes from a
480                    //    module instance that is part of the current store itself.
481                    unsafe {
482                        elem_drop(&self.modules, &mut self.elements, module_addr, element_idx);
483                    }
484                }
485                ElemMode::Declarative => {
486                    // instantiation step 15:
487                    // TODO (for now, we are doing hopefully what is equivalent to it)
488                    // execute:
489                    //   elem.drop i
490
491                    // SAFETY: The passed element index comes from the
492                    // validation info, that was just used to allocate a new
493                    // module instance with address `module_addr` in
494                    // `self.modules`. Therefore, it must be safe to use for
495                    // accessing the referenced element.
496                    // SAFETY: All requirements are met:
497                    // 1. The module address was just retrieved by inserting a
498                    //    new module instance into the current store. Therefore, it
499                    //    is valid in the current store.
500                    // 2. The element index is valid for the current module
501                    //    instance because it came from the validation info of the
502                    //    same module.
503                    // 3. The element address is valid because it comes from a
504                    //    module instance that is part of the current store itself.
505                    unsafe {
506                        elem_drop(&self.modules, &mut self.elements, module_addr, element_idx);
507                    }
508                }
509                ElemMode::Passive => (),
510            }
511        }
512
513        // instantiation: step 16
514        // TODO have to stray away from the spec a bit since our codebase does not lend itself well to freely executing instructions by themselves
515        for (i, DataSegment { init, mode }) in validation_info.data.iter_enumerated() {
516            match mode {
517                crate::core::reader::types::data::DataMode::Active(DataModeActive {
518                    memory_idx,
519                    offset: dinstr_i,
520                }) => {
521                    let n = init.len() as u32;
522
523                    // TODO (for now, we are doing hopefully what is equivalent to it)
524                    // execute:
525                    //   dinstr_i
526                    //   i32.const 0
527                    //   i32.const n
528                    //   memory.init i
529                    //   data.drop i
530                    // SAFETY: The module with this module address was just
531                    // inserted into this `AddrVec`. Furthermore, the span comes
532                    // from a data segment contained in the same validation info
533                    // the Wasm bytecode is from. Therefore, the constant
534                    // expression in that span must be validated already.
535                    let const_expr_result = unsafe {
536                        run_const_span(validation_info.wasm, dinstr_i, module_addr, self)?
537                    };
538                    let d: u32 = const_expr_result
539                        .unwrap_validated() // there is a return value
540                        .try_into()
541                        .unwrap_validated(); // return value has the correct type
542
543                    let s = 0;
544                    // SAFETY: All requirements are met:
545                    // 1. The module address was just retrieved by inserting a
546                    //    new module instance into the current store. Therefore, it
547                    //    is valid in the current store.
548                    // 2. The memory index is valid for the current module
549                    //    instance because it came from the validation info of the
550                    //    same module.
551                    // 3./5. The memory and data addresses are valid because
552                    //       they come from a module instance that is part of the
553                    //       current store itself.
554                    // 4. The data index is valid for the current module
555                    //    instance because it came from the validation info of the
556                    //    same module.
557                    unsafe {
558                        memory_init(
559                            &self.modules,
560                            &mut self.memories,
561                            &self.data,
562                            module_addr,
563                            i,
564                            *memory_idx,
565                            n,
566                            s,
567                            d,
568                        )
569                    }?;
570
571                    // SAFETY: All requirements are met:
572                    // 1. The module address was just retrieved by inserting a
573                    //    new module instance into the current store. Therefore, it
574                    //    is valid in the current store.
575                    // 2. The data index is valid for the current module
576                    //    instance because it came from the validation info of the
577                    //    same module.
578                    // 3. The data address is valid because it comes from a
579                    //    module instance that is part of the current store itself.
580                    unsafe { data_drop(&self.modules, &mut self.data, module_addr, i) };
581                }
582                crate::core::reader::types::data::DataMode::Passive => (),
583            }
584        }
585
586        // instantiation: step 17
587        let maybe_remaining_fuel = if let Some(func_idx) = validation_info.start {
588            // TODO (for now, we are doing hopefully what is equivalent to it)
589            // execute
590            //   call func_ifx
591
592            // SAFETY: The module with this module address was just inserted
593            // into this `AddrVec`
594            let module = unsafe { self.modules.get(module_addr) };
595            // SAFETY: The function index comes from the passed `ValidationInfo`
596            // and the `IdxVec<FuncIdx, FuncAddr>` comes from the module
597            // instance that originated from that same `ValidationInfo`.
598            // Therefore, this is sound.
599            let func_addr = unsafe { module.func_addrs.get(func_idx) };
600            // SAFETY: The function address just came from the current module
601            // and is therefore valid in the current store. Furthermore, there
602            // are no function arguments and thus also no other address types
603            // can be invalid.
604            let run_state = unsafe { self.invoke(*func_addr, Vec::new(), maybe_fuel) }?;
605
606            let RunState::Finished {
607                maybe_remaining_fuel,
608                ..
609            } = run_state
610            else {
611                return Err(RuntimeError::OutOfFuel);
612            };
613            maybe_remaining_fuel
614        } else {
615            maybe_fuel
616        };
617
618        Ok(InstantiationOutcome {
619            module_addr,
620            maybe_remaining_fuel,
621        })
622    }
623
624    /// Gets an export of a specific module instance by its name
625    ///
626    /// See: WebAssembly Specification 2.0 - 7.1.6 - instance_export
627    ///
628    /// # Safety
629    ///
630    /// The caller has to guarantee that the [`ModuleAddr`] came from the
631    /// current [`Store`] object.
632    pub unsafe fn instance_export(
633        &self,
634        module_addr: ModuleAddr,
635        name: &str,
636    ) -> Result<ExternVal, RuntimeError> {
637        // Fetch the module instance because we store them in the [`Store`]
638        // SAFETY: The caller ensures the module address to be valid in the
639        // current store.
640        let module_inst = unsafe { self.modules.get(module_addr) };
641
642        // 1. Assert: due to validity of the module instance `moduleinst`, all its export names are different
643
644        // 2. If there exists an `exportinst_i` in `moduleinst.exports` such that name `exportinst_i.name` equals `name`, then:
645        //   a. Return the external value `exportinst_i.value`.
646        // 3. Else return `error`.
647        module_inst
648            .exports
649            .get(name)
650            .copied()
651            .ok_or(RuntimeError::UnknownExport)
652    }
653
654    /// Allocates a new function with some host code.
655    ///
656    /// This type of function is also called a host function.
657    ///
658    /// # Panics & Unexpected Behavior
659    /// The specification states that:
660    ///
661    /// > This operation must make sure that the provided host function satisfies the pre-
662    /// > and post-conditions required for a function instance with type `functype`.
663    ///
664    /// Therefore, all "invalid" host functions (e.g. those which return incorrect return values)
665    /// can cause the interpreter to panic or behave unexpectedly.
666    ///
667    /// See: <https://webassembly.github.io/spec/core/exec/modules.html#host-functions>
668    /// See: WebAssembly Specification 2.0 - 7.1.7 - func_alloc
669    ///
670    /// # Safety
671    ///
672    /// The caller has to guarantee that if the [`Value`]s returned from the
673    /// given host function are references, their addresses came either from the
674    /// host function arguments or from the current [`Store`] object.
675    pub unsafe fn func_alloc(
676        &mut self,
677        func_type: FuncType,
678        host_func: fn(&mut T, Vec<Value>) -> Result<Vec<Value>, HaltExecutionError>,
679    ) -> FuncAddr {
680        // 1. Pre-condition: `functype` is valid.
681
682        // 2. Let `funcaddr` be the result of allocating a host function in `store` with
683        //    function type `functype` and host function code `hostfunc`.
684        // 3. Return the new store paired with `funcaddr`.
685        //
686        // Note: Returning the new store is a noop for us because we mutate the store instead.
687        self.functions.insert(FuncInst::HostFunc(HostFuncInst {
688            function_type: func_type,
689            hostcode: host_func,
690        }))
691    }
692
693    /// Gets the type of a function by its addr.
694    ///
695    /// See: WebAssembly Specification 2.0 - 7.1.7 - func_type
696    ///
697    /// # Safety
698    ///
699    /// The caller has to guarantee that the [`FuncAddr`] came from the current
700    /// [`Store`] object.
701    pub unsafe fn func_type(&self, func_addr: FuncAddr) -> FuncType {
702        // 1. Return `S.funcs[a].type`.
703        // SAFETY: The caller ensures this function address to be valid for the
704        // current store.
705        let function = unsafe { self.functions.get(func_addr) };
706        function.ty().clone()
707
708        // 2. Post-condition: the returned function type is valid.
709    }
710
711    /// See: WebAssembly Specification 2.0 - 7.1.7 - func_invoke
712    ///
713    /// # Safety
714    ///
715    /// The caller has to guarantee that the given [`FuncAddr`] and any
716    /// [`FuncAddr`] or [`ExternAddr`](crate::execution::value::ExternAddr)
717    /// values contained in the parameter values came from the current [`Store`]
718    /// object.
719    pub unsafe fn invoke(
720        &mut self,
721        func_addr: FuncAddr,
722        params: Vec<Value>,
723        maybe_fuel: Option<u64>,
724    ) -> Result<RunState<T>, RuntimeError> {
725        // SAFETY: The caller ensures that the function address and any function
726        // addresses or extern addresses contained in the parameter values are
727        // valid in the current store.
728        let resumable = unsafe { self.create_resumable(func_addr, params, maybe_fuel)? };
729
730        // SAFETY: This resumable just came from the current store. Therefore,
731        // it must be valid in the current store.
732        unsafe { self.resume(resumable) }
733    }
734
735    /// Allocates a new table with some table type and an initialization value `ref` and returns its table address.
736    ///
737    /// See: WebAssembly Specification 2.0 - 7.1.8 - table_alloc
738    ///
739    /// # Safety
740    ///
741    /// The caller has to guarantee that any [`FuncAddr`] or [`ExternAddr`](crate::execution::value::ExternAddr)
742    /// values contained in `r#ref` came from the current [`Store`] object.
743    pub unsafe fn table_alloc(
744        &mut self,
745        table_type: TableType,
746        r#ref: Ref,
747    ) -> Result<TableAddr, RuntimeError> {
748        // Check pre-condition: ref has correct type
749        if table_type.et != r#ref.ty() {
750            return Err(RuntimeError::TableTypeMismatch);
751        }
752
753        // 1. Pre-condition: `tabletype` is valid
754
755        // 2. Let `tableaddr` be the result of allocating a table in `store` with table type `tabletype`
756        //    and initialization value `ref`.
757        // SAFETY: The caller ensures that the reference is valid in the current
758        // store.
759        let table_addr = unsafe { self.alloc_table(table_type, r#ref) };
760
761        // 3. Return the new store paired with `tableaddr`.
762        //
763        // Note: Returning the new store is a noop for us because we mutate the store instead.
764        Ok(table_addr)
765    }
766
767    /// Gets the type of some table by its addr.
768    ///
769    /// See: WebAssembly Specification 2.0 - 7.1.8 - table_type
770    ///
771    /// # Safety
772    ///
773    /// The caller has to guarantee that the given [`TableAddr`] came from
774    /// the current [`Store`] object.
775    pub unsafe fn table_type(&self, table_addr: TableAddr) -> TableType {
776        // 1. Return `S.tables[a].type`.
777        // SAFETY: The caller ensures that the given table address is valid in
778        // the current store.
779        let table = unsafe { self.tables.get(table_addr) };
780        table.ty
781
782        // 2. Post-condition: the returned table type is valid.
783    }
784
785    /// Reads a single reference from a table by its table address and an index into the table.
786    ///
787    /// See: WebAssembly Specification 2.0 - 7.1.8 - table_read
788    ///
789    /// # Safety
790    ///
791    /// The caller has to guarantee that the given [`TableAddr`] must come from
792    /// the current [`Store`] object.
793    pub unsafe fn table_read(&self, table_addr: TableAddr, i: u32) -> Result<Ref, RuntimeError> {
794        // Convert `i` to usize for indexing
795        let i = i.into_usize();
796
797        // 1. Let `ti` be the table instance `store.tables[tableaddr]`
798        // SAFETY: The caller ensures that the given table address is valid in
799        // the current store.
800        let ti = unsafe { self.tables.get(table_addr) };
801
802        // 2. If `i` is larger than or equal to the length of `ti.elem`, then return `error`.
803        // 3. Else, return the reference value `ti.elem[i]`.
804        ti.elem
805            .get(i)
806            .copied()
807            .ok_or(RuntimeError::TableAccessOutOfBounds)
808    }
809
810    /// Writes a single reference into a table by its table address and an index into the table.
811    ///
812    /// See: WebAssembly Specification 2.0 - 7.1.8 - table_write
813    ///
814    /// # Safety
815    ///
816    /// The caller has to guarantee that the given [`TableAddr`] and any
817    /// [`FuncAddr`] or [`ExternAddr`](crate::execution::value::ExternAddr)
818    /// values contained in the [`Ref`] must come from the current [`Store`]
819    /// object.
820    pub unsafe fn table_write(
821        &mut self,
822        table_addr: TableAddr,
823        i: u32,
824        r#ref: Ref,
825    ) -> Result<(), RuntimeError> {
826        // Convert `i` to usize for indexing
827        let i = i.into_usize();
828
829        // 1. Let `ti` be the table instance `store.tables[tableaddr]`.
830        // SAFETY: The caller ensures that the given table address is valid in
831        // the current store.
832        let ti = unsafe { self.tables.get_mut(table_addr) };
833
834        // Check pre-condition: ref has correct type
835        if ti.ty.et != r#ref.ty() {
836            return Err(RuntimeError::TableTypeMismatch);
837        }
838
839        // 2. If `i` is larger than or equal to the length of `ti.elem`, then return `error`.
840        // 3. Replace `ti.elem[i]` with the reference value `ref`
841        *ti.elem
842            .get_mut(i)
843            .ok_or(RuntimeError::TableAccessOutOfBounds)? = r#ref;
844
845        // 4. Return the updated store.
846        //
847        // Note: Returning the new store is a noop for us because we mutate the store instead.
848        Ok(())
849    }
850
851    /// Gets the current size of a table by its table address.
852    ///
853    /// See: WebAssembly Specification 2.0 - 7.1.8 - table_size
854    ///
855    /// # Safety
856    ///
857    /// The caller has to guarantee that the given [`TableAddr`] must come from
858    /// the current [`Store`] object.
859    pub unsafe fn table_size(&self, table_addr: TableAddr) -> u32 {
860        // 1. Return the length of `store.tables[tableaddr].elem`.
861        // SAFETY: The caller ensures that the table address is valid in the
862        // current store.
863        let table = unsafe { self.tables.get(table_addr) };
864        let len = table.elem.len();
865
866        // In addition we have to convert the length back to a `u32`
867        u32::try_from(len).expect(
868            "the maximum table length to be u32::MAX because thats what the specification allows for indexing",
869        )
870    }
871
872    /// Grows a table referenced by its table address by `n` elements.
873    ///
874    /// See: WebAssembly Specification 2.0 - 7.1.8 - table_grow
875    ///
876    /// # Safety
877    ///
878    /// The caller has to guarantee that the given [`TableAddr`] and any
879    /// [`FuncAddr`] or [`ExternAddr`](crate::execution::value::ExternAddr)
880    /// values contained in the [`Ref`] must come from the current [`Store`]
881    /// object.
882    pub unsafe fn table_grow(
883        &mut self,
884        table_addr: TableAddr,
885        n: u32,
886        r#ref: Ref,
887    ) -> Result<(), RuntimeError> {
888        // 1. Try growing the table instance `store.tables[tableaddr] by `n` elements with initialization value `ref`:
889        //   a. If it succeeds, return the updated store.
890        //   b. Else, return `error`.
891        //
892        // Note: Returning the new store is a noop for us because we mutate the store instead.
893        // SAFETY: The caller ensures that the given table address is valid in
894        // the current store.
895        let table = unsafe { self.tables.get_mut(table_addr) };
896        table.grow(n, r#ref)
897    }
898
899    /// Allocates a new linear memory and returns its memory address.
900    ///
901    /// See: WebAssembly Specification 2.0 - 7.1.9 - mem_alloc
902    pub fn mem_alloc(&mut self, mem_type: MemType) -> MemAddr {
903        // 1. Pre-condition: `memtype` is valid.
904
905        // 2. Let `memaddr` be the result of allocating a memory in `store` with memory type `memtype`.
906        // 3. Return the new store paired with `memaddr`.
907        //
908        // Note: Returning the new store is a noop for us because we mutate the store instead.
909        self.alloc_mem(mem_type)
910    }
911
912    /// Gets the memory type of some memory by its memory address
913    ///
914    /// See: WebAssemblySpecification 2.0 - 7.1.9 - mem_type
915    ///
916    /// # Safety
917    ///
918    /// The caller has to guarantee that the given [`MemAddr`] came from the
919    /// current [`Store`] object.
920    pub unsafe fn mem_type(&self, mem_addr: MemAddr) -> MemType {
921        // 1. Return `S.mems[a].type`.
922        // SAFETY: The caller ensures that the given memory address is valid in
923        // the current store.
924        let memory = unsafe { self.memories.get(mem_addr) };
925        memory.ty
926
927        // 2. Post-condition: the returned memory type is valid.
928    }
929
930    /// Reads a byte from some memory by its memory address and an index into the memory
931    ///
932    /// See: WebAssemblySpecification 2.0 - 7.1.9 - mem_read
933    ///
934    /// # Safety
935    ///
936    /// The caller has to guarantee that the given [`MemAddr`] came from the
937    /// current [`Store`] object.
938    pub unsafe fn mem_read(&self, mem_addr: MemAddr, i: u32) -> Result<u8, RuntimeError> {
939        // Convert the index type
940        let i = i.into_usize();
941
942        // 1. Let `mi` be the memory instance `store.mems[memaddr]`.
943        // SAFETY: The caller ensures that the given memory address is valid in
944        // the current store.
945        let mi = unsafe { self.memories.get(mem_addr) };
946
947        // 2. If `i` is larger than or equal to the length of `mi.data`, then return `error`.
948        // 3. Else, return the byte `mi.data[i]`.
949        mi.mem.load(i)
950    }
951
952    /// Writes a byte into some memory by its memory address and an index into the memory
953    ///
954    /// See: WebAssemblySpecification 2.0 - 7.1.9 - mem_write
955    ///
956    /// # Safety
957    ///
958    /// The caller has to guarantee that the given [`MemAddr`] came from the
959    /// current [`Store`] object.
960    pub unsafe fn mem_write(
961        &self,
962        mem_addr: MemAddr,
963        i: u32,
964        byte: u8,
965    ) -> Result<(), RuntimeError> {
966        // Convert the index type
967        let i = i.into_usize();
968
969        // 1. Let `mi` be the memory instance `store.mems[memaddr]`.
970        // SAFETY: The caller ensures that the given memory address is valid in
971        // the current store.
972        let mi = unsafe { self.memories.get(mem_addr) };
973
974        mi.mem.store(i, byte)
975    }
976
977    /// Gets the size of some memory by its memory address in pages.
978    ///
979    /// See: WebAssemblySpecification 2.0 - 7.1.9 - mem_size
980    ///
981    /// # Safety
982    ///
983    /// The caller has to guarantee that the given [`MemAddr`] came from the
984    /// current [`Store`] object.
985    pub unsafe fn mem_size(&self, mem_addr: MemAddr) -> u32 {
986        // 1. Return the length of `store.mems[memaddr].data` divided by the page size.
987        // SAFETY: The caller ensures that the given memory address is valid in
988        // the current store.
989        let memory = unsafe { self.memories.get(mem_addr) };
990        let length = memory.size();
991
992        // In addition we have to convert the length back to a `u32`
993        length.try_into().expect(
994            "the maximum memory length to be smaller than u32::MAX because thats what the specification allows for indexing into the memory. Also the memory size is measured in pages, not bytes.")
995    }
996
997    /// Grows some memory by its memory address by `n` pages.
998    ///
999    /// See: WebAssemblySpecification 2.0 - 7.1.9 - mem_grow
1000    ///
1001    /// # Safety
1002    ///
1003    /// The caller has to guarantee that the given [`MemAddr`] came from the
1004    /// current [`Store`] object.
1005    pub unsafe fn mem_grow(&mut self, mem_addr: MemAddr, n: u32) -> Result<(), RuntimeError> {
1006        // 1. Try growing the memory instance `store.mems[memaddr]` by `n` pages:
1007        //   a. If it succeeds, then return the updated store.
1008        //   b. Else, return `error`.
1009        //
1010        // Note: Returning the new store is a noop for us because we mutate the store instead.
1011        // SAFETY: The caller ensures that the given memory address is valid in
1012        // the current store.
1013        let memory = unsafe { self.memories.get_mut(mem_addr) };
1014        memory.grow(n)
1015    }
1016
1017    /// Allocates a new global and returns its global address.
1018    ///
1019    /// See: WebAssemblySpecification 2.0 - 7.1.10 - global_alloc
1020    ///
1021    /// # Safety
1022    ///
1023    /// The caller has to guarantee that any [`FuncAddr`] or
1024    /// [`ExternAddr`](crate::execution::value::ExternAddr) values contained in
1025    /// the [`Value`] came from the current [`Store`] object.
1026    pub unsafe fn global_alloc(
1027        &mut self,
1028        global_type: GlobalType,
1029        val: Value,
1030    ) -> Result<GlobalAddr, RuntimeError> {
1031        // Check pre-condition: val has correct type
1032        if global_type.ty != val.to_ty() {
1033            return Err(RuntimeError::GlobalTypeMismatch);
1034        }
1035
1036        // 1. Pre-condition: `globaltype` is valid.
1037
1038        // 2. Let `globaladdr` be the result of allocating a global with global type `globaltype` and initialization value `val`.
1039        // SAFETY: The caller ensures that any address types contained in the
1040        // initial value are valid in the current store.
1041        let global_addr = unsafe { self.alloc_global(global_type, val) };
1042
1043        // 3. Return the new store paired with `globaladdr`.
1044        //
1045        // Note: Returning the new store is a noop for us because we mutate the store instead.
1046        Ok(global_addr)
1047    }
1048
1049    /// Returns the global type of some global instance by its addr.
1050    ///
1051    /// See: WebAssembly Specification 2.0 - 7.1.10 - global_type
1052    ///
1053    /// # Safety
1054    ///
1055    /// The caller has to guarantee that the given [`GlobalAddr`] came from the
1056    /// current [`Store`] object.
1057    pub unsafe fn global_type(&self, global_addr: GlobalAddr) -> GlobalType {
1058        // 1. Return `S.globals[a].type`.
1059        // SAFETY: The caller ensures that the given global address is valid in
1060        // the current store.
1061        let global = unsafe { self.globals.get(global_addr) };
1062        global.ty
1063        // 2. Post-condition: the returned global type is valid
1064    }
1065
1066    /// Returns the current value of some global instance by its addr.
1067    ///
1068    /// See: WebAssembly Specification 2.0 - 7.1.10 - global_read
1069    ///
1070    /// # Safety
1071    ///
1072    /// The caller has to guarantee that the given [`GlobalAddr`] came from the
1073    /// current [`Store`] object.
1074    pub unsafe fn global_read(&self, global_addr: GlobalAddr) -> Value {
1075        // 1. Let `gi` be the global instance `store.globals[globaladdr].
1076        // SAFETY: The caller ensures that the given global address is valid in
1077        // the current store.
1078        let gi = unsafe { self.globals.get(global_addr) };
1079
1080        // 2. Return the value `gi.value`.
1081        gi.value
1082    }
1083
1084    /// Sets a new value of some global instance by its addr.
1085    ///
1086    /// # Errors
1087    /// - [` RuntimeError::WriteOnImmutableGlobal`]
1088    /// - [` RuntimeError::GlobalTypeMismatch`]
1089    ///
1090    /// See: WebAssembly Specification 2.0 - 7.1.10 - global_write
1091    ///
1092    /// # Safety
1093    ///
1094    /// The caller has to guarantee that the given [`GlobalAddr`] and any
1095    /// [`FuncAddr`] or [`ExternAddr`](crate::execution::value::ExternAddr)
1096    /// values contained in the [`Value`] came from the current [`Store`]
1097    /// object.
1098    pub unsafe fn global_write(
1099        &mut self,
1100        global_addr: GlobalAddr,
1101        val: Value,
1102    ) -> Result<(), RuntimeError> {
1103        // 1. Let `gi` be the global instance `store.globals[globaladdr]`.
1104        // SAFETY: The caller ensures that the given global address is valid in the current module.
1105        let gi = unsafe { self.globals.get_mut(global_addr) };
1106
1107        // 2. Let `mut t` be the structure of the global type `gi.type`.
1108        let r#mut = gi.ty.is_mut;
1109        let t = gi.ty.ty;
1110
1111        // 3. If `mut` is not `var`, then return error.
1112        if !r#mut {
1113            return Err(RuntimeError::WriteOnImmutableGlobal);
1114        }
1115
1116        // Check invariant:
1117        //   It is an invariant of the semantics that the value has a type equal to the value type of `globaltype`.
1118        // See: WebAssembly Specification 2.0 - 4.2.9
1119        if t != val.to_ty() {
1120            return Err(RuntimeError::GlobalTypeMismatch);
1121        }
1122
1123        // 4. Replace `gi.value` with the value `val`.
1124        gi.value = val;
1125
1126        // 5. Return the updated store.
1127        // This is a noop for us, as our store `self` is mutable.
1128
1129        Ok(())
1130    }
1131
1132    /// roughly matches <https://webassembly.github.io/spec/core/exec/modules.html#functions> with the addition of sidetable pointer to the input signature
1133    ///
1134    /// # Safety
1135    ///
1136    /// The caller has to guarantee that
1137    /// - the given [`ModuleAddr`] came from the current [`Store`] object.
1138    /// - the given [`TypeIdx`] is valid in the module for the given [`ModuleAddr`].
1139    // TODO refactor the type of func
1140    unsafe fn alloc_func(
1141        &mut self,
1142        func: (TypeIdx, (Span, usize)),
1143        module_addr: ModuleAddr,
1144    ) -> FuncAddr {
1145        let (ty, (span, stp)) = func;
1146
1147        // TODO rewrite this huge chunk of parsing after generic way to re-parse(?) structs lands
1148        // SAFETY: The caller ensures that the given module address is valid in
1149        // the current store.
1150        let module = unsafe { self.modules.get(module_addr) };
1151        let mut wasm_reader = WasmReader::new(module.wasm_bytecode);
1152        wasm_reader.move_start_to(span).unwrap_validated();
1153
1154        let (locals, bytes_read) = wasm_reader
1155            .measure_num_read_bytes(crate::code::read_declared_locals)
1156            .unwrap_validated();
1157
1158        let code_expr = wasm_reader
1159            .make_span(span.len() - bytes_read)
1160            .unwrap_validated();
1161
1162        // core of the method below
1163
1164        // validation guarantees func_ty_idx exists within module_inst.types
1165        // TODO fix clone
1166        // SAFETY: The caller guarantees that the given type index is valid for
1167        // this module.
1168        let function_type = unsafe { module.types.get(ty).clone() };
1169        let func_inst = FuncInst::WasmFunc(WasmFuncInst {
1170            function_type,
1171            _ty: ty,
1172            locals,
1173            code_expr,
1174            stp,
1175            module_addr,
1176        });
1177        self.functions.insert(func_inst)
1178    }
1179
1180    /// <https://webassembly.github.io/spec/core/exec/modules.html#tables>
1181    ///
1182    /// # Safety
1183    ///
1184    /// The caller has to guarantee that any [`FuncAddr`] or
1185    /// [`ExternAddr`](crate::execution::value::ExternAddr) values contained in
1186    /// the [`Ref`] came from the current [`Store`] object.
1187    unsafe fn alloc_table(&mut self, table_type: TableType, reff: Ref) -> TableAddr {
1188        let table_inst = TableInst {
1189            ty: table_type,
1190            elem: vec![reff; table_type.lim.min.into_usize()],
1191        };
1192
1193        self.tables.insert(table_inst)
1194    }
1195
1196    /// <https://webassembly.github.io/spec/core/exec/modules.html#memories>
1197    fn alloc_mem(&mut self, mem_type: MemType) -> MemAddr {
1198        let mem_inst = MemInst {
1199            ty: mem_type,
1200            mem: LinearMemory::new_with_initial_pages(
1201                mem_type.limits.min.try_into().unwrap_validated(),
1202            ),
1203        };
1204
1205        self.memories.insert(mem_inst)
1206    }
1207
1208    /// <https://webassembly.github.io/spec/core/exec/modules.html#globals>
1209    ///
1210    /// # Safety
1211    ///
1212    /// The caller has to guarantee that any [`FuncAddr`] or
1213    /// [`ExternAddr`](crate::execution::value::ExternAddr) values contained in
1214    /// the [`Value`] came from the current [`Store`] object.
1215    unsafe fn alloc_global(&mut self, global_type: GlobalType, val: Value) -> GlobalAddr {
1216        let global_inst = GlobalInst {
1217            ty: global_type,
1218            value: val,
1219        };
1220
1221        self.globals.insert(global_inst)
1222    }
1223
1224    /// <https://webassembly.github.io/spec/core/exec/modules.html#element-segments>
1225    ///
1226    /// # Safety
1227    ///
1228    /// The caller has to guarantee that any [`FuncAddr`] or
1229    /// [`ExternAddr`](crate::execution::value::ExternAddr) values contained in
1230    /// the [`Ref`]s came from the current [`Store`] object.
1231    unsafe fn alloc_elem(&mut self, ref_type: RefType, refs: Vec<Ref>) -> ElemAddr {
1232        let elem_inst = ElemInst {
1233            _ty: ref_type,
1234            references: refs,
1235        };
1236
1237        self.elements.insert(elem_inst)
1238    }
1239
1240    /// <https://webassembly.github.io/spec/core/exec/modules.html#data-segments>
1241    fn alloc_data(&mut self, bytes: &[u8]) -> DataAddr {
1242        let data_inst = DataInst {
1243            data: Vec::from(bytes),
1244        };
1245
1246        self.data.insert(data_inst)
1247    }
1248
1249    /// Creates a new resumable, which when resumed for the first time invokes the function `function_ref` is associated
1250    /// to, with the arguments `params`. The newly created resumable initially stores `fuel` units of fuel. Returns a
1251    /// `[ResumableRef]` associated to the newly created resumable on success.
1252    ///
1253    /// # Safety
1254    ///
1255    /// The caller has to guarantee that the [`FuncAddr`] and any [`FuncAddr`]
1256    /// or [`ExternAddr`](crate::execution::value::ExternAddr) values contained
1257    /// in the parameter values came from the current [`Store`] object.
1258    pub unsafe fn create_resumable(
1259        &self,
1260        func_addr: FuncAddr,
1261        params: Vec<Value>,
1262        maybe_fuel: Option<u64>,
1263    ) -> Result<Resumable<T>, RuntimeError> {
1264        // SAFETY: The caller ensures that this function address is valid in the
1265        // current store.
1266        let func_inst = unsafe { self.functions.get(func_addr) };
1267
1268        let func_ty = func_inst.ty();
1269
1270        // Verify that the given parameters match the function parameters
1271        let param_types = params.iter().map(|v| v.to_ty()).collect::<Vec<_>>();
1272
1273        if func_ty.params.valtypes != param_types {
1274            trace!(
1275                "Func param types len: {}; Given args len: {}",
1276                func_ty.params.valtypes.len(),
1277                param_types.len()
1278            );
1279            return Err(RuntimeError::FunctionInvocationSignatureMismatch);
1280        }
1281
1282        match func_inst {
1283            FuncInst::WasmFunc(wasm_func_inst) => {
1284                // Prepare a new stack with the locals for the entry function
1285                let stack = Stack::new::<T>(
1286                    params,
1287                    &wasm_func_inst.function_type,
1288                    &wasm_func_inst.locals,
1289                )?;
1290
1291                Ok(Resumable::Wasm(WasmResumable {
1292                    current_func_addr: func_addr,
1293                    stack,
1294                    pc: wasm_func_inst.code_expr.from,
1295                    stp: wasm_func_inst.stp,
1296                    maybe_fuel,
1297                }))
1298            }
1299            FuncInst::HostFunc(host_func_inst) => Ok(Resumable::Host(HostResumable {
1300                func_addr,
1301                params,
1302                hostcode: host_func_inst.hostcode,
1303                maybe_fuel,
1304            })),
1305        }
1306    }
1307
1308    /// Resumes the given [`Resumable`]. Returns a [`RunState`] that may contain
1309    /// a new [`Resumable`] depending on whether execution ran out of fuel or
1310    /// finished normally.
1311    ///
1312    /// # Safety
1313    ///
1314    /// The caller has to guarantee that the [`Resumable`] came from the current
1315    /// [`Store`] object.
1316    pub unsafe fn resume(&mut self, resumable: Resumable<T>) -> Result<RunState<T>, RuntimeError> {
1317        match resumable {
1318            Resumable::Wasm(mut resumable) => {
1319                let result = interpreter_loop::run(&mut resumable, self)?;
1320
1321                match result {
1322                    None => {
1323                        let maybe_remaining_fuel = resumable.maybe_fuel;
1324                        let values = resumable.stack.into_values();
1325                        Ok(RunState::Finished {
1326                            values,
1327                            maybe_remaining_fuel,
1328                        })
1329                    }
1330                    Some(required_fuel) => Ok(RunState::Resumable {
1331                        resumable: Resumable::Wasm(resumable),
1332                        required_fuel,
1333                    }),
1334                }
1335            }
1336            Resumable::Host(resumable) => {
1337                let returns = (resumable.hostcode)(&mut self.user_data, resumable.params);
1338
1339                debug!("Successfully invoked function");
1340
1341                let returns = returns
1342                    .map_err(|HaltExecutionError| RuntimeError::HostFunctionHaltedExecution)?;
1343
1344                // Verify that the return parameters match the host function parameters
1345                // since we have no validation guarantees for host functions
1346
1347                // SAFETY: The caller ensures that the resumable, and thus also
1348                // the function address in it, is valid in the current store.
1349                let function = unsafe { self.functions.get(resumable.func_addr) };
1350
1351                let FuncInst::HostFunc(host_func_inst) = function else {
1352                    unreachable!("expected function to be a host function instance")
1353                };
1354
1355                let return_types = returns.iter().map(|v| v.to_ty()).collect::<Vec<_>>();
1356                if host_func_inst.function_type.returns.valtypes != return_types {
1357                    trace!(
1358                        "Func return types len: {}; returned args len: {}",
1359                        host_func_inst.function_type.returns.valtypes.len(),
1360                        return_types.len()
1361                    );
1362                    return Err(RuntimeError::HostFunctionSignatureMismatch);
1363                }
1364
1365                Ok(RunState::Finished {
1366                    values: returns,
1367                    maybe_remaining_fuel: resumable.maybe_fuel,
1368                })
1369            }
1370        }
1371    }
1372
1373    /// Invokes a function without fuel.
1374    ///
1375    /// This function is simply syntactic sugar for calling [`Store::invoke`]
1376    /// without any fuel and destructuring the resulting [`RunState`].
1377    ///
1378    /// # Safety
1379    ///
1380    /// The caller has to guarantee that the given [`FuncAddr`] and any
1381    /// [`FuncAddr`] or [`ExternAddr`](crate::execution::value::ExternAddr)
1382    /// values contained in the parameter values came from the current [`Store`]
1383    /// object.
1384    pub unsafe fn invoke_without_fuel(
1385        &mut self,
1386        function: FuncAddr,
1387        params: Vec<Value>,
1388    ) -> Result<Vec<Value>, RuntimeError> {
1389        // SAFETY: The caller ensures that the given function address and all
1390        // address types contained in the parameters are valid in the current
1391        // store.
1392        let run_state = unsafe { self.invoke(function, params, None) }?;
1393
1394        match run_state {
1395            RunState::Finished {
1396                values,
1397                maybe_remaining_fuel: _,
1398            } => Ok(values),
1399            RunState::Resumable { .. } => unreachable!("fuel is disabled"),
1400        }
1401    }
1402
1403    /// Allows a given closure to temporarily access the entire memory as a
1404    /// `&mut [u8]`.
1405    ///
1406    /// # Safety
1407    ///
1408    /// The caller has to guarantee that the given [`MemAddr`] came from the
1409    /// current [`Store`] object.
1410    pub unsafe fn mem_access_mut_slice<R>(
1411        &self,
1412        memory: MemAddr,
1413        accessor: impl FnOnce(&mut [u8]) -> R,
1414    ) -> R {
1415        // SAFETY: The caller ensures that the given memory address is valid in
1416        // the current store.
1417        let memory = unsafe { self.memories.get(memory) };
1418        memory.mem.access_mut_slice(accessor)
1419    }
1420
1421    /// Returns all exports of a module instance by its module address.
1422    ///
1423    /// To get a single import by its known name, use
1424    /// [`Store::instance_export`].
1425    ///
1426    /// # Safety
1427    ///
1428    /// The caller has to guarantee that the given [`ModuleAddr`] came from the
1429    /// current [`Store`] object.
1430    pub unsafe fn instance_exports(&self, module_addr: ModuleAddr) -> Vec<(String, ExternVal)> {
1431        // SAFETY: The caller ensures that the given module address is valid in
1432        // the current store.
1433        let module = unsafe { self.modules.get(module_addr) };
1434
1435        module
1436            .exports
1437            .iter()
1438            .map(|(name, externval)| (name.clone(), *externval))
1439            .collect()
1440    }
1441}
1442
1443/// A marker error for host functions to return, in case they want execution to be halted.
1444pub struct HaltExecutionError;
1445
1446///<https://webassembly.github.io/spec/core/exec/runtime.html#external-values>
1447#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1448pub enum ExternVal {
1449    Func(FuncAddr),
1450    Table(TableAddr),
1451    Mem(MemAddr),
1452    Global(GlobalAddr),
1453}
1454
1455impl ExternVal {
1456    /// returns the external type of `self` according to typing relation,
1457    /// taking `store` as context S.
1458    ///
1459    /// # Safety
1460    /// The caller has to guarantee that `self` came from the same [`Store`] which
1461    /// is passed now as a reference.
1462    pub fn extern_type<T: Config>(&self, store: &Store<T>) -> ExternType {
1463        match self {
1464            // TODO: fix ugly clone in function types
1465            ExternVal::Func(func_addr) => {
1466                // SAFETY: The caller ensures that self including the function
1467                // address in self is valid in the given store.
1468                let function = unsafe { store.functions.get(*func_addr) };
1469                ExternType::Func(function.ty().clone())
1470            }
1471            ExternVal::Table(table_addr) => {
1472                // SAFETY: The caller ensures that self including the table
1473                // address in self is valid in the given store.
1474                let table = unsafe { store.tables.get(*table_addr) };
1475                ExternType::Table(table.ty)
1476            }
1477            ExternVal::Mem(mem_addr) => {
1478                // SAFETY: The caller ensures that self including the memory
1479                // address in self is valid in the given store.
1480                let memory = unsafe { store.memories.get(*mem_addr) };
1481                ExternType::Mem(memory.ty)
1482            }
1483            ExternVal::Global(global_addr) => {
1484                // SAFETY: The caller ensures that self including the global
1485                // address in self is valid in the given store.
1486                let global = unsafe { store.globals.get(*global_addr) };
1487                ExternType::Global(global.ty)
1488            }
1489        }
1490    }
1491}
1492
1493impl ExternVal {
1494    pub fn as_func(self) -> Option<FuncAddr> {
1495        match self {
1496            ExternVal::Func(func_addr) => Some(func_addr),
1497            _ => None,
1498        }
1499    }
1500
1501    pub fn as_table(self) -> Option<TableAddr> {
1502        match self {
1503            ExternVal::Table(table_addr) => Some(table_addr),
1504            _ => None,
1505        }
1506    }
1507
1508    pub fn as_mem(self) -> Option<MemAddr> {
1509        match self {
1510            ExternVal::Mem(mem_addr) => Some(mem_addr),
1511            _ => None,
1512        }
1513    }
1514
1515    pub fn as_global(self) -> Option<GlobalAddr> {
1516        match self {
1517            ExternVal::Global(global_addr) => Some(global_addr),
1518            _ => None,
1519        }
1520    }
1521}
1522
1523/// common convention functions defined for lists of ExternVals, ExternTypes, Exports
1524/// <https://webassembly.github.io/spec/core/exec/runtime.html#conventions>
1525/// <https://webassembly.github.io/spec/core/syntax/types.html#id3>
1526/// <https://webassembly.github.io/spec/core/syntax/modules.html?highlight=convention#id1>
1527// TODO implement this trait for ExternType lists Export lists
1528pub trait ExternFilterable {
1529    fn funcs(self) -> impl Iterator<Item = FuncAddr>;
1530    fn tables(self) -> impl Iterator<Item = TableAddr>;
1531    fn mems(self) -> impl Iterator<Item = MemAddr>;
1532    fn globals(self) -> impl Iterator<Item = GlobalAddr>;
1533}
1534
1535impl<'a, I> ExternFilterable for I
1536where
1537    I: Iterator<Item = &'a ExternVal>,
1538{
1539    fn funcs(self) -> impl Iterator<Item = FuncAddr> {
1540        self.filter_map(|extern_val| extern_val.as_func())
1541    }
1542
1543    fn tables(self) -> impl Iterator<Item = TableAddr> {
1544        self.filter_map(|extern_val| extern_val.as_table())
1545    }
1546
1547    fn mems(self) -> impl Iterator<Item = MemAddr> {
1548        self.filter_map(|extern_val| extern_val.as_mem())
1549    }
1550
1551    fn globals(self) -> impl Iterator<Item = GlobalAddr> {
1552        self.filter_map(|extern_val| extern_val.as_global())
1553    }
1554}
1555
1556/// Represents a successful, possibly fueled instantiation of a module.
1557pub struct InstantiationOutcome {
1558    /// contains the store address of the module that has successfully instantiated.
1559    pub module_addr: ModuleAddr,
1560    /// contains `Some(remaining_fuel)` if instantiation was fuel-metered and `None` otherwise.
1561    pub maybe_remaining_fuel: Option<u64>,
1562}