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