1use crate::core::indices::TypeIdx;
2use crate::core::reader::span::Span;
3use crate::core::reader::types::data::{DataModeActive, DataSegment};
4use crate::core::reader::types::element::{ActiveElem, ElemItems, ElemMode, ElemType};
5use crate::core::reader::types::export::{Export, ExportDesc};
6use crate::core::reader::types::global::{Global, GlobalType};
7use crate::core::reader::types::import::Import;
8use crate::core::reader::types::{
9 ExternType, FuncType, ImportSubTypeRelation, MemType, TableType, ValType,
10};
11use crate::core::reader::WasmReader;
12use crate::core::sidetable::Sidetable;
13use crate::execution::interpreter_loop::{self, memory_init, table_init};
14use crate::execution::value::{Ref, Value};
15use crate::execution::{run_const_span, Stack};
16use crate::registry::Registry;
17use crate::resumable::{Dormitory, Resumable, RunState};
18use crate::value::FuncAddr;
19use crate::{Limits, RefType, RuntimeError, TrapError, ValidationInfo};
20use alloc::borrow::ToOwned;
21use alloc::collections::btree_map::BTreeMap;
22use alloc::string::String;
23use alloc::vec;
24use alloc::vec::Vec;
25
26use super::hooks::EmptyHookSet;
27use super::interpreter_loop::{data_drop, elem_drop};
28use super::UnwrapValidatedExt;
29
30use crate::linear_memory::LinearMemory;
31
32pub struct Store<'b, T> {
38 pub functions: Vec<FuncInst<T>>,
39 pub memories: Vec<MemInst>,
40 pub globals: Vec<GlobalInst>,
41 pub data: Vec<DataInst>,
42 pub tables: Vec<TableInst>,
43 pub elements: Vec<ElemInst>,
44 pub modules: Vec<ModuleInst<'b>>,
45
46 pub registry: Registry,
51 pub user_data: T,
52
53 pub dormitory: Dormitory,
55}
56
57impl<'b, T> Store<'b, T> {
58 pub fn new(user_data: T) -> Self {
60 Self {
61 functions: Vec::default(),
62 memories: Vec::default(),
63 globals: Vec::default(),
64 data: Vec::default(),
65 tables: Vec::default(),
66 elements: Vec::default(),
67 modules: Vec::default(),
68 registry: Registry::default(),
69 dormitory: Dormitory::default(),
70 user_data,
71 }
72 }
73
74 pub fn add_module(
80 &mut self,
81 name: &str,
82 validation_info: &ValidationInfo<'b>,
83 maybe_fuel: Option<u32>,
84 ) -> Result<(), RuntimeError> {
85 debug!("adding module with name {:?}", name);
88 let mut extern_vals = Vec::new();
89
90 for Import {
91 module_name: exporting_module_name,
92 name: import_name,
93 desc: import_desc,
94 } in &validation_info.imports
95 {
96 trace!(
97 "trying to import from exporting module instance named {:?}, the entity with name {:?} with desc: {:?}",
98 exporting_module_name,
99 import_name,
100 import_desc
101 );
102 let import_extern_type = import_desc.extern_type(validation_info);
103 let export_extern_val_candidate = *self.registry.lookup(
104 exporting_module_name.clone().into(),
105 import_name.clone().into(),
106 )?;
107 trace!("export candidate found: {:?}", export_extern_val_candidate);
108 if !export_extern_val_candidate
109 .extern_type(self)
110 .is_subtype_of(&import_extern_type)
111 {
112 return Err(RuntimeError::InvalidImportType);
113 }
114 trace!("import and export matches. Adding to externvals");
115 extern_vals.push(export_extern_val_candidate)
116 }
117
118 let mut module_inst = ModuleInst {
123 types: validation_info.types.clone(),
124 func_addrs: extern_vals.iter().funcs().collect(),
125 table_addrs: Vec::new(),
126 mem_addrs: Vec::new(),
127 global_addrs: extern_vals.iter().globals().collect(),
128 elem_addrs: Vec::new(),
129 data_addrs: Vec::new(),
130 exports: BTreeMap::new(),
131 wasm_bytecode: validation_info.wasm,
132 sidetable: validation_info.sidetable.clone(),
133 };
134
135 let func_addrs: Vec<usize> = validation_info
138 .functions
139 .iter()
140 .zip(validation_info.func_blocks_stps.iter())
141 .map(|(ty_idx, (span, stp))| {
142 self.alloc_func((*ty_idx, (*span, *stp)), &module_inst, self.modules.len())
143 })
144 .collect();
145
146 module_inst.func_addrs.extend(func_addrs);
147
148 let maybe_global_init_vals: Result<Vec<Value>, _> = validation_info
151 .globals
152 .iter()
153 .map(|global| {
154 run_const_span(validation_info.wasm, &global.init_expr, &module_inst, self)
155 .transpose()
156 .unwrap_validated()
157 })
158 .collect();
159 let global_init_vals = maybe_global_init_vals?;
160
161 let mut element_init_ref_lists: Vec<Vec<Ref>> =
164 Vec::with_capacity(validation_info.elements.len());
165
166 for elem in &validation_info.elements {
167 let mut new_list = Vec::new();
168 match &elem.init {
169 ElemItems::RefFuncs(ref_funcs) => {
172 for func_idx in ref_funcs {
173 let func_addr = *module_inst
174 .func_addrs
175 .get(*func_idx as usize)
176 .unwrap_validated();
177
178 new_list.push(Ref::Func(FuncAddr(func_addr)));
179 }
180 }
181 ElemItems::Exprs(_, exprs) => {
182 for expr in exprs {
183 new_list.push(
184 run_const_span(validation_info.wasm, expr, &module_inst, self)?
185 .unwrap_validated() .try_into()
187 .unwrap_validated(), )
189 }
190 }
191 }
192 element_init_ref_lists.push(new_list);
193 }
194
195 let module = validation_info;
202
203 let extern_vals = extern_vals;
204 let vals = global_init_vals;
205 let ref_lists = element_init_ref_lists;
206
207 let table_addrs: Vec<usize> = module
211 .tables
212 .iter()
213 .map(|table_type| self.alloc_table(*table_type, Ref::Null(table_type.et)))
214 .collect();
215 let mem_addrs: Vec<usize> = module
216 .memories
217 .iter()
218 .map(|mem_type| self.alloc_mem(*mem_type))
219 .collect();
220 let global_addrs: Vec<usize> = module
221 .globals
222 .iter()
223 .zip(vals)
224 .map(
225 |(
226 Global {
227 ty: global_type, ..
228 },
229 val,
230 )| self.alloc_global(*global_type, val),
231 )
232 .collect();
233 let elem_addrs = module
234 .elements
235 .iter()
236 .zip(ref_lists)
237 .map(|(elem, refs)| self.alloc_elem(elem.ty(), refs))
238 .collect();
239 let data_addrs = module
240 .data
241 .iter()
242 .map(|DataSegment { init: bytes, .. }| self.alloc_data(bytes))
243 .collect();
244
245 let mut table_addrs_mod: Vec<usize> = extern_vals.iter().tables().collect();
249 table_addrs_mod.extend(table_addrs);
250
251 let mut mem_addrs_mod: Vec<usize> = extern_vals.iter().mems().collect();
252 mem_addrs_mod.extend(mem_addrs);
253
254 module_inst.global_addrs.extend(global_addrs);
256
257 let export_insts: BTreeMap<String, ExternVal> = module
259 .exports
260 .iter()
261 .map(|Export { name, desc }| {
262 let value = match desc {
263 ExportDesc::FuncIdx(func_idx) => {
264 ExternVal::Func(module_inst.func_addrs[*func_idx])
265 }
266 ExportDesc::TableIdx(table_idx) => {
267 ExternVal::Table(table_addrs_mod[*table_idx])
268 }
269 ExportDesc::MemIdx(mem_idx) => ExternVal::Mem(mem_addrs_mod[*mem_idx]),
270 ExportDesc::GlobalIdx(global_idx) => {
271 ExternVal::Global(module_inst.global_addrs[*global_idx])
272 }
273 };
274 (String::from(name), value)
275 })
276 .collect();
277
278 module_inst.table_addrs = table_addrs_mod;
280 module_inst.mem_addrs = mem_addrs_mod;
281 module_inst.elem_addrs = elem_addrs;
282 module_inst.data_addrs = data_addrs;
283 module_inst.exports = export_insts;
284
285 self.registry
289 .register_module(name.to_owned().into(), &module_inst)?;
290
291 let current_module_idx = self.modules.len();
294 self.modules.push(module_inst);
295
296 for (
299 i,
300 ElemType {
301 init: elem_items,
302 mode,
303 },
304 ) in validation_info.elements.iter().enumerate()
305 {
306 match mode {
307 ElemMode::Active(ActiveElem {
308 table_idx: table_idx_i,
309 init_expr: einstr_i,
310 }) => {
311 let n = elem_items.len() as i32;
312 let d: i32 = run_const_span(
322 validation_info.wasm,
323 einstr_i,
324 &self.modules[current_module_idx],
325 self,
326 )?
327 .unwrap_validated() .try_into()
329 .unwrap_validated(); let s = 0;
332 table_init(
333 &self.modules,
334 &mut self.tables,
335 &self.elements,
336 current_module_idx,
337 i,
338 *table_idx_i as usize,
339 n,
340 s,
341 d,
342 )?;
343 elem_drop(&self.modules, &mut self.elements, current_module_idx, i)?;
344 }
345 ElemMode::Declarative => {
346 elem_drop(&self.modules, &mut self.elements, current_module_idx, i)?;
351 }
352 ElemMode::Passive => (),
353 }
354 }
355
356 for (i, DataSegment { init, mode }) in validation_info.data.iter().enumerate() {
359 match mode {
360 crate::core::reader::types::data::DataMode::Active(DataModeActive {
361 memory_idx,
362 offset: dinstr_i,
363 }) => {
364 let n = init.len() as i32;
365 if *memory_idx != 0 {
367 return Err(RuntimeError::MoreThanOneMemory);
369 }
370
371 let d: i32 = run_const_span(
379 validation_info.wasm,
380 dinstr_i,
381 &self.modules[current_module_idx],
382 self,
383 )?
384 .unwrap_validated() .try_into()
386 .unwrap_validated(); let s = 0;
389 memory_init(
390 &self.modules,
391 &mut self.memories,
392 &self.data,
393 current_module_idx,
394 i,
395 0,
396 n,
397 s,
398 d,
399 )?;
400 data_drop(&self.modules, &mut self.data, current_module_idx, i)?;
401 }
402 crate::core::reader::types::data::DataMode::Passive => (),
403 }
404 }
405
406 if let Some(func_idx) = validation_info.start {
408 let func_addr = self.modules[current_module_idx].func_addrs[func_idx];
412 self.invoke(func_addr, Vec::new(), maybe_fuel)?;
413 };
414
415 Ok(())
416 }
417
418 fn alloc_func(
422 &mut self,
423 func: (TypeIdx, (Span, usize)),
424 module_inst: &ModuleInst,
425 module_addr: usize,
426 ) -> usize {
427 let (ty, (span, stp)) = func;
428
429 let mut wasm_reader = WasmReader::new(module_inst.wasm_bytecode);
431 wasm_reader.move_start_to(span).unwrap_validated();
432
433 let (locals, bytes_read) = wasm_reader
434 .measure_num_read_bytes(crate::code::read_declared_locals)
435 .unwrap_validated();
436
437 let code_expr = wasm_reader
438 .make_span(span.len() - bytes_read)
439 .unwrap_validated();
440
441 let func_inst = FuncInst::WasmFunc(WasmFuncInst {
446 function_type: module_inst.types[ty].clone(),
447 ty,
448 locals,
449 code_expr,
450 stp,
451 module_addr,
452 });
453
454 let addr = self.functions.len();
455 self.functions.push(func_inst);
456 addr
457 }
458
459 pub(super) fn alloc_host_func(
461 &mut self,
462 func_type: FuncType,
463 host_func: fn(&mut T, Vec<Value>) -> Vec<Value>,
464 ) -> usize {
465 let func_inst = FuncInst::HostFunc(HostFuncInst {
466 function_type: func_type,
467 hostcode: host_func,
468 });
469 let addr = self.functions.len();
470 self.functions.push(func_inst);
471 addr
472 }
473
474 fn alloc_table(&mut self, table_type: TableType, reff: Ref) -> usize {
476 let table_inst = TableInst {
477 ty: table_type,
478 elem: vec![reff; table_type.lim.min as usize],
479 };
480
481 let addr = self.tables.len();
482 self.tables.push(table_inst);
483 addr
484 }
485
486 fn alloc_mem(&mut self, mem_type: MemType) -> usize {
488 let mem_inst = MemInst {
489 ty: mem_type,
490 mem: LinearMemory::new_with_initial_pages(
491 mem_type.limits.min.try_into().unwrap_validated(),
492 ),
493 };
494
495 let addr = self.memories.len();
496 self.memories.push(mem_inst);
497 addr
498 }
499
500 fn alloc_global(&mut self, global_type: GlobalType, val: Value) -> usize {
502 let global_inst = GlobalInst {
503 ty: global_type,
504 value: val,
505 };
506
507 let addr = self.globals.len();
508 self.globals.push(global_inst);
509 addr
510 }
511
512 fn alloc_elem(&mut self, ref_type: RefType, refs: Vec<Ref>) -> usize {
514 let elem_inst = ElemInst {
515 ty: ref_type,
516 references: refs,
517 };
518
519 let addr = self.elements.len();
520 self.elements.push(elem_inst);
521 addr
522 }
523
524 fn alloc_data(&mut self, bytes: &[u8]) -> usize {
526 let data_inst = DataInst {
527 data: Vec::from(bytes),
528 };
529
530 let addr = self.data.len();
531 self.data.push(data_inst);
532 addr
533 }
534
535 pub fn invoke(
536 &mut self,
537 func_addr: usize,
538 params: Vec<Value>,
539 maybe_fuel: Option<u32>,
540 ) -> Result<RunState, RuntimeError> {
541 let func_inst = self
542 .functions
543 .get(func_addr)
544 .ok_or(RuntimeError::FunctionNotFound)?;
545
546 let func_ty = func_inst.ty();
547
548 let param_types = params.iter().map(|v| v.to_ty()).collect::<Vec<_>>();
550
551 if func_ty.params.valtypes != param_types {
552 trace!(
553 "Func param types len: {}; Given args len: {}",
554 func_ty.params.valtypes.len(),
555 param_types.len()
556 );
557 panic!("Invalid parameters for function");
558 }
559
560 match &func_inst {
561 FuncInst::HostFunc(host_func_inst) => {
562 let returns = (host_func_inst.hostcode)(&mut self.user_data, params);
563 debug!("Successfully invoked function");
564
565 let return_types = returns.iter().map(|v| v.to_ty()).collect::<Vec<_>>();
569 if func_ty.returns.valtypes != return_types {
570 trace!(
571 "Func param types len: {}; Given args len: {}",
572 func_ty.params.valtypes.len(),
573 param_types.len()
574 );
575 return Err(RuntimeError::HostFunctionSignatureMismatch);
576 }
577
578 Ok(RunState::Finished(returns))
579 }
580 FuncInst::WasmFunc(wasm_func_inst) => {
581 let mut stack = Stack::new_with_values(params);
583
584 stack.push_call_frame(
585 usize::MAX,
586 &func_ty,
587 &wasm_func_inst.locals,
588 usize::MAX,
589 usize::MAX,
590 )?;
591
592 let mut resumable = Resumable {
593 current_func_addr: func_addr,
594 stack,
595 pc: wasm_func_inst.code_expr.from,
596 stp: wasm_func_inst.stp,
597 };
598
599 let result = interpreter_loop::run(
601 &mut resumable,
603 self,
605 EmptyHookSet,
606 maybe_fuel,
607 );
608
609 match result {
610 Ok(()) => {
611 debug!("Successfully invoked function");
612 Ok(RunState::Finished(resumable.stack.into_values()))
613 }
614 Err(RuntimeError::OutOfFuel) => {
615 debug!("Successfully invoked function, but ran out of fuel");
616 Ok(RunState::Resumable(self.dormitory.insert(resumable)))
617 }
618 Err(err) => Err(err),
619 }
620 }
621 }
622 }
623}
624
625#[derive(Debug)]
626pub enum FuncInst<T> {
628 WasmFunc(WasmFuncInst),
629 HostFunc(HostFuncInst<T>),
630}
631
632#[derive(Debug)]
633pub struct WasmFuncInst {
634 pub function_type: FuncType,
635 pub ty: TypeIdx,
636 pub locals: Vec<ValType>,
637 pub code_expr: Span,
638 pub stp: usize,
640
641 pub module_addr: usize,
644}
645
646#[derive(Debug)]
647pub struct HostFuncInst<T> {
648 pub function_type: FuncType,
649 pub hostcode: fn(&mut T, Vec<Value>) -> Vec<Value>,
650}
651
652impl<T> FuncInst<T> {
653 pub fn ty(&self) -> FuncType {
654 match self {
655 FuncInst::WasmFunc(wasm_func_inst) => wasm_func_inst.function_type.clone(),
656 FuncInst::HostFunc(host_func_inst) => host_func_inst.function_type.clone(),
657 }
658 }
659}
660
661#[derive(Clone, Debug)]
662pub struct ElemInst {
664 pub ty: RefType,
665 pub references: Vec<Ref>,
666}
667
668impl ElemInst {
669 pub fn len(&self) -> usize {
670 self.references.len()
671 }
672 pub fn is_empty(&self) -> bool {
673 self.references.is_empty()
674 }
675}
676
677#[derive(Debug)]
681pub struct TableInst {
682 pub ty: TableType,
683 pub elem: Vec<Ref>,
684}
685
686impl TableInst {
687 pub fn len(&self) -> usize {
688 self.elem.len()
689 }
690
691 pub fn is_empty(&self) -> bool {
692 self.elem.is_empty()
693 }
694
695 pub fn new(ty: TableType) -> Self {
696 Self {
697 ty,
698 elem: vec![Ref::Null(ty.et); ty.lim.min as usize],
699 }
700 }
701
702 pub fn grow(&mut self, n: u32, reff: Ref) -> Result<(), RuntimeError> {
704 let len = n
706 .checked_add(self.elem.len() as u32)
707 .ok_or(TrapError::TableOrElementAccessOutOfBounds)?;
708
709 if self.ty.lim.max.map(|max| len > max).unwrap_or(false) {
713 return Err(TrapError::TableOrElementAccessOutOfBounds.into());
714 }
715 let limits_prime = Limits {
716 min: len,
717 max: self.ty.lim.max,
718 };
719
720 self.elem.extend(vec![reff; n as usize]);
721
722 self.ty.lim = limits_prime;
723 Ok(())
724 }
725}
726
727pub struct MemInst {
728 #[allow(warnings)]
729 pub ty: MemType,
730 pub mem: LinearMemory,
731}
732impl core::fmt::Debug for MemInst {
733 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
734 f.debug_struct("MemInst")
735 .field("ty", &self.ty)
736 .finish_non_exhaustive()
737 }
738}
739
740impl MemInst {
741 pub fn new(ty: MemType) -> Self {
742 Self {
743 ty,
744 mem: LinearMemory::new_with_initial_pages(ty.limits.min.try_into().unwrap()),
745 }
746 }
747
748 pub fn grow(&mut self, n: u32) -> Result<(), RuntimeError> {
750 let len = n + self.mem.pages() as u32;
752 if len > Limits::MAX_MEM_PAGES {
753 return Err(TrapError::MemoryOrDataAccessOutOfBounds.into());
754 }
755
756 if self.ty.limits.max.map(|max| len > max).unwrap_or(false) {
760 return Err(TrapError::MemoryOrDataAccessOutOfBounds.into());
761 }
762 let limits_prime = Limits {
763 min: len,
764 max: self.ty.limits.max,
765 };
766
767 self.mem.grow(n.try_into().unwrap());
768
769 self.ty.limits = limits_prime;
770 Ok(())
771 }
772
773 pub fn size(&self) -> usize {
775 self.mem.len() / (crate::Limits::MEM_PAGE_SIZE as usize)
776 }
777}
778
779#[derive(Debug)]
785pub struct GlobalInst {
786 pub ty: GlobalType,
787 pub value: Value,
789}
790
791pub struct DataInst {
792 pub data: Vec<u8>,
793}
794
795impl core::fmt::Debug for DataInst {
796 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
797 f.debug_struct("DataInst").finish_non_exhaustive()
798 }
799}
800
801#[derive(Debug, Copy, Clone, PartialEq, Eq)]
803pub enum ExternVal {
804 Func(usize),
805 Table(usize),
806 Mem(usize),
807 Global(usize),
808}
809
810impl ExternVal {
811 pub fn extern_type<T>(&self, store: &Store<T>) -> ExternType {
817 match self {
818 ExternVal::Func(func_addr) => ExternType::Func(
820 store
821 .functions
822 .get(*func_addr)
823 .expect("the correct store to be used")
824 .ty(),
825 ),
826 ExternVal::Table(table_addr) => ExternType::Table(
827 store
828 .tables
829 .get(*table_addr)
830 .expect("the correct store to be used")
831 .ty,
832 ),
833 ExternVal::Mem(mem_addr) => ExternType::Mem(
834 store
835 .memories
836 .get(*mem_addr)
837 .expect("the correct store to be used")
838 .ty,
839 ),
840 ExternVal::Global(global_addr) => ExternType::Global(
841 store
842 .globals
843 .get(*global_addr)
844 .expect("the correct store to be used")
845 .ty,
846 ),
847 }
848 }
849}
850
851pub trait ExternFilterable<T> {
857 fn funcs(self) -> impl Iterator<Item = T>;
858 fn tables(self) -> impl Iterator<Item = T>;
859 fn mems(self) -> impl Iterator<Item = T>;
860 fn globals(self) -> impl Iterator<Item = T>;
861}
862
863impl<'a, I> ExternFilterable<usize> for I
864where
865 I: Iterator<Item = &'a ExternVal>,
866{
867 fn funcs(self) -> impl Iterator<Item = usize> {
868 self.filter_map(|extern_val| {
869 if let ExternVal::Func(func_addr) = extern_val {
870 Some(*func_addr)
871 } else {
872 None
873 }
874 })
875 }
876
877 fn tables(self) -> impl Iterator<Item = usize> {
878 self.filter_map(|extern_val| {
879 if let ExternVal::Table(table_addr) = extern_val {
880 Some(*table_addr)
881 } else {
882 None
883 }
884 })
885 }
886
887 fn mems(self) -> impl Iterator<Item = usize> {
888 self.filter_map(|extern_val| {
889 if let ExternVal::Mem(mem_addr) = extern_val {
890 Some(*mem_addr)
891 } else {
892 None
893 }
894 })
895 }
896
897 fn globals(self) -> impl Iterator<Item = usize> {
898 self.filter_map(|extern_val| {
899 if let ExternVal::Global(global_addr) = extern_val {
900 Some(*global_addr)
901 } else {
902 None
903 }
904 })
905 }
906}
907
908#[derive(Debug)]
910pub struct ModuleInst<'b> {
911 pub types: Vec<FuncType>,
912 pub func_addrs: Vec<usize>,
913 pub table_addrs: Vec<usize>,
914 pub mem_addrs: Vec<usize>,
915 pub global_addrs: Vec<usize>,
916 pub elem_addrs: Vec<usize>,
917 pub data_addrs: Vec<usize>,
918 pub exports: BTreeMap<String, ExternVal>,
923
924 pub wasm_bytecode: &'b [u8],
926
927 pub sidetable: Sidetable,
929}