wasm/execution/store/
mod.rs

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