wasm/execution/store/
mod.rs

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