wasm/execution/store/
mod.rs

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