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, InterpreterLoopOutcome};
17use crate::execution::value::{Ref, Value};
18use crate::execution::{run_const_span, Stack};
19use crate::resumable::{HostCall, 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>,
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
601            // SAFETY: The function address just came from the current module
602            // and is therefore valid in the current store. Furthermore, there
603            // are no function arguments and thus also no other address types
604            // can be invalid.
605            let create_resumable_outcome =
606                unsafe { self.create_resumable(*func_addr, Vec::new(), maybe_fuel) }?;
607
608            let Resumable::Wasm(resumable) = create_resumable_outcome else {
609                todo!("calling host functions from the start function");
610            };
611
612            // SAFETY: The resumable just came from the current store.
613            // Therefore, it is always valid in the current store.
614            match unsafe { self.resume_wasm(resumable) }? {
615                RunState::Finished {
616                    maybe_remaining_fuel,
617                    ..
618                } => maybe_remaining_fuel,
619                RunState::Resumable { .. } => return Err(RuntimeError::OutOfFuel),
620                RunState::HostCalled { .. } => {
621                    return Err(RuntimeError::UnsupportedHostCallDuringInstantiation);
622                }
623            }
624        } else {
625            maybe_fuel
626        };
627
628        Ok(InstantiationOutcome {
629            module_addr,
630            maybe_remaining_fuel,
631        })
632    }
633
634    /// Gets an export of a specific module instance by its name
635    ///
636    /// See: WebAssembly Specification 2.0 - 7.1.6 - instance_export
637    ///
638    /// # Safety
639    ///
640    /// The caller has to guarantee that the [`ModuleAddr`] came from the
641    /// current [`Store`] object.
642    pub unsafe fn instance_export(
643        &self,
644        module_addr: ModuleAddr,
645        name: &str,
646    ) -> Result<ExternVal, RuntimeError> {
647        // Fetch the module instance because we store them in the [`Store`]
648        // SAFETY: The caller ensures the module address to be valid in the
649        // current store.
650        let module_inst = unsafe { self.modules.get(module_addr) };
651
652        // 1. Assert: due to validity of the module instance `moduleinst`, all its export names are different
653
654        // 2. If there exists an `exportinst_i` in `moduleinst.exports` such that name `exportinst_i.name` equals `name`, then:
655        //   a. Return the external value `exportinst_i.value`.
656        // 3. Else return `error`.
657        module_inst
658            .exports
659            .get(name)
660            .copied()
661            .ok_or(RuntimeError::UnknownExport)
662    }
663
664    /// Allocates a new function with some host code.
665    ///
666    /// This type of function is also called a host function.
667    ///
668    /// # Panics & Unexpected Behavior
669    /// The specification states that:
670    ///
671    /// > This operation must make sure that the provided host function satisfies the pre-
672    /// > and post-conditions required for a function instance with type `functype`.
673    ///
674    /// Therefore, all "invalid" host functions (e.g. those which return incorrect return values)
675    /// can cause the interpreter to panic or behave unexpectedly.
676    ///
677    /// See: <https://webassembly.github.io/spec/core/exec/modules.html#host-functions>
678    /// See: WebAssembly Specification 2.0 - 7.1.7 - func_alloc
679    pub fn func_alloc(&mut self, func_type: FuncType, hostcode: Hostcode) -> 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,
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, 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        // SAFETY: The resumable just came from the current store. Therefore, it
730        // must be valid in the current store.
731        unsafe { self.resume(resumable) }
732    }
733
734    /// Allocates a new table with some table type and an initialization value `ref` and returns its table address.
735    ///
736    /// See: WebAssembly Specification 2.0 - 7.1.8 - table_alloc
737    ///
738    /// # Safety
739    ///
740    /// The caller has to guarantee that any [`FuncAddr`] or [`ExternAddr`](crate::execution::value::ExternAddr)
741    /// values contained in `r#ref` came from the current [`Store`] object.
742    pub unsafe fn table_alloc(
743        &mut self,
744        table_type: TableType,
745        r#ref: Ref,
746    ) -> Result<TableAddr, RuntimeError> {
747        // Check pre-condition: ref has correct type
748        if table_type.et != r#ref.ty() {
749            return Err(RuntimeError::TableTypeMismatch);
750        }
751
752        // 1. Pre-condition: `tabletype` is valid
753
754        // 2. Let `tableaddr` be the result of allocating a table in `store` with table type `tabletype`
755        //    and initialization value `ref`.
756        // SAFETY: The caller ensures that the reference is valid in the current
757        // store.
758        let table_addr = unsafe { self.alloc_table(table_type, r#ref) };
759
760        // 3. Return the new store paired with `tableaddr`.
761        //
762        // Note: Returning the new store is a noop for us because we mutate the store instead.
763        Ok(table_addr)
764    }
765
766    /// Gets the type of some table by its addr.
767    ///
768    /// See: WebAssembly Specification 2.0 - 7.1.8 - table_type
769    ///
770    /// # Safety
771    ///
772    /// The caller has to guarantee that the given [`TableAddr`] came from
773    /// the current [`Store`] object.
774    pub unsafe fn table_type(&self, table_addr: TableAddr) -> TableType {
775        // 1. Return `S.tables[a].type`.
776        // SAFETY: The caller ensures that the given table address is valid in
777        // the current store.
778        let table = unsafe { self.tables.get(table_addr) };
779        table.ty
780
781        // 2. Post-condition: the returned table type is valid.
782    }
783
784    /// Reads a single reference from a table by its table address and an index into the table.
785    ///
786    /// See: WebAssembly Specification 2.0 - 7.1.8 - table_read
787    ///
788    /// # Safety
789    ///
790    /// The caller has to guarantee that the given [`TableAddr`] must come from
791    /// the current [`Store`] object.
792    pub unsafe fn table_read(&self, table_addr: TableAddr, i: u32) -> Result<Ref, RuntimeError> {
793        // Convert `i` to usize for indexing
794        let i = i.into_usize();
795
796        // 1. Let `ti` be the table instance `store.tables[tableaddr]`
797        // SAFETY: The caller ensures that the given table address is valid in
798        // the current store.
799        let ti = unsafe { self.tables.get(table_addr) };
800
801        // 2. If `i` is larger than or equal to the length of `ti.elem`, then return `error`.
802        // 3. Else, return the reference value `ti.elem[i]`.
803        ti.elem
804            .get(i)
805            .copied()
806            .ok_or(RuntimeError::TableAccessOutOfBounds)
807    }
808
809    /// Writes a single reference into a table by its table address and an index into the table.
810    ///
811    /// See: WebAssembly Specification 2.0 - 7.1.8 - table_write
812    ///
813    /// # Safety
814    ///
815    /// The caller has to guarantee that the given [`TableAddr`] and any
816    /// [`FuncAddr`] or [`ExternAddr`](crate::execution::value::ExternAddr)
817    /// values contained in the [`Ref`] must come from the current [`Store`]
818    /// object.
819    pub unsafe fn table_write(
820        &mut self,
821        table_addr: TableAddr,
822        i: u32,
823        r#ref: Ref,
824    ) -> Result<(), RuntimeError> {
825        // Convert `i` to usize for indexing
826        let i = i.into_usize();
827
828        // 1. Let `ti` be the table instance `store.tables[tableaddr]`.
829        // SAFETY: The caller ensures that the given table address is valid in
830        // the current store.
831        let ti = unsafe { self.tables.get_mut(table_addr) };
832
833        // Check pre-condition: ref has correct type
834        if ti.ty.et != r#ref.ty() {
835            return Err(RuntimeError::TableTypeMismatch);
836        }
837
838        // 2. If `i` is larger than or equal to the length of `ti.elem`, then return `error`.
839        // 3. Replace `ti.elem[i]` with the reference value `ref`
840        *ti.elem
841            .get_mut(i)
842            .ok_or(RuntimeError::TableAccessOutOfBounds)? = r#ref;
843
844        // 4. Return the updated store.
845        //
846        // Note: Returning the new store is a noop for us because we mutate the store instead.
847        Ok(())
848    }
849
850    /// Gets the current size of a table by its table address.
851    ///
852    /// See: WebAssembly Specification 2.0 - 7.1.8 - table_size
853    ///
854    /// # Safety
855    ///
856    /// The caller has to guarantee that the given [`TableAddr`] must come from
857    /// the current [`Store`] object.
858    pub unsafe fn table_size(&self, table_addr: TableAddr) -> u32 {
859        // 1. Return the length of `store.tables[tableaddr].elem`.
860        // SAFETY: The caller ensures that the table address is valid in the
861        // current store.
862        let table = unsafe { self.tables.get(table_addr) };
863        let len = table.elem.len();
864
865        // In addition we have to convert the length back to a `u32`
866        u32::try_from(len).expect(
867            "the maximum table length to be u32::MAX because thats what the specification allows for indexing",
868        )
869    }
870
871    /// Grows a table referenced by its table address by `n` elements.
872    ///
873    /// See: WebAssembly Specification 2.0 - 7.1.8 - table_grow
874    ///
875    /// # Safety
876    ///
877    /// The caller has to guarantee that the given [`TableAddr`] and any
878    /// [`FuncAddr`] or [`ExternAddr`](crate::execution::value::ExternAddr)
879    /// values contained in the [`Ref`] must come from the current [`Store`]
880    /// object.
881    pub unsafe fn table_grow(
882        &mut self,
883        table_addr: TableAddr,
884        n: u32,
885        r#ref: Ref,
886    ) -> Result<(), RuntimeError> {
887        // 1. Try growing the table instance `store.tables[tableaddr] by `n` elements with initialization value `ref`:
888        //   a. If it succeeds, return the updated store.
889        //   b. Else, return `error`.
890        //
891        // Note: Returning the new store is a noop for us because we mutate the store instead.
892        // SAFETY: The caller ensures that the given table address is valid in
893        // the current store.
894        let table = unsafe { self.tables.get_mut(table_addr) };
895        table.grow(n, r#ref)
896    }
897
898    /// Allocates a new linear memory and returns its memory address.
899    ///
900    /// See: WebAssembly Specification 2.0 - 7.1.9 - mem_alloc
901    pub fn mem_alloc(&mut self, mem_type: MemType) -> MemAddr {
902        // 1. Pre-condition: `memtype` is valid.
903
904        // 2. Let `memaddr` be the result of allocating a memory in `store` with memory type `memtype`.
905        // 3. Return the new store paired with `memaddr`.
906        //
907        // Note: Returning the new store is a noop for us because we mutate the store instead.
908        self.alloc_mem(mem_type)
909    }
910
911    /// Gets the memory type of some memory by its memory address
912    ///
913    /// See: WebAssemblySpecification 2.0 - 7.1.9 - mem_type
914    ///
915    /// # Safety
916    ///
917    /// The caller has to guarantee that the given [`MemAddr`] came from the
918    /// current [`Store`] object.
919    pub unsafe fn mem_type(&self, mem_addr: MemAddr) -> MemType {
920        // 1. Return `S.mems[a].type`.
921        // SAFETY: The caller ensures that the given memory address is valid in
922        // the current store.
923        let memory = unsafe { self.memories.get(mem_addr) };
924        memory.ty
925
926        // 2. Post-condition: the returned memory type is valid.
927    }
928
929    /// Reads a byte from some memory by its memory address and an index into the memory
930    ///
931    /// See: WebAssemblySpecification 2.0 - 7.1.9 - mem_read
932    ///
933    /// # Safety
934    ///
935    /// The caller has to guarantee that the given [`MemAddr`] came from the
936    /// current [`Store`] object.
937    pub unsafe fn mem_read(&self, mem_addr: MemAddr, i: u32) -> Result<u8, RuntimeError> {
938        // Convert the index type
939        let i = i.into_usize();
940
941        // 1. Let `mi` be the memory instance `store.mems[memaddr]`.
942        // SAFETY: The caller ensures that the given memory address is valid in
943        // the current store.
944        let mi = unsafe { self.memories.get(mem_addr) };
945
946        // 2. If `i` is larger than or equal to the length of `mi.data`, then return `error`.
947        // 3. Else, return the byte `mi.data[i]`.
948        mi.mem.load(i)
949    }
950
951    /// Writes a byte into some memory by its memory address and an index into the memory
952    ///
953    /// See: WebAssemblySpecification 2.0 - 7.1.9 - mem_write
954    ///
955    /// # Safety
956    ///
957    /// The caller has to guarantee that the given [`MemAddr`] came from the
958    /// current [`Store`] object.
959    pub unsafe fn mem_write(
960        &self,
961        mem_addr: MemAddr,
962        i: u32,
963        byte: u8,
964    ) -> Result<(), RuntimeError> {
965        // Convert the index type
966        let i = i.into_usize();
967
968        // 1. Let `mi` be the memory instance `store.mems[memaddr]`.
969        // SAFETY: The caller ensures that the given memory address is valid in
970        // the current store.
971        let mi = unsafe { self.memories.get(mem_addr) };
972
973        mi.mem.store(i, byte)
974    }
975
976    /// Gets the size of some memory by its memory address in pages.
977    ///
978    /// See: WebAssemblySpecification 2.0 - 7.1.9 - mem_size
979    ///
980    /// # Safety
981    ///
982    /// The caller has to guarantee that the given [`MemAddr`] came from the
983    /// current [`Store`] object.
984    pub unsafe fn mem_size(&self, mem_addr: MemAddr) -> u32 {
985        // 1. Return the length of `store.mems[memaddr].data` divided by the page size.
986        // SAFETY: The caller ensures that the given memory address is valid in
987        // the current store.
988        let memory = unsafe { self.memories.get(mem_addr) };
989        let length = memory.size();
990
991        // In addition we have to convert the length back to a `u32`
992        length.try_into().expect(
993            "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.")
994    }
995
996    /// Grows some memory by its memory address by `n` pages.
997    ///
998    /// See: WebAssemblySpecification 2.0 - 7.1.9 - mem_grow
999    ///
1000    /// # Safety
1001    ///
1002    /// The caller has to guarantee that the given [`MemAddr`] came from the
1003    /// current [`Store`] object.
1004    pub unsafe fn mem_grow(&mut self, mem_addr: MemAddr, n: u32) -> Result<(), RuntimeError> {
1005        // 1. Try growing the memory instance `store.mems[memaddr]` by `n` pages:
1006        //   a. If it succeeds, then return the updated store.
1007        //   b. Else, return `error`.
1008        //
1009        // Note: Returning the new store is a noop for us because we mutate the store instead.
1010        // SAFETY: The caller ensures that the given memory address is valid in
1011        // the current store.
1012        let memory = unsafe { self.memories.get_mut(mem_addr) };
1013        memory.grow(n)
1014    }
1015
1016    /// Allocates a new global and returns its global address.
1017    ///
1018    /// See: WebAssemblySpecification 2.0 - 7.1.10 - global_alloc
1019    ///
1020    /// # Safety
1021    ///
1022    /// The caller has to guarantee that any [`FuncAddr`] or
1023    /// [`ExternAddr`](crate::execution::value::ExternAddr) values contained in
1024    /// the [`Value`] came from the current [`Store`] object.
1025    pub unsafe fn global_alloc(
1026        &mut self,
1027        global_type: GlobalType,
1028        val: Value,
1029    ) -> Result<GlobalAddr, RuntimeError> {
1030        // Check pre-condition: val has correct type
1031        if global_type.ty != val.to_ty() {
1032            return Err(RuntimeError::GlobalTypeMismatch);
1033        }
1034
1035        // 1. Pre-condition: `globaltype` is valid.
1036
1037        // 2. Let `globaladdr` be the result of allocating a global with global type `globaltype` and initialization value `val`.
1038        // SAFETY: The caller ensures that any address types contained in the
1039        // initial value are valid in the current store.
1040        let global_addr = unsafe { self.alloc_global(global_type, val) };
1041
1042        // 3. Return the new store paired with `globaladdr`.
1043        //
1044        // Note: Returning the new store is a noop for us because we mutate the store instead.
1045        Ok(global_addr)
1046    }
1047
1048    /// Returns the global type of some global instance by its addr.
1049    ///
1050    /// See: WebAssembly Specification 2.0 - 7.1.10 - global_type
1051    ///
1052    /// # Safety
1053    ///
1054    /// The caller has to guarantee that the given [`GlobalAddr`] came from the
1055    /// current [`Store`] object.
1056    pub unsafe fn global_type(&self, global_addr: GlobalAddr) -> GlobalType {
1057        // 1. Return `S.globals[a].type`.
1058        // SAFETY: The caller ensures that the given global address is valid in
1059        // the current store.
1060        let global = unsafe { self.globals.get(global_addr) };
1061        global.ty
1062        // 2. Post-condition: the returned global type is valid
1063    }
1064
1065    /// Returns the current value of some global instance by its addr.
1066    ///
1067    /// See: WebAssembly Specification 2.0 - 7.1.10 - global_read
1068    ///
1069    /// # Safety
1070    ///
1071    /// The caller has to guarantee that the given [`GlobalAddr`] came from the
1072    /// current [`Store`] object.
1073    pub unsafe fn global_read(&self, global_addr: GlobalAddr) -> Value {
1074        // 1. Let `gi` be the global instance `store.globals[globaladdr].
1075        // SAFETY: The caller ensures that the given global address is valid in
1076        // the current store.
1077        let gi = unsafe { self.globals.get(global_addr) };
1078
1079        // 2. Return the value `gi.value`.
1080        gi.value
1081    }
1082
1083    /// Sets a new value of some global instance by its addr.
1084    ///
1085    /// # Errors
1086    /// - [` RuntimeError::WriteOnImmutableGlobal`]
1087    /// - [` RuntimeError::GlobalTypeMismatch`]
1088    ///
1089    /// See: WebAssembly Specification 2.0 - 7.1.10 - global_write
1090    ///
1091    /// # Safety
1092    ///
1093    /// The caller has to guarantee that the given [`GlobalAddr`] and any
1094    /// [`FuncAddr`] or [`ExternAddr`](crate::execution::value::ExternAddr)
1095    /// values contained in the [`Value`] came from the current [`Store`]
1096    /// object.
1097    pub unsafe fn global_write(
1098        &mut self,
1099        global_addr: GlobalAddr,
1100        val: Value,
1101    ) -> Result<(), RuntimeError> {
1102        // 1. Let `gi` be the global instance `store.globals[globaladdr]`.
1103        // SAFETY: The caller ensures that the given global address is valid in the current module.
1104        let gi = unsafe { self.globals.get_mut(global_addr) };
1105
1106        // 2. Let `mut t` be the structure of the global type `gi.type`.
1107        let r#mut = gi.ty.is_mut;
1108        let t = gi.ty.ty;
1109
1110        // 3. If `mut` is not `var`, then return error.
1111        if !r#mut {
1112            return Err(RuntimeError::WriteOnImmutableGlobal);
1113        }
1114
1115        // Check invariant:
1116        //   It is an invariant of the semantics that the value has a type equal to the value type of `globaltype`.
1117        // See: WebAssembly Specification 2.0 - 4.2.9
1118        if t != val.to_ty() {
1119            return Err(RuntimeError::GlobalTypeMismatch);
1120        }
1121
1122        // 4. Replace `gi.value` with the value `val`.
1123        gi.value = val;
1124
1125        // 5. Return the updated store.
1126        // This is a noop for us, as our store `self` is mutable.
1127
1128        Ok(())
1129    }
1130
1131    /// roughly matches <https://webassembly.github.io/spec/core/exec/modules.html#functions> with the addition of sidetable pointer to the input signature
1132    ///
1133    /// # Safety
1134    ///
1135    /// The caller has to guarantee that
1136    /// - the given [`ModuleAddr`] came from the current [`Store`] object.
1137    /// - the given [`TypeIdx`] is valid in the module for the given [`ModuleAddr`].
1138    // TODO refactor the type of func
1139    unsafe fn alloc_func(
1140        &mut self,
1141        func: (TypeIdx, (Span, usize)),
1142        module_addr: ModuleAddr,
1143    ) -> FuncAddr {
1144        let (ty, (span, stp)) = func;
1145
1146        // TODO rewrite this huge chunk of parsing after generic way to re-parse(?) structs lands
1147        // SAFETY: The caller ensures that the given module address is valid in
1148        // the current store.
1149        let module = unsafe { self.modules.get(module_addr) };
1150        let mut wasm_reader = WasmReader::new(module.wasm_bytecode);
1151        wasm_reader.move_start_to(span).unwrap_validated();
1152
1153        let (locals, bytes_read) = wasm_reader
1154            .measure_num_read_bytes(crate::code::read_declared_locals)
1155            .unwrap_validated();
1156
1157        let code_expr = wasm_reader
1158            .make_span(span.len() - bytes_read)
1159            .unwrap_validated();
1160
1161        // core of the method below
1162
1163        // validation guarantees func_ty_idx exists within module_inst.types
1164        // TODO fix clone
1165        // SAFETY: The caller guarantees that the given type index is valid for
1166        // this module.
1167        let function_type = unsafe { module.types.get(ty).clone() };
1168        let func_inst = FuncInst::WasmFunc(WasmFuncInst {
1169            function_type,
1170            _ty: ty,
1171            locals,
1172            code_expr,
1173            stp,
1174            module_addr,
1175        });
1176        self.functions.insert(func_inst)
1177    }
1178
1179    /// <https://webassembly.github.io/spec/core/exec/modules.html#tables>
1180    ///
1181    /// # Safety
1182    ///
1183    /// The caller has to guarantee that any [`FuncAddr`] or
1184    /// [`ExternAddr`](crate::execution::value::ExternAddr) values contained in
1185    /// the [`Ref`] came from the current [`Store`] object.
1186    unsafe fn alloc_table(&mut self, table_type: TableType, reff: Ref) -> TableAddr {
1187        let table_inst = TableInst {
1188            ty: table_type,
1189            elem: vec![reff; table_type.lim.min.into_usize()],
1190        };
1191
1192        self.tables.insert(table_inst)
1193    }
1194
1195    /// <https://webassembly.github.io/spec/core/exec/modules.html#memories>
1196    fn alloc_mem(&mut self, mem_type: MemType) -> MemAddr {
1197        let mem_inst = MemInst {
1198            ty: mem_type,
1199            mem: LinearMemory::new_with_initial_pages(
1200                mem_type.limits.min.try_into().unwrap_validated(),
1201            ),
1202        };
1203
1204        self.memories.insert(mem_inst)
1205    }
1206
1207    /// <https://webassembly.github.io/spec/core/exec/modules.html#globals>
1208    ///
1209    /// # Safety
1210    ///
1211    /// The caller has to guarantee that any [`FuncAddr`] or
1212    /// [`ExternAddr`](crate::execution::value::ExternAddr) values contained in
1213    /// the [`Value`] came from the current [`Store`] object.
1214    unsafe fn alloc_global(&mut self, global_type: GlobalType, val: Value) -> GlobalAddr {
1215        let global_inst = GlobalInst {
1216            ty: global_type,
1217            value: val,
1218        };
1219
1220        self.globals.insert(global_inst)
1221    }
1222
1223    /// <https://webassembly.github.io/spec/core/exec/modules.html#element-segments>
1224    ///
1225    /// # Safety
1226    ///
1227    /// The caller has to guarantee that any [`FuncAddr`] or
1228    /// [`ExternAddr`](crate::execution::value::ExternAddr) values contained in
1229    /// the [`Ref`]s came from the current [`Store`] object.
1230    unsafe fn alloc_elem(&mut self, ref_type: RefType, refs: Vec<Ref>) -> ElemAddr {
1231        let elem_inst = ElemInst {
1232            _ty: ref_type,
1233            references: refs,
1234        };
1235
1236        self.elements.insert(elem_inst)
1237    }
1238
1239    /// <https://webassembly.github.io/spec/core/exec/modules.html#data-segments>
1240    fn alloc_data(&mut self, bytes: &[u8]) -> DataAddr {
1241        let data_inst = DataInst {
1242            data: Vec::from(bytes),
1243        };
1244
1245        self.data.insert(data_inst)
1246    }
1247
1248    /// Creates a new resumable, which when resumed for the first time invokes the function `function_ref` is associated
1249    /// to, with the arguments `params`. The newly created resumable initially stores `fuel` units of fuel. Returns a
1250    /// `[ResumableRef]` associated to the newly created resumable on success.
1251    ///
1252    /// # Safety
1253    ///
1254    /// The caller has to guarantee that the [`FuncAddr`] and any [`FuncAddr`]
1255    /// or [`ExternAddr`](crate::execution::value::ExternAddr) values contained
1256    /// in the parameter values came from the current [`Store`] object.
1257    pub unsafe fn create_resumable(
1258        &self,
1259        func_addr: FuncAddr,
1260        params: Vec<Value>,
1261        maybe_fuel: Option<u64>,
1262    ) -> Result<Resumable, RuntimeError> {
1263        // SAFETY: The caller ensures that this function address is valid in the
1264        // current store.
1265        let func_inst = unsafe { self.functions.get(func_addr) };
1266
1267        let func_ty = func_inst.ty();
1268
1269        // Verify that the given parameter types match the function parameter types
1270        if func_ty.params.valtypes.len() != params.len() {
1271            return Err(RuntimeError::FunctionInvocationSignatureMismatch);
1272        }
1273
1274        let type_mismatch = func_ty
1275            .params
1276            .valtypes
1277            .iter()
1278            .zip(&params)
1279            .any(|(func_val_ty, param_val)| func_val_ty != &param_val.to_ty());
1280
1281        if type_mismatch {
1282            return Err(RuntimeError::FunctionInvocationSignatureMismatch);
1283        };
1284
1285        let resumable = match func_inst {
1286            FuncInst::WasmFunc(wasm_func_inst) => {
1287                // Prepare a new stack with the locals for the entry function
1288                let stack = Stack::new::<T>(
1289                    params,
1290                    &wasm_func_inst.function_type,
1291                    &wasm_func_inst.locals,
1292                )?;
1293
1294                Resumable::Wasm(WasmResumable {
1295                    current_func_addr: func_addr,
1296                    stack,
1297                    pc: wasm_func_inst.code_expr.from,
1298                    stp: wasm_func_inst.stp,
1299                    maybe_fuel,
1300                })
1301            }
1302            FuncInst::HostFunc(host_func_inst) => Resumable::Host {
1303                host_call: HostCall {
1304                    params,
1305                    hostcode: host_func_inst.hostcode,
1306                },
1307                host_resumable: HostResumable {
1308                    host_func_addr: func_addr,
1309                    inner_resumable: None,
1310                    maybe_fuel: Some(maybe_fuel),
1311                },
1312            },
1313        };
1314
1315        Ok(resumable)
1316    }
1317
1318    /// Resumes execution of a [`Resumable`], regardless of its inner representation.
1319    ///
1320    /// Note: The [`Resumable`] may also be deconstructed by the user and its
1321    /// contents used with [`Store::resume_wasm`] or
1322    /// [`Store::finish_host_call`].
1323    ///
1324    /// # Safety
1325    ///
1326    /// The caller has to guarantee that the [`Resumable`] came from the current
1327    /// [`Store`] object.
1328    pub unsafe fn resume(&mut self, resumable: Resumable) -> Result<RunState, RuntimeError> {
1329        match resumable {
1330            // SAFETY: The caller ensures that this `WasmResumable` came from
1331            // the current store.
1332            Resumable::Wasm(wasm_resumable) => unsafe { self.resume_wasm(wasm_resumable) },
1333            Resumable::Host {
1334                host_call,
1335                host_resumable,
1336            } => Ok(RunState::HostCalled {
1337                host_call,
1338                resumable: host_resumable,
1339            }),
1340        }
1341    }
1342
1343    /// Resumes the given [`WasmResumable`]. Returns a [`RunState`] that may contain
1344    /// a new [`Resumable`] depending on whether execution ran out of fuel or
1345    /// finished normally.
1346    ///
1347    /// # Safety
1348    ///
1349    /// The caller has to guarantee that the [`Resumable`] came from the current
1350    /// [`Store`] object.
1351    pub unsafe fn resume_wasm(
1352        &mut self,
1353        mut resumable: WasmResumable,
1354    ) -> Result<RunState, RuntimeError> {
1355        let result = interpreter_loop::run(&mut resumable, self)?;
1356
1357        let run_state = match result {
1358            InterpreterLoopOutcome::ExecutionReturned => RunState::Finished {
1359                values: resumable.stack.into_values(),
1360                maybe_remaining_fuel: resumable.maybe_fuel,
1361            },
1362            InterpreterLoopOutcome::OutOfFuel { required_fuel } => RunState::Resumable {
1363                resumable,
1364                required_fuel: Some(required_fuel),
1365            },
1366            InterpreterLoopOutcome::HostCalled {
1367                func_addr,
1368                params,
1369                hostcode,
1370            } => RunState::HostCalled {
1371                host_call: HostCall { params, hostcode },
1372                resumable: HostResumable {
1373                    host_func_addr: func_addr,
1374                    inner_resumable: Some(resumable),
1375                    maybe_fuel: None,
1376                },
1377            },
1378        };
1379
1380        Ok(run_state)
1381    }
1382
1383    /// To be executed after executing a [`HostCall`].
1384    ///
1385    /// # Safety
1386    ///
1387    /// The caller has to guarantee that the [`HostResumable`] and all
1388    /// addresses in the return values came from the current [`Store`] object.
1389    pub unsafe fn finish_host_call(
1390        &mut self,
1391        host_resumable: HostResumable,
1392        host_call_return_values: Vec<Value>,
1393    ) -> Result<RunState, RuntimeError> {
1394        // Verify that the return parameters match the host function parameters
1395        // since we have no validation guarantees for host functions
1396
1397        // SAFETY: The caller ensures that the `HostResumable`, and thus also
1398        // the function address in it, is valid in the current store.
1399        let function = unsafe { self.functions.get(host_resumable.host_func_addr) };
1400
1401        let FuncInst::HostFunc(host_func_inst) = function else {
1402            unreachable!("expected function to be a host function instance")
1403        };
1404
1405        let return_types = host_call_return_values
1406            .iter()
1407            .map(|v| v.to_ty())
1408            .collect::<Vec<_>>();
1409
1410        if host_func_inst.function_type.returns.valtypes != return_types {
1411            return Err(RuntimeError::HostFunctionSignatureMismatch);
1412        }
1413
1414        if let Some(mut wasm_resumable) = host_resumable.inner_resumable {
1415            for return_value in host_call_return_values {
1416                wasm_resumable.stack.push_value::<T>(return_value)?;
1417            }
1418
1419            Ok(RunState::Resumable {
1420                resumable: wasm_resumable,
1421                required_fuel: None,
1422            })
1423        } else {
1424            Ok(RunState::Finished {
1425                values: host_call_return_values,
1426                maybe_remaining_fuel: host_resumable
1427                    .maybe_fuel
1428                    .expect("this to be set if the inner WasmResumable is None"),
1429            })
1430        }
1431    }
1432
1433    /// Invokes a function without support for fuel or host functions.
1434    ///
1435    /// This function wraps [`Store::invoke`].
1436    ///
1437    /// # Safety
1438    ///
1439    /// The caller has to guarantee that the given [`FuncAddr`] and any
1440    /// [`FuncAddr`] or [`ExternAddr`](crate::execution::value::ExternAddr)
1441    /// values contained in the parameter values came from the current [`Store`]
1442    /// object.
1443    pub unsafe fn invoke_simple(
1444        &mut self,
1445        function: FuncAddr,
1446        params: Vec<Value>,
1447    ) -> Result<Vec<Value>, RuntimeError> {
1448        // SAFETY: The caller ensures that the given function address and all
1449        // address types contained in the parameters are valid in the current
1450        // store.
1451        let run_state = unsafe { self.invoke(function, params, None) }?;
1452
1453        match run_state {
1454            RunState::Finished {
1455                values,
1456                maybe_remaining_fuel: _,
1457            } => Ok(values),
1458            RunState::Resumable { .. } => unreachable!("fuel is disabled"),
1459            RunState::HostCalled { .. } => Err(RuntimeError::UnexpectedHostCall),
1460        }
1461    }
1462
1463    /// Allows a given closure to temporarily access the entire memory as a
1464    /// `&mut [u8]`.
1465    ///
1466    /// # Safety
1467    ///
1468    /// The caller has to guarantee that the given [`MemAddr`] came from the
1469    /// current [`Store`] object.
1470    pub unsafe fn mem_access_mut_slice<R>(
1471        &self,
1472        memory: MemAddr,
1473        accessor: impl FnOnce(&mut [u8]) -> R,
1474    ) -> R {
1475        // SAFETY: The caller ensures that the given memory address is valid in
1476        // the current store.
1477        let memory = unsafe { self.memories.get(memory) };
1478        memory.mem.access_mut_slice(accessor)
1479    }
1480
1481    /// Returns all exports of a module instance by its module address.
1482    ///
1483    /// To get a single import by its known name, use
1484    /// [`Store::instance_export`].
1485    ///
1486    /// # Safety
1487    ///
1488    /// The caller has to guarantee that the given [`ModuleAddr`] came from the
1489    /// current [`Store`] object.
1490    pub unsafe fn instance_exports(&self, module_addr: ModuleAddr) -> Vec<(String, ExternVal)> {
1491        // SAFETY: The caller ensures that the given module address is valid in
1492        // the current store.
1493        let module = unsafe { self.modules.get(module_addr) };
1494
1495        module
1496            .exports
1497            .iter()
1498            .map(|(name, externval)| (name.clone(), *externval))
1499            .collect()
1500    }
1501}
1502
1503///<https://webassembly.github.io/spec/core/exec/runtime.html#external-values>
1504#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1505pub enum ExternVal {
1506    Func(FuncAddr),
1507    Table(TableAddr),
1508    Mem(MemAddr),
1509    Global(GlobalAddr),
1510}
1511
1512impl ExternVal {
1513    /// returns the external type of `self` according to typing relation,
1514    /// taking `store` as context S.
1515    ///
1516    /// # Safety
1517    /// The caller has to guarantee that `self` came from the same [`Store`] which
1518    /// is passed now as a reference.
1519    pub fn extern_type<T: Config>(&self, store: &Store<T>) -> ExternType {
1520        match self {
1521            // TODO: fix ugly clone in function types
1522            ExternVal::Func(func_addr) => {
1523                // SAFETY: The caller ensures that self including the function
1524                // address in self is valid in the given store.
1525                let function = unsafe { store.functions.get(*func_addr) };
1526                ExternType::Func(function.ty().clone())
1527            }
1528            ExternVal::Table(table_addr) => {
1529                // SAFETY: The caller ensures that self including the table
1530                // address in self is valid in the given store.
1531                let table = unsafe { store.tables.get(*table_addr) };
1532                ExternType::Table(table.ty)
1533            }
1534            ExternVal::Mem(mem_addr) => {
1535                // SAFETY: The caller ensures that self including the memory
1536                // address in self is valid in the given store.
1537                let memory = unsafe { store.memories.get(*mem_addr) };
1538                ExternType::Mem(memory.ty)
1539            }
1540            ExternVal::Global(global_addr) => {
1541                // SAFETY: The caller ensures that self including the global
1542                // address in self is valid in the given store.
1543                let global = unsafe { store.globals.get(*global_addr) };
1544                ExternType::Global(global.ty)
1545            }
1546        }
1547    }
1548}
1549
1550impl ExternVal {
1551    pub fn as_func(self) -> Option<FuncAddr> {
1552        match self {
1553            ExternVal::Func(func_addr) => Some(func_addr),
1554            _ => None,
1555        }
1556    }
1557
1558    pub fn as_table(self) -> Option<TableAddr> {
1559        match self {
1560            ExternVal::Table(table_addr) => Some(table_addr),
1561            _ => None,
1562        }
1563    }
1564
1565    pub fn as_mem(self) -> Option<MemAddr> {
1566        match self {
1567            ExternVal::Mem(mem_addr) => Some(mem_addr),
1568            _ => None,
1569        }
1570    }
1571
1572    pub fn as_global(self) -> Option<GlobalAddr> {
1573        match self {
1574            ExternVal::Global(global_addr) => Some(global_addr),
1575            _ => None,
1576        }
1577    }
1578}
1579
1580/// common convention functions defined for lists of ExternVals, ExternTypes, Exports
1581/// <https://webassembly.github.io/spec/core/exec/runtime.html#conventions>
1582/// <https://webassembly.github.io/spec/core/syntax/types.html#id3>
1583/// <https://webassembly.github.io/spec/core/syntax/modules.html?highlight=convention#id1>
1584// TODO implement this trait for ExternType lists Export lists
1585pub trait ExternFilterable {
1586    fn funcs(self) -> impl Iterator<Item = FuncAddr>;
1587    fn tables(self) -> impl Iterator<Item = TableAddr>;
1588    fn mems(self) -> impl Iterator<Item = MemAddr>;
1589    fn globals(self) -> impl Iterator<Item = GlobalAddr>;
1590}
1591
1592impl<'a, I> ExternFilterable for I
1593where
1594    I: Iterator<Item = &'a ExternVal>,
1595{
1596    fn funcs(self) -> impl Iterator<Item = FuncAddr> {
1597        self.filter_map(|extern_val| extern_val.as_func())
1598    }
1599
1600    fn tables(self) -> impl Iterator<Item = TableAddr> {
1601        self.filter_map(|extern_val| extern_val.as_table())
1602    }
1603
1604    fn mems(self) -> impl Iterator<Item = MemAddr> {
1605        self.filter_map(|extern_val| extern_val.as_mem())
1606    }
1607
1608    fn globals(self) -> impl Iterator<Item = GlobalAddr> {
1609        self.filter_map(|extern_val| extern_val.as_global())
1610    }
1611}
1612
1613/// Represents a successful, possibly fueled instantiation of a module.
1614pub struct InstantiationOutcome {
1615    /// contains the store address of the module that has successfully instantiated.
1616    pub module_addr: ModuleAddr,
1617    /// contains `Some(remaining_fuel)` if instantiation was fuel-metered and `None` otherwise.
1618    pub maybe_remaining_fuel: Option<u64>,
1619}
1620
1621pub type Hostcode = usize;