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::locals::Locals;
29use super::value::ExternAddr;
30use super::UnwrapValidatedExt;
31
32use crate::linear_memory::LinearMemory;
33
34#[derive(Debug)]
40pub struct Store<'b, T> {
41 pub functions: Vec<FuncInst<T>>,
42 pub memories: Vec<MemInst>,
43 pub globals: Vec<GlobalInst>,
44 pub data: Vec<DataInst>,
45 pub tables: Vec<TableInst>,
46 pub elements: Vec<ElemInst>,
47 pub modules: Vec<ModuleInst<'b>>,
48
49 pub registry: Registry,
54 pub user_data: T,
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 user_data,
70 }
71 }
72
73 pub fn add_module(
79 &mut self,
80 name: &str,
81 validation_info: &ValidationInfo<'b>,
82 ) -> CustomResult<()> {
83 debug!("adding module with name {:?}", name);
86 let mut extern_vals = Vec::new();
87
88 for Import {
89 module_name: exporting_module_name,
90 name: import_name,
91 desc: import_desc,
92 } in &validation_info.imports
93 {
94 trace!(
95 "trying to import from exporting module instance named {:?}, the entity with name {:?} with desc: {:?}",
96 exporting_module_name,
97 import_name,
98 import_desc
99 );
100 let import_extern_type = import_desc.extern_type(validation_info)?;
101 let export_extern_val_candidate = *self.registry.lookup(
102 exporting_module_name.clone().into(),
103 import_name.clone().into(),
104 )?;
105 trace!("export candidate found: {:?}", export_extern_val_candidate);
106 if !export_extern_val_candidate
107 .extern_type(self)?
108 .is_subtype_of(&import_extern_type)
109 {
110 return Err(Error::InvalidImportType);
111 }
112 trace!("import and export matches. Adding to externvals");
113 extern_vals.push(export_extern_val_candidate)
114 }
115
116 let mut module_inst = ModuleInst {
121 types: validation_info.types.clone(),
122 func_addrs: extern_vals.iter().funcs().collect(),
123 table_addrs: Vec::new(),
124 mem_addrs: Vec::new(),
125 global_addrs: extern_vals.iter().globals().collect(),
126 elem_addrs: Vec::new(),
127 data_addrs: Vec::new(),
128 exports: BTreeMap::new(),
129 wasm_bytecode: validation_info.wasm,
130 sidetable: validation_info.sidetable.clone(),
131 };
132
133 let func_addrs: Vec<usize> = validation_info
136 .functions
137 .iter()
138 .zip(validation_info.func_blocks_stps.iter())
139 .map(|(ty_idx, (span, stp))| {
140 self.alloc_func((*ty_idx, (*span, *stp)), &module_inst, self.modules.len())
141 })
142 .collect();
143
144 module_inst.func_addrs.extend(func_addrs);
145
146 let maybe_global_init_vals: Result<Vec<Value>, _> = validation_info
149 .globals
150 .iter()
151 .map(|global| {
152 run_const_span(validation_info.wasm, &global.init_expr, &module_inst, self)
153 .transpose()
154 .unwrap_validated()
155 })
156 .collect();
157 let global_init_vals = maybe_global_init_vals?;
158
159 let mut element_init_ref_lists: Vec<Vec<Ref>> =
162 Vec::with_capacity(validation_info.elements.len());
163
164 for elem in &validation_info.elements {
165 let mut new_list = Vec::new();
166 match &elem.init {
167 ElemItems::RefFuncs(ref_funcs) => {
170 for func_idx in ref_funcs {
171 new_list.push(Ref::Func(FuncAddr {
172 addr: Some(module_inst.func_addrs[*func_idx as usize]),
173 }))
174 }
175 }
176 ElemItems::Exprs(_, exprs) => {
177 for expr in exprs {
178 new_list.push(
179 run_const_span(validation_info.wasm, expr, &module_inst, self)?
180 .unwrap_validated()
181 .into(),
182 )
183 }
184 }
185 }
186 element_init_ref_lists.push(new_list);
187 }
188
189 let module = validation_info;
196
197 let extern_vals = extern_vals;
198 let vals = global_init_vals;
199 let ref_lists = element_init_ref_lists;
200
201 let table_addrs: Vec<usize> = module
205 .tables
206 .iter()
207 .map(|table_type| {
208 let null_ref = match table_type.et {
209 RefType::FuncRef => Ref::Func(FuncAddr { addr: None }),
210 RefType::ExternRef => Ref::Extern(ExternAddr { addr: None }),
211 };
212 self.alloc_table(*table_type, null_ref)
213 })
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()
328 .into();
329 let s = 0;
330 table_init(
331 &self.modules,
332 &mut self.tables,
333 &self.elements,
334 current_module_idx,
335 i,
336 *table_idx_i as usize,
337 n,
338 s,
339 d,
340 )
341 .map_err(Error::RuntimeError)?;
342 elem_drop(&self.modules, &mut self.elements, current_module_idx, i)
343 .map_err(Error::RuntimeError)?;
344 }
345 ElemMode::Declarative => {
346 elem_drop(&self.modules, &mut self.elements, current_module_idx, i)
351 .map_err(Error::RuntimeError)?;
352 }
353 ElemMode::Passive => (),
354 }
355 }
356
357 for (i, DataSegment { init, mode }) in validation_info.data.iter().enumerate() {
360 match mode {
361 crate::core::reader::types::data::DataMode::Active(DataModeActive {
362 memory_idx,
363 offset: dinstr_i,
364 }) => {
365 let n = init.len() as i32;
366 if *memory_idx != 0 {
368 return Err(Error::MoreThanOneMemory);
370 }
371
372 let d: i32 = run_const_span(
380 validation_info.wasm,
381 dinstr_i,
382 &self.modules[current_module_idx],
383 self,
384 )?
385 .unwrap_validated()
386 .into();
387 let s = 0;
388 memory_init(
389 &self.modules,
390 &mut self.memories,
391 &self.data,
392 current_module_idx,
393 i,
394 0,
395 n,
396 s,
397 d,
398 )
399 .map_err(Error::RuntimeError)?;
400 data_drop(&self.modules, &mut self.data, current_module_idx, i)
401 .map_err(Error::RuntimeError)?;
402 }
403 crate::core::reader::types::data::DataMode::Passive => (),
404 }
405 }
406
407 if let Some(func_idx) = validation_info.start {
409 let func_addr = self.modules[current_module_idx].func_addrs[func_idx];
413 self.invoke(func_addr, Vec::new())
414 .map_err(Error::RuntimeError)?;
415 };
416
417 Ok(())
418 }
419
420 fn alloc_func(
424 &mut self,
425 func: (TypeIdx, (Span, usize)),
426 module_inst: &ModuleInst,
427 module_addr: usize,
428 ) -> usize {
429 let (ty, (span, stp)) = func;
430
431 let mut wasm_reader = WasmReader::new(module_inst.wasm_bytecode);
433 wasm_reader.move_start_to(span).unwrap_validated();
434
435 let (locals, bytes_read) = wasm_reader
436 .measure_num_read_bytes(crate::code::read_declared_locals)
437 .unwrap_validated();
438
439 let code_expr = wasm_reader
440 .make_span(span.len() - bytes_read)
441 .unwrap_validated();
442
443 let func_inst = FuncInst::WasmFunc(WasmFuncInst {
448 function_type: module_inst.types[ty].clone(),
449 ty,
450 locals,
451 code_expr,
452 stp,
453 module_addr,
454 });
455
456 let addr = self.functions.len();
457 self.functions.push(func_inst);
458 addr
459 }
460
461 pub(super) fn alloc_host_func(
463 &mut self,
464 func_type: FuncType,
465 host_func: fn(&mut T, Vec<Value>) -> Vec<Value>,
466 ) -> usize {
467 let func_inst = FuncInst::HostFunc(HostFuncInst {
468 function_type: func_type,
469 hostcode: host_func,
470 });
471 let addr = self.functions.len();
472 self.functions.push(func_inst);
473 addr
474 }
475
476 fn alloc_table(&mut self, table_type: TableType, reff: Ref) -> usize {
478 let table_inst = TableInst {
479 ty: table_type,
480 elem: vec![reff; table_type.lim.min as usize],
481 };
482
483 let addr = self.tables.len();
484 self.tables.push(table_inst);
485 addr
486 }
487
488 fn alloc_mem(&mut self, mem_type: MemType) -> usize {
490 let mem_inst = MemInst {
491 ty: mem_type,
492 mem: LinearMemory::new_with_initial_pages(
493 mem_type.limits.min.try_into().unwrap_validated(),
494 ),
495 };
496
497 let addr = self.memories.len();
498 self.memories.push(mem_inst);
499 addr
500 }
501
502 fn alloc_global(&mut self, global_type: GlobalType, val: Value) -> usize {
504 let global_inst = GlobalInst {
505 ty: global_type,
506 value: val,
507 };
508
509 let addr = self.globals.len();
510 self.globals.push(global_inst);
511 addr
512 }
513
514 fn alloc_elem(&mut self, ref_type: RefType, refs: Vec<Ref>) -> usize {
516 let elem_inst = ElemInst {
517 ty: ref_type,
518 references: refs,
519 };
520
521 let addr = self.elements.len();
522 self.elements.push(elem_inst);
523 addr
524 }
525
526 fn alloc_data(&mut self, bytes: &[u8]) -> usize {
528 let data_inst = DataInst {
529 data: Vec::from(bytes),
530 };
531
532 let addr = self.data.len();
533 self.data.push(data_inst);
534 addr
535 }
536
537 pub fn invoke(
538 &mut self,
539 func_addr: usize,
540 params: Vec<Value>,
541 ) -> Result<Vec<Value>, RuntimeError> {
542 let func_inst = self
543 .functions
544 .get(func_addr)
545 .ok_or(RuntimeError::FunctionNotFound)?;
546
547 let func_ty = func_inst.ty();
548
549 let param_types = params.iter().map(|v| v.to_ty()).collect::<Vec<_>>();
551
552 if func_ty.params.valtypes != param_types {
553 trace!(
554 "Func param types len: {}; Given args len: {}",
555 func_ty.params.valtypes.len(),
556 param_types.len()
557 );
558 panic!("Invalid parameters for function");
559 }
560
561 match &func_inst {
562 FuncInst::HostFunc(host_func_inst) => {
563 let returns = (host_func_inst.hostcode)(&mut self.user_data, params);
564 debug!("Successfully invoked function");
565
566 let return_types = returns.iter().map(|v| v.to_ty()).collect::<Vec<_>>();
570 if func_ty.returns.valtypes != return_types {
571 trace!(
572 "Func param types len: {}; Given args len: {}",
573 func_ty.params.valtypes.len(),
574 param_types.len()
575 );
576 return Err(RuntimeError::HostFunctionSignatureMismatch);
577 }
578
579 Ok(returns)
580 }
581 FuncInst::WasmFunc(wasm_func_inst) => {
582 let mut stack = Stack::new();
584 let locals = Locals::new(params.into_iter(), wasm_func_inst.locals.iter().cloned());
585
586 stack.push_stackframe(usize::MAX, &func_ty, locals, usize::MAX, usize::MAX)?;
587
588 interpreter_loop::run(
590 func_addr,
592 &mut stack,
594 EmptyHookSet,
595 self,
596 )?;
597 debug!("Successfully invoked function");
598 Ok(stack.into_values())
599 }
600 }
601 }
602}
603
604#[derive(Debug)]
605pub enum FuncInst<T> {
607 WasmFunc(WasmFuncInst),
608 HostFunc(HostFuncInst<T>),
609}
610
611#[derive(Debug)]
612pub struct WasmFuncInst {
613 pub function_type: FuncType,
614 pub ty: TypeIdx,
615 pub locals: Vec<ValType>,
616 pub code_expr: Span,
617 pub stp: usize,
619
620 pub module_addr: usize,
623}
624
625#[derive(Debug)]
626pub struct HostFuncInst<T> {
627 pub function_type: FuncType,
628 pub hostcode: fn(&mut T, Vec<Value>) -> Vec<Value>,
629}
630
631impl<T> FuncInst<T> {
632 pub fn ty(&self) -> FuncType {
633 match self {
634 FuncInst::WasmFunc(wasm_func_inst) => wasm_func_inst.function_type.clone(),
635 FuncInst::HostFunc(host_func_inst) => host_func_inst.function_type.clone(),
636 }
637 }
638}
639
640#[derive(Clone, Debug)]
641pub struct ElemInst {
643 pub ty: RefType,
644 pub references: Vec<Ref>,
645}
646
647impl ElemInst {
648 pub fn len(&self) -> usize {
649 self.references.len()
650 }
651 pub fn is_empty(&self) -> bool {
652 self.references.is_empty()
653 }
654}
655
656#[derive(Debug)]
660pub struct TableInst {
661 pub ty: TableType,
662 pub elem: Vec<Ref>,
663}
664
665impl TableInst {
666 pub fn len(&self) -> usize {
667 self.elem.len()
668 }
669
670 pub fn is_empty(&self) -> bool {
671 self.elem.is_empty()
672 }
673
674 pub fn new(ty: TableType) -> Self {
675 Self {
676 ty,
677 elem: vec![Ref::default_from_ref_type(ty.et); ty.lim.min as usize],
678 }
679 }
680
681 pub fn grow(&mut self, n: u32, reff: Ref) -> Result<(), RuntimeError> {
683 let len = n
685 .checked_add(self.elem.len() as u32)
686 .ok_or(RuntimeError::TableAccessOutOfBounds)?;
687
688 if self.ty.lim.max.map(|max| len > max).unwrap_or(false) {
692 return Err(RuntimeError::TableAccessOutOfBounds);
693 }
694 let limits_prime = Limits {
695 min: len,
696 max: self.ty.lim.max,
697 };
698
699 self.elem.extend(vec![reff; n as usize]);
700
701 self.ty.lim = limits_prime;
702 Ok(())
703 }
704}
705
706pub struct MemInst {
707 #[allow(warnings)]
708 pub ty: MemType,
709 pub mem: LinearMemory,
710}
711impl core::fmt::Debug for MemInst {
712 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
713 f.debug_struct("MemInst")
714 .field("ty", &self.ty)
715 .finish_non_exhaustive()
716 }
717}
718
719impl MemInst {
720 pub fn new(ty: MemType) -> Self {
721 Self {
722 ty,
723 mem: LinearMemory::new_with_initial_pages(ty.limits.min.try_into().unwrap()),
724 }
725 }
726
727 pub fn grow(&mut self, n: u32) -> Result<(), RuntimeError> {
729 let len = n + self.mem.pages() as u32;
731 if len > Limits::MAX_MEM_PAGES {
732 return Err(RuntimeError::MemoryAccessOutOfBounds);
733 }
734
735 if self.ty.limits.max.map(|max| len > max).unwrap_or(false) {
739 return Err(RuntimeError::MemoryAccessOutOfBounds);
740 }
741 let limits_prime = Limits {
742 min: len,
743 max: self.ty.limits.max,
744 };
745
746 self.mem.grow(n.try_into().unwrap());
747
748 self.ty.limits = limits_prime;
749 Ok(())
750 }
751
752 pub fn size(&self) -> usize {
754 self.mem.len() / (crate::Limits::MEM_PAGE_SIZE as usize)
755 }
756}
757
758#[derive(Debug)]
764pub struct GlobalInst {
765 pub ty: GlobalType,
766 pub value: Value,
768}
769
770pub struct DataInst {
771 pub data: Vec<u8>,
772}
773
774impl core::fmt::Debug for DataInst {
775 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
776 f.debug_struct("DataInst").finish_non_exhaustive()
777 }
778}
779
780#[derive(Debug, Copy, Clone, PartialEq, Eq)]
782pub enum ExternVal {
783 Func(usize),
784 Table(usize),
785 Mem(usize),
786 Global(usize),
787}
788
789impl ExternVal {
790 pub fn extern_type<T>(&self, store: &Store<T>) -> CustomResult<ExternType> {
795 Ok(match self {
797 ExternVal::Func(func_addr) => ExternType::Func(
799 store
800 .functions
801 .get(*func_addr)
802 .ok_or(Error::InvalidImportType)?
803 .ty(),
804 ),
805 ExternVal::Table(table_addr) => ExternType::Table(
806 store
807 .tables
808 .get(*table_addr)
809 .ok_or(Error::InvalidImportType)?
810 .ty,
811 ),
812 ExternVal::Mem(mem_addr) => ExternType::Mem(
813 store
814 .memories
815 .get(*mem_addr)
816 .ok_or(Error::InvalidImportType)?
817 .ty,
818 ),
819 ExternVal::Global(global_addr) => ExternType::Global(
820 store
821 .globals
822 .get(*global_addr)
823 .ok_or(Error::InvalidImportType)?
824 .ty,
825 ),
826 })
827 }
828}
829
830pub trait ExternFilterable<T> {
836 fn funcs(self) -> impl Iterator<Item = T>;
837 fn tables(self) -> impl Iterator<Item = T>;
838 fn mems(self) -> impl Iterator<Item = T>;
839 fn globals(self) -> impl Iterator<Item = T>;
840}
841
842impl<'a, I> ExternFilterable<usize> for I
843where
844 I: Iterator<Item = &'a ExternVal>,
845{
846 fn funcs(self) -> impl Iterator<Item = usize> {
847 self.filter_map(|extern_val| {
848 if let ExternVal::Func(func_addr) = extern_val {
849 Some(*func_addr)
850 } else {
851 None
852 }
853 })
854 }
855
856 fn tables(self) -> impl Iterator<Item = usize> {
857 self.filter_map(|extern_val| {
858 if let ExternVal::Table(table_addr) = extern_val {
859 Some(*table_addr)
860 } else {
861 None
862 }
863 })
864 }
865
866 fn mems(self) -> impl Iterator<Item = usize> {
867 self.filter_map(|extern_val| {
868 if let ExternVal::Mem(mem_addr) = extern_val {
869 Some(*mem_addr)
870 } else {
871 None
872 }
873 })
874 }
875
876 fn globals(self) -> impl Iterator<Item = usize> {
877 self.filter_map(|extern_val| {
878 if let ExternVal::Global(global_addr) = extern_val {
879 Some(*global_addr)
880 } else {
881 None
882 }
883 })
884 }
885}
886
887#[derive(Debug)]
889pub struct ModuleInst<'b> {
890 pub types: Vec<FuncType>,
891 pub func_addrs: Vec<usize>,
892 pub table_addrs: Vec<usize>,
893 pub mem_addrs: Vec<usize>,
894 pub global_addrs: Vec<usize>,
895 pub elem_addrs: Vec<usize>,
896 pub data_addrs: Vec<usize>,
897 pub exports: BTreeMap<String, ExternVal>,
902
903 pub wasm_bytecode: &'b [u8],
905
906 pub sidetable: Sidetable,
908}