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