1use crate::core::error::Result as CustomResult;
2use crate::core::indices::TypeIdx;
3use crate::core::reader::span::Span;
4use crate::core::reader::types::data::{DataModeActive, DataSegment};
5use crate::core::reader::types::element::{ActiveElem, ElemItems, ElemMode, ElemType};
6use crate::core::reader::types::export::{Export, ExportDesc};
7use crate::core::reader::types::global::{Global, GlobalType};
8use crate::core::reader::types::import::Import;
9use crate::core::reader::types::{
10 ExternType, FuncType, ImportSubTypeRelation, MemType, TableType, ValType,
11};
12use crate::core::reader::WasmReader;
13use crate::core::sidetable::Sidetable;
14use crate::execution::interpreter_loop::{self, memory_init, table_init};
15use crate::execution::value::{Ref, Value};
16use crate::execution::{run_const_span, Stack};
17use crate::registry::Registry;
18use crate::value::FuncAddr;
19use crate::{Error, Limits, RefType, RuntimeError, 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::value::ExternAddr;
29use super::UnwrapValidatedExt;
30
31use crate::linear_memory::LinearMemory;
32
33#[derive(Debug)]
39pub struct Store<'b, T> {
40 pub functions: Vec<FuncInst<T>>,
41 pub memories: Vec<MemInst>,
42 pub globals: Vec<GlobalInst>,
43 pub data: Vec<DataInst>,
44 pub tables: Vec<TableInst>,
45 pub elements: Vec<ElemInst>,
46 pub modules: Vec<ModuleInst<'b>>,
47
48 pub registry: Registry,
53 pub user_data: T,
54}
55
56impl<'b, T> Store<'b, T> {
57 pub fn new(user_data: T) -> Self {
59 Self {
60 functions: Vec::default(),
61 memories: Vec::default(),
62 globals: Vec::default(),
63 data: Vec::default(),
64 tables: Vec::default(),
65 elements: Vec::default(),
66 modules: Vec::default(),
67 registry: Registry::default(),
68 user_data,
69 }
70 }
71
72 pub fn add_module(
78 &mut self,
79 name: &str,
80 validation_info: &ValidationInfo<'b>,
81 ) -> CustomResult<()> {
82 debug!("adding module with name {:?}", name);
85 let mut extern_vals = Vec::new();
86
87 for Import {
88 module_name: exporting_module_name,
89 name: import_name,
90 desc: import_desc,
91 } in &validation_info.imports
92 {
93 trace!(
94 "trying to import from exporting module instance named {:?}, the entity with name {:?} with desc: {:?}",
95 exporting_module_name,
96 import_name,
97 import_desc
98 );
99 let import_extern_type = import_desc.extern_type(validation_info)?;
100 let export_extern_val_candidate = *self.registry.lookup(
101 exporting_module_name.clone().into(),
102 import_name.clone().into(),
103 )?;
104 trace!("export candidate found: {:?}", export_extern_val_candidate);
105 if !export_extern_val_candidate
106 .extern_type(self)?
107 .is_subtype_of(&import_extern_type)
108 {
109 return Err(Error::InvalidImportType);
110 }
111 trace!("import and export matches. Adding to externvals");
112 extern_vals.push(export_extern_val_candidate)
113 }
114
115 let mut module_inst = ModuleInst {
120 types: validation_info.types.clone(),
121 func_addrs: extern_vals.iter().funcs().collect(),
122 table_addrs: Vec::new(),
123 mem_addrs: Vec::new(),
124 global_addrs: extern_vals.iter().globals().collect(),
125 elem_addrs: Vec::new(),
126 data_addrs: Vec::new(),
127 exports: BTreeMap::new(),
128 wasm_bytecode: validation_info.wasm,
129 sidetable: validation_info.sidetable.clone(),
130 };
131
132 let func_addrs: Vec<usize> = validation_info
135 .functions
136 .iter()
137 .zip(validation_info.func_blocks_stps.iter())
138 .map(|(ty_idx, (span, stp))| {
139 self.alloc_func((*ty_idx, (*span, *stp)), &module_inst, self.modules.len())
140 })
141 .collect();
142
143 module_inst.func_addrs.extend(func_addrs);
144
145 let maybe_global_init_vals: Result<Vec<Value>, _> = validation_info
148 .globals
149 .iter()
150 .map(|global| {
151 run_const_span(validation_info.wasm, &global.init_expr, &module_inst, self)
152 .transpose()
153 .unwrap_validated()
154 })
155 .collect();
156 let global_init_vals = maybe_global_init_vals?;
157
158 let mut element_init_ref_lists: Vec<Vec<Ref>> =
161 Vec::with_capacity(validation_info.elements.len());
162
163 for elem in &validation_info.elements {
164 let mut new_list = Vec::new();
165 match &elem.init {
166 ElemItems::RefFuncs(ref_funcs) => {
169 for func_idx in ref_funcs {
170 new_list.push(Ref::Func(FuncAddr {
171 addr: Some(module_inst.func_addrs[*func_idx as usize]),
172 }))
173 }
174 }
175 ElemItems::Exprs(_, exprs) => {
176 for expr in exprs {
177 new_list.push(
178 run_const_span(validation_info.wasm, expr, &module_inst, self)?
179 .unwrap_validated()
180 .into(),
181 )
182 }
183 }
184 }
185 element_init_ref_lists.push(new_list);
186 }
187
188 let module = validation_info;
195
196 let extern_vals = extern_vals;
197 let vals = global_init_vals;
198 let ref_lists = element_init_ref_lists;
199
200 let table_addrs: Vec<usize> = module
204 .tables
205 .iter()
206 .map(|table_type| {
207 let null_ref = match table_type.et {
208 RefType::FuncRef => Ref::Func(FuncAddr { addr: None }),
209 RefType::ExternRef => Ref::Extern(ExternAddr { addr: None }),
210 };
211 self.alloc_table(*table_type, null_ref)
212 })
213 .collect();
214 let mem_addrs: Vec<usize> = module
215 .memories
216 .iter()
217 .map(|mem_type| self.alloc_mem(*mem_type))
218 .collect();
219 let global_addrs: Vec<usize> = module
220 .globals
221 .iter()
222 .zip(vals)
223 .map(
224 |(
225 Global {
226 ty: global_type, ..
227 },
228 val,
229 )| self.alloc_global(*global_type, val),
230 )
231 .collect();
232 let elem_addrs = module
233 .elements
234 .iter()
235 .zip(ref_lists)
236 .map(|(elem, refs)| self.alloc_elem(elem.ty(), refs))
237 .collect();
238 let data_addrs = module
239 .data
240 .iter()
241 .map(|DataSegment { init: bytes, .. }| self.alloc_data(bytes))
242 .collect();
243
244 let mut table_addrs_mod: Vec<usize> = extern_vals.iter().tables().collect();
248 table_addrs_mod.extend(table_addrs);
249
250 let mut mem_addrs_mod: Vec<usize> = extern_vals.iter().mems().collect();
251 mem_addrs_mod.extend(mem_addrs);
252
253 module_inst.global_addrs.extend(global_addrs);
255
256 let export_insts: BTreeMap<String, ExternVal> = module
258 .exports
259 .iter()
260 .map(|Export { name, desc }| {
261 let value = match desc {
262 ExportDesc::FuncIdx(func_idx) => {
263 ExternVal::Func(module_inst.func_addrs[*func_idx])
264 }
265 ExportDesc::TableIdx(table_idx) => {
266 ExternVal::Table(table_addrs_mod[*table_idx])
267 }
268 ExportDesc::MemIdx(mem_idx) => ExternVal::Mem(mem_addrs_mod[*mem_idx]),
269 ExportDesc::GlobalIdx(global_idx) => {
270 ExternVal::Global(module_inst.global_addrs[*global_idx])
271 }
272 };
273 (String::from(name), value)
274 })
275 .collect();
276
277 module_inst.table_addrs = table_addrs_mod;
279 module_inst.mem_addrs = mem_addrs_mod;
280 module_inst.elem_addrs = elem_addrs;
281 module_inst.data_addrs = data_addrs;
282 module_inst.exports = export_insts;
283
284 self.registry
288 .register_module(name.to_owned().into(), &module_inst)?;
289
290 let current_module_idx = self.modules.len();
293 self.modules.push(module_inst);
294
295 for (
298 i,
299 ElemType {
300 init: elem_items,
301 mode,
302 },
303 ) in validation_info.elements.iter().enumerate()
304 {
305 match mode {
306 ElemMode::Active(ActiveElem {
307 table_idx: table_idx_i,
308 init_expr: einstr_i,
309 }) => {
310 let n = elem_items.len() as i32;
311 let d: i32 = run_const_span(
321 validation_info.wasm,
322 einstr_i,
323 &self.modules[current_module_idx],
324 self,
325 )?
326 .unwrap_validated()
327 .into();
328 let s = 0;
329 table_init(
330 &self.modules,
331 &mut self.tables,
332 &self.elements,
333 current_module_idx,
334 i,
335 *table_idx_i as usize,
336 n,
337 s,
338 d,
339 )
340 .map_err(Error::RuntimeError)?;
341 elem_drop(&self.modules, &mut self.elements, current_module_idx, i)
342 .map_err(Error::RuntimeError)?;
343 }
344 ElemMode::Declarative => {
345 elem_drop(&self.modules, &mut self.elements, current_module_idx, i)
350 .map_err(Error::RuntimeError)?;
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(Error::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()
385 .into();
386 let s = 0;
387 memory_init(
388 &self.modules,
389 &mut self.memories,
390 &self.data,
391 current_module_idx,
392 i,
393 0,
394 n,
395 s,
396 d,
397 )
398 .map_err(Error::RuntimeError)?;
399 data_drop(&self.modules, &mut self.data, current_module_idx, i)
400 .map_err(Error::RuntimeError)?;
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())
413 .map_err(Error::RuntimeError)?;
414 };
415
416 Ok(())
417 }
418
419 fn alloc_func(
423 &mut self,
424 func: (TypeIdx, (Span, usize)),
425 module_inst: &ModuleInst,
426 module_addr: usize,
427 ) -> usize {
428 let (ty, (span, stp)) = func;
429
430 let mut wasm_reader = WasmReader::new(module_inst.wasm_bytecode);
432 wasm_reader.move_start_to(span).unwrap_validated();
433
434 let (locals, bytes_read) = wasm_reader
435 .measure_num_read_bytes(crate::code::read_declared_locals)
436 .unwrap_validated();
437
438 let code_expr = wasm_reader
439 .make_span(span.len() - bytes_read)
440 .unwrap_validated();
441
442 let func_inst = FuncInst::WasmFunc(WasmFuncInst {
447 function_type: module_inst.types[ty].clone(),
448 ty,
449 locals,
450 code_expr,
451 stp,
452 module_addr,
453 });
454
455 let addr = self.functions.len();
456 self.functions.push(func_inst);
457 addr
458 }
459
460 pub(super) fn alloc_host_func(
462 &mut self,
463 func_type: FuncType,
464 host_func: fn(&mut T, Vec<Value>) -> Vec<Value>,
465 ) -> usize {
466 let func_inst = FuncInst::HostFunc(HostFuncInst {
467 function_type: func_type,
468 hostcode: host_func,
469 });
470 let addr = self.functions.len();
471 self.functions.push(func_inst);
472 addr
473 }
474
475 fn alloc_table(&mut self, table_type: TableType, reff: Ref) -> usize {
477 let table_inst = TableInst {
478 ty: table_type,
479 elem: vec![reff; table_type.lim.min as usize],
480 };
481
482 let addr = self.tables.len();
483 self.tables.push(table_inst);
484 addr
485 }
486
487 fn alloc_mem(&mut self, mem_type: MemType) -> usize {
489 let mem_inst = MemInst {
490 ty: mem_type,
491 mem: LinearMemory::new_with_initial_pages(
492 mem_type.limits.min.try_into().unwrap_validated(),
493 ),
494 };
495
496 let addr = self.memories.len();
497 self.memories.push(mem_inst);
498 addr
499 }
500
501 fn alloc_global(&mut self, global_type: GlobalType, val: Value) -> usize {
503 let global_inst = GlobalInst {
504 ty: global_type,
505 value: val,
506 };
507
508 let addr = self.globals.len();
509 self.globals.push(global_inst);
510 addr
511 }
512
513 fn alloc_elem(&mut self, ref_type: RefType, refs: Vec<Ref>) -> usize {
515 let elem_inst = ElemInst {
516 ty: ref_type,
517 references: refs,
518 };
519
520 let addr = self.elements.len();
521 self.elements.push(elem_inst);
522 addr
523 }
524
525 fn alloc_data(&mut self, bytes: &[u8]) -> usize {
527 let data_inst = DataInst {
528 data: Vec::from(bytes),
529 };
530
531 let addr = self.data.len();
532 self.data.push(data_inst);
533 addr
534 }
535
536 pub fn invoke(
537 &mut self,
538 func_addr: usize,
539 params: Vec<Value>,
540 ) -> Result<Vec<Value>, 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(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 interpreter_loop::run(
594 func_addr,
596 &mut stack,
598 EmptyHookSet,
599 self,
600 )?;
601 debug!("Successfully invoked function");
602 Ok(stack.into_values())
603 }
604 }
605 }
606}
607
608#[derive(Debug)]
609pub enum FuncInst<T> {
611 WasmFunc(WasmFuncInst),
612 HostFunc(HostFuncInst<T>),
613}
614
615#[derive(Debug)]
616pub struct WasmFuncInst {
617 pub function_type: FuncType,
618 pub ty: TypeIdx,
619 pub locals: Vec<ValType>,
620 pub code_expr: Span,
621 pub stp: usize,
623
624 pub module_addr: usize,
627}
628
629#[derive(Debug)]
630pub struct HostFuncInst<T> {
631 pub function_type: FuncType,
632 pub hostcode: fn(&mut T, Vec<Value>) -> Vec<Value>,
633}
634
635impl<T> FuncInst<T> {
636 pub fn ty(&self) -> FuncType {
637 match self {
638 FuncInst::WasmFunc(wasm_func_inst) => wasm_func_inst.function_type.clone(),
639 FuncInst::HostFunc(host_func_inst) => host_func_inst.function_type.clone(),
640 }
641 }
642}
643
644#[derive(Clone, Debug)]
645pub struct ElemInst {
647 pub ty: RefType,
648 pub references: Vec<Ref>,
649}
650
651impl ElemInst {
652 pub fn len(&self) -> usize {
653 self.references.len()
654 }
655 pub fn is_empty(&self) -> bool {
656 self.references.is_empty()
657 }
658}
659
660#[derive(Debug)]
664pub struct TableInst {
665 pub ty: TableType,
666 pub elem: Vec<Ref>,
667}
668
669impl TableInst {
670 pub fn len(&self) -> usize {
671 self.elem.len()
672 }
673
674 pub fn is_empty(&self) -> bool {
675 self.elem.is_empty()
676 }
677
678 pub fn new(ty: TableType) -> Self {
679 Self {
680 ty,
681 elem: vec![Ref::default_from_ref_type(ty.et); ty.lim.min as usize],
682 }
683 }
684
685 pub fn grow(&mut self, n: u32, reff: Ref) -> Result<(), RuntimeError> {
687 let len = n
689 .checked_add(self.elem.len() as u32)
690 .ok_or(RuntimeError::TableAccessOutOfBounds)?;
691
692 if self.ty.lim.max.map(|max| len > max).unwrap_or(false) {
696 return Err(RuntimeError::TableAccessOutOfBounds);
697 }
698 let limits_prime = Limits {
699 min: len,
700 max: self.ty.lim.max,
701 };
702
703 self.elem.extend(vec![reff; n as usize]);
704
705 self.ty.lim = limits_prime;
706 Ok(())
707 }
708}
709
710pub struct MemInst {
711 #[allow(warnings)]
712 pub ty: MemType,
713 pub mem: LinearMemory,
714}
715impl core::fmt::Debug for MemInst {
716 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
717 f.debug_struct("MemInst")
718 .field("ty", &self.ty)
719 .finish_non_exhaustive()
720 }
721}
722
723impl MemInst {
724 pub fn new(ty: MemType) -> Self {
725 Self {
726 ty,
727 mem: LinearMemory::new_with_initial_pages(ty.limits.min.try_into().unwrap()),
728 }
729 }
730
731 pub fn grow(&mut self, n: u32) -> Result<(), RuntimeError> {
733 let len = n + self.mem.pages() as u32;
735 if len > Limits::MAX_MEM_PAGES {
736 return Err(RuntimeError::MemoryAccessOutOfBounds);
737 }
738
739 if self.ty.limits.max.map(|max| len > max).unwrap_or(false) {
743 return Err(RuntimeError::MemoryAccessOutOfBounds);
744 }
745 let limits_prime = Limits {
746 min: len,
747 max: self.ty.limits.max,
748 };
749
750 self.mem.grow(n.try_into().unwrap());
751
752 self.ty.limits = limits_prime;
753 Ok(())
754 }
755
756 pub fn size(&self) -> usize {
758 self.mem.len() / (crate::Limits::MEM_PAGE_SIZE as usize)
759 }
760}
761
762#[derive(Debug)]
768pub struct GlobalInst {
769 pub ty: GlobalType,
770 pub value: Value,
772}
773
774pub struct DataInst {
775 pub data: Vec<u8>,
776}
777
778impl core::fmt::Debug for DataInst {
779 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
780 f.debug_struct("DataInst").finish_non_exhaustive()
781 }
782}
783
784#[derive(Debug, Copy, Clone, PartialEq, Eq)]
786pub enum ExternVal {
787 Func(usize),
788 Table(usize),
789 Mem(usize),
790 Global(usize),
791}
792
793impl ExternVal {
794 pub fn extern_type<T>(&self, store: &Store<T>) -> CustomResult<ExternType> {
799 Ok(match self {
801 ExternVal::Func(func_addr) => ExternType::Func(
803 store
804 .functions
805 .get(*func_addr)
806 .ok_or(Error::InvalidImportType)?
807 .ty(),
808 ),
809 ExternVal::Table(table_addr) => ExternType::Table(
810 store
811 .tables
812 .get(*table_addr)
813 .ok_or(Error::InvalidImportType)?
814 .ty,
815 ),
816 ExternVal::Mem(mem_addr) => ExternType::Mem(
817 store
818 .memories
819 .get(*mem_addr)
820 .ok_or(Error::InvalidImportType)?
821 .ty,
822 ),
823 ExternVal::Global(global_addr) => ExternType::Global(
824 store
825 .globals
826 .get(*global_addr)
827 .ok_or(Error::InvalidImportType)?
828 .ty,
829 ),
830 })
831 }
832}
833
834pub trait ExternFilterable<T> {
840 fn funcs(self) -> impl Iterator<Item = T>;
841 fn tables(self) -> impl Iterator<Item = T>;
842 fn mems(self) -> impl Iterator<Item = T>;
843 fn globals(self) -> impl Iterator<Item = T>;
844}
845
846impl<'a, I> ExternFilterable<usize> for I
847where
848 I: Iterator<Item = &'a ExternVal>,
849{
850 fn funcs(self) -> impl Iterator<Item = usize> {
851 self.filter_map(|extern_val| {
852 if let ExternVal::Func(func_addr) = extern_val {
853 Some(*func_addr)
854 } else {
855 None
856 }
857 })
858 }
859
860 fn tables(self) -> impl Iterator<Item = usize> {
861 self.filter_map(|extern_val| {
862 if let ExternVal::Table(table_addr) = extern_val {
863 Some(*table_addr)
864 } else {
865 None
866 }
867 })
868 }
869
870 fn mems(self) -> impl Iterator<Item = usize> {
871 self.filter_map(|extern_val| {
872 if let ExternVal::Mem(mem_addr) = extern_val {
873 Some(*mem_addr)
874 } else {
875 None
876 }
877 })
878 }
879
880 fn globals(self) -> impl Iterator<Item = usize> {
881 self.filter_map(|extern_val| {
882 if let ExternVal::Global(global_addr) = extern_val {
883 Some(*global_addr)
884 } else {
885 None
886 }
887 })
888 }
889}
890
891#[derive(Debug)]
893pub struct ModuleInst<'b> {
894 pub types: Vec<FuncType>,
895 pub func_addrs: Vec<usize>,
896 pub table_addrs: Vec<usize>,
897 pub mem_addrs: Vec<usize>,
898 pub global_addrs: Vec<usize>,
899 pub elem_addrs: Vec<usize>,
900 pub data_addrs: Vec<usize>,
901 pub exports: BTreeMap<String, ExternVal>,
906
907 pub wasm_bytecode: &'b [u8],
909
910 pub sidetable: Sidetable,
912}