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