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(Default, Debug)]
40pub struct Store<'b> {
41 pub functions: Vec<FuncInst>,
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}
55
56impl<'b> Store<'b> {
57 pub fn add_module(
63 &mut self,
64 name: &str,
65 validation_info: &ValidationInfo<'b>,
66 ) -> CustomResult<()> {
67 debug!("adding module with name {:?}", name);
70 let mut extern_vals = Vec::new();
71
72 for Import {
73 module_name: exporting_module_name,
74 name: import_name,
75 desc: import_desc,
76 } in &validation_info.imports
77 {
78 trace!(
79 "trying to import from exporting module instance named {:?}, the entity with name {:?} with desc: {:?}",
80 exporting_module_name,
81 import_name,
82 import_desc
83 );
84 let import_extern_type = import_desc.extern_type(validation_info)?;
85 let export_extern_val_candidate = *self.registry.lookup(
86 exporting_module_name.clone().into(),
87 import_name.clone().into(),
88 )?;
89 trace!("export candidate found: {:?}", export_extern_val_candidate);
90 if !export_extern_val_candidate
91 .extern_type(self)?
92 .is_subtype_of(&import_extern_type)
93 {
94 return Err(Error::InvalidImportType);
95 }
96 trace!("import and export matches. Adding to externvals");
97 extern_vals.push(export_extern_val_candidate)
98 }
99
100 let mut module_inst = ModuleInst {
105 types: validation_info.types.clone(),
106 func_addrs: extern_vals.iter().funcs().collect(),
107 table_addrs: Vec::new(),
108 mem_addrs: Vec::new(),
109 global_addrs: extern_vals.iter().globals().collect(),
110 elem_addrs: Vec::new(),
111 data_addrs: Vec::new(),
112 exports: BTreeMap::new(),
113 wasm_bytecode: validation_info.wasm,
114 sidetable: validation_info.sidetable.clone(),
115 };
116
117 let func_addrs: Vec<usize> = validation_info
120 .functions
121 .iter()
122 .zip(validation_info.func_blocks_stps.iter())
123 .map(|(ty_idx, (span, stp))| {
124 self.alloc_func((*ty_idx, (*span, *stp)), &module_inst, self.modules.len())
125 })
126 .collect();
127
128 module_inst.func_addrs.extend(func_addrs);
129
130 let maybe_global_init_vals: Result<Vec<Value>, _> = validation_info
133 .globals
134 .iter()
135 .map(|global| {
136 run_const_span(validation_info.wasm, &global.init_expr, &module_inst, self)
137 .transpose()
138 .unwrap_validated()
139 })
140 .collect();
141 let global_init_vals = maybe_global_init_vals?;
142
143 let mut element_init_ref_lists: Vec<Vec<Ref>> =
146 Vec::with_capacity(validation_info.elements.len());
147
148 for elem in &validation_info.elements {
149 let mut new_list = Vec::new();
150 match &elem.init {
151 ElemItems::RefFuncs(ref_funcs) => {
154 for func_idx in ref_funcs {
155 new_list.push(Ref::Func(FuncAddr {
156 addr: Some(module_inst.func_addrs[*func_idx as usize]),
157 }))
158 }
159 }
160 ElemItems::Exprs(_, exprs) => {
161 for expr in exprs {
162 new_list.push(
163 run_const_span(validation_info.wasm, expr, &module_inst, self)?
164 .unwrap_validated()
165 .into(),
166 )
167 }
168 }
169 }
170 element_init_ref_lists.push(new_list);
171 }
172
173 let module = validation_info;
180
181 let extern_vals = extern_vals;
182 let vals = global_init_vals;
183 let ref_lists = element_init_ref_lists;
184
185 let table_addrs: Vec<usize> = module
189 .tables
190 .iter()
191 .map(|table_type| {
192 let null_ref = match table_type.et {
193 RefType::FuncRef => Ref::Func(FuncAddr { addr: None }),
194 RefType::ExternRef => Ref::Extern(ExternAddr { addr: None }),
195 };
196 self.alloc_table(*table_type, null_ref)
197 })
198 .collect();
199 let mem_addrs: Vec<usize> = module
200 .memories
201 .iter()
202 .map(|mem_type| self.alloc_mem(*mem_type))
203 .collect();
204 let global_addrs: Vec<usize> = module
205 .globals
206 .iter()
207 .zip(vals)
208 .map(
209 |(
210 Global {
211 ty: global_type, ..
212 },
213 val,
214 )| self.alloc_global(*global_type, val),
215 )
216 .collect();
217 let elem_addrs = module
218 .elements
219 .iter()
220 .zip(ref_lists)
221 .map(|(elem, refs)| self.alloc_elem(elem.ty(), refs))
222 .collect();
223 let data_addrs = module
224 .data
225 .iter()
226 .map(|DataSegment { init: bytes, .. }| self.alloc_data(bytes))
227 .collect();
228
229 let mut table_addrs_mod: Vec<usize> = extern_vals.iter().tables().collect();
233 table_addrs_mod.extend(table_addrs);
234
235 let mut mem_addrs_mod: Vec<usize> = extern_vals.iter().mems().collect();
236 mem_addrs_mod.extend(mem_addrs);
237
238 module_inst.global_addrs.extend(global_addrs);
240
241 let export_insts: BTreeMap<String, ExternVal> = module
243 .exports
244 .iter()
245 .map(|Export { name, desc }| {
246 let value = match desc {
247 ExportDesc::FuncIdx(func_idx) => {
248 ExternVal::Func(module_inst.func_addrs[*func_idx])
249 }
250 ExportDesc::TableIdx(table_idx) => {
251 ExternVal::Table(table_addrs_mod[*table_idx])
252 }
253 ExportDesc::MemIdx(mem_idx) => ExternVal::Mem(mem_addrs_mod[*mem_idx]),
254 ExportDesc::GlobalIdx(global_idx) => {
255 ExternVal::Global(module_inst.global_addrs[*global_idx])
256 }
257 };
258 (String::from(name), value)
259 })
260 .collect();
261
262 module_inst.table_addrs = table_addrs_mod;
264 module_inst.mem_addrs = mem_addrs_mod;
265 module_inst.elem_addrs = elem_addrs;
266 module_inst.data_addrs = data_addrs;
267 module_inst.exports = export_insts;
268
269 self.registry
273 .register_module(name.to_owned().into(), &module_inst)?;
274
275 let current_module_idx = self.modules.len();
278 self.modules.push(module_inst);
279
280 for (
283 i,
284 ElemType {
285 init: elem_items,
286 mode,
287 },
288 ) in validation_info.elements.iter().enumerate()
289 {
290 match mode {
291 ElemMode::Active(ActiveElem {
292 table_idx: table_idx_i,
293 init_expr: einstr_i,
294 }) => {
295 let n = elem_items.len() as i32;
296 let d: i32 = run_const_span(
306 validation_info.wasm,
307 einstr_i,
308 &self.modules[current_module_idx],
309 self,
310 )?
311 .unwrap_validated()
312 .into();
313 let s = 0;
314 table_init(
315 &self.modules,
316 &mut self.tables,
317 &self.elements,
318 current_module_idx,
319 i,
320 *table_idx_i as usize,
321 n,
322 s,
323 d,
324 )
325 .map_err(Error::RuntimeError)?;
326 elem_drop(&self.modules, &mut self.elements, current_module_idx, i)
327 .map_err(Error::RuntimeError)?;
328 }
329 ElemMode::Declarative => {
330 elem_drop(&self.modules, &mut self.elements, current_module_idx, i)
335 .map_err(Error::RuntimeError)?;
336 }
337 ElemMode::Passive => (),
338 }
339 }
340
341 for (i, DataSegment { init, mode }) in validation_info.data.iter().enumerate() {
344 match mode {
345 crate::core::reader::types::data::DataMode::Active(DataModeActive {
346 memory_idx,
347 offset: dinstr_i,
348 }) => {
349 let n = init.len() as i32;
350 if *memory_idx != 0 {
352 return Err(Error::MoreThanOneMemory);
354 }
355
356 let d: i32 = run_const_span(
364 validation_info.wasm,
365 dinstr_i,
366 &self.modules[current_module_idx],
367 self,
368 )?
369 .unwrap_validated()
370 .into();
371 let s = 0;
372 memory_init(
373 &self.modules,
374 &mut self.memories,
375 &self.data,
376 current_module_idx,
377 i,
378 0,
379 n,
380 s,
381 d,
382 )
383 .map_err(Error::RuntimeError)?;
384 data_drop(&self.modules, &mut self.data, current_module_idx, i)
385 .map_err(Error::RuntimeError)?;
386 }
387 crate::core::reader::types::data::DataMode::Passive => (),
388 }
389 }
390
391 if let Some(func_idx) = validation_info.start {
393 let func_addr = self.modules[current_module_idx].func_addrs[func_idx];
397 self.invoke(func_addr, Vec::new())
398 .map_err(Error::RuntimeError)?;
399 };
400
401 Ok(())
402 }
403
404 fn alloc_func(
408 &mut self,
409 func: (TypeIdx, (Span, usize)),
410 module_inst: &ModuleInst,
411 module_addr: usize,
412 ) -> usize {
413 let (ty, (span, stp)) = func;
414
415 let mut wasm_reader = WasmReader::new(module_inst.wasm_bytecode);
417 wasm_reader.move_start_to(span).unwrap_validated();
418
419 let (locals, bytes_read) = wasm_reader
420 .measure_num_read_bytes(crate::code::read_declared_locals)
421 .unwrap_validated();
422
423 let code_expr = wasm_reader
424 .make_span(span.len() - bytes_read)
425 .unwrap_validated();
426
427 let func_inst = FuncInst::WasmFunc(WasmFuncInst {
432 function_type: module_inst.types[ty].clone(),
433 ty,
434 locals,
435 code_expr,
436 stp,
437 module_addr,
438 });
439
440 let addr = self.functions.len();
441 self.functions.push(func_inst);
442 addr
443 }
444
445 pub(super) fn alloc_host_func(
447 &mut self,
448 func_type: FuncType,
449 host_func: fn(Vec<Value>) -> Vec<Value>,
450 ) -> usize {
451 let func_inst = FuncInst::HostFunc(HostFuncInst {
452 function_type: func_type,
453 hostcode: host_func,
454 });
455 let addr = self.functions.len();
456 self.functions.push(func_inst);
457 addr
458 }
459
460 fn alloc_table(&mut self, table_type: TableType, reff: Ref) -> usize {
462 let table_inst = TableInst {
463 ty: table_type,
464 elem: vec![reff; table_type.lim.min as usize],
465 };
466
467 let addr = self.tables.len();
468 self.tables.push(table_inst);
469 addr
470 }
471
472 fn alloc_mem(&mut self, mem_type: MemType) -> usize {
474 let mem_inst = MemInst {
475 ty: mem_type,
476 mem: LinearMemory::new_with_initial_pages(
477 mem_type.limits.min.try_into().unwrap_validated(),
478 ),
479 };
480
481 let addr = self.memories.len();
482 self.memories.push(mem_inst);
483 addr
484 }
485
486 fn alloc_global(&mut self, global_type: GlobalType, val: Value) -> usize {
488 let global_inst = GlobalInst {
489 ty: global_type,
490 value: val,
491 };
492
493 let addr = self.globals.len();
494 self.globals.push(global_inst);
495 addr
496 }
497
498 fn alloc_elem(&mut self, ref_type: RefType, refs: Vec<Ref>) -> usize {
500 let elem_inst = ElemInst {
501 ty: ref_type,
502 references: refs,
503 };
504
505 let addr = self.elements.len();
506 self.elements.push(elem_inst);
507 addr
508 }
509
510 fn alloc_data(&mut self, bytes: &[u8]) -> usize {
512 let data_inst = DataInst {
513 data: Vec::from(bytes),
514 };
515
516 let addr = self.data.len();
517 self.data.push(data_inst);
518 addr
519 }
520
521 pub fn invoke(
522 &mut self,
523 func_addr: usize,
524 params: Vec<Value>,
525 ) -> Result<Vec<Value>, RuntimeError> {
526 let func_inst = self
527 .functions
528 .get(func_addr)
529 .ok_or(RuntimeError::FunctionNotFound)?;
530
531 let func_ty = func_inst.ty();
532
533 let param_types = params.iter().map(|v| v.to_ty()).collect::<Vec<_>>();
535
536 if func_ty.params.valtypes != param_types {
537 trace!(
538 "Func param types len: {}; Given args len: {}",
539 func_ty.params.valtypes.len(),
540 param_types.len()
541 );
542 panic!("Invalid parameters for function");
543 }
544
545 match &func_inst {
546 FuncInst::HostFunc(host_func_inst) => {
547 let returns = (host_func_inst.hostcode)(params);
548 debug!("Successfully invoked function");
549
550 let return_types = returns.iter().map(|v| v.to_ty()).collect::<Vec<_>>();
554 if func_ty.returns.valtypes != return_types {
555 trace!(
556 "Func param types len: {}; Given args len: {}",
557 func_ty.params.valtypes.len(),
558 param_types.len()
559 );
560 return Err(RuntimeError::HostFunctionSignatureMismatch);
561 }
562
563 Ok(returns)
564 }
565 FuncInst::WasmFunc(wasm_func_inst) => {
566 let mut stack = Stack::new();
568 let locals = Locals::new(params.into_iter(), wasm_func_inst.locals.iter().cloned());
569
570 stack.push_stackframe(usize::MAX, &func_ty, locals, usize::MAX, usize::MAX)?;
571
572 interpreter_loop::run(
574 func_addr,
576 &mut stack,
578 EmptyHookSet,
579 self,
580 )?;
581 debug!("Successfully invoked function");
582 Ok(stack.into_values())
583 }
584 }
585 }
586}
587
588#[derive(Debug)]
589pub enum FuncInst {
591 WasmFunc(WasmFuncInst),
592 HostFunc(HostFuncInst),
593}
594
595#[derive(Debug)]
596pub struct WasmFuncInst {
597 pub function_type: FuncType,
598 pub ty: TypeIdx,
599 pub locals: Vec<ValType>,
600 pub code_expr: Span,
601 pub stp: usize,
603
604 pub module_addr: usize,
607}
608
609#[derive(Debug)]
610pub struct HostFuncInst {
611 pub function_type: FuncType,
612 pub hostcode: fn(Vec<Value>) -> Vec<Value>,
613}
614
615impl FuncInst {
616 pub fn ty(&self) -> FuncType {
617 match self {
618 FuncInst::WasmFunc(wasm_func_inst) => wasm_func_inst.function_type.clone(),
619 FuncInst::HostFunc(host_func_inst) => host_func_inst.function_type.clone(),
620 }
621 }
622}
623
624#[derive(Clone, Debug)]
625pub struct ElemInst {
627 pub ty: RefType,
628 pub references: Vec<Ref>,
629}
630
631impl ElemInst {
632 pub fn len(&self) -> usize {
633 self.references.len()
634 }
635 pub fn is_empty(&self) -> bool {
636 self.references.is_empty()
637 }
638}
639
640#[derive(Debug)]
644pub struct TableInst {
645 pub ty: TableType,
646 pub elem: Vec<Ref>,
647}
648
649impl TableInst {
650 pub fn len(&self) -> usize {
651 self.elem.len()
652 }
653
654 pub fn is_empty(&self) -> bool {
655 self.elem.is_empty()
656 }
657
658 pub fn new(ty: TableType) -> Self {
659 Self {
660 ty,
661 elem: vec![Ref::default_from_ref_type(ty.et); ty.lim.min as usize],
662 }
663 }
664
665 pub fn grow(&mut self, n: u32, reff: Ref) -> Result<(), RuntimeError> {
667 let len = n
669 .checked_add(self.elem.len() as u32)
670 .ok_or(RuntimeError::TableAccessOutOfBounds)?;
671
672 if self.ty.lim.max.map(|max| len > max).unwrap_or(false) {
676 return Err(RuntimeError::TableAccessOutOfBounds);
677 }
678 let limits_prime = Limits {
679 min: len,
680 max: self.ty.lim.max,
681 };
682
683 self.elem.extend(vec![reff; n as usize]);
684
685 self.ty.lim = limits_prime;
686 Ok(())
687 }
688}
689
690pub struct MemInst {
691 #[allow(warnings)]
692 pub ty: MemType,
693 pub mem: LinearMemory,
694}
695impl core::fmt::Debug for MemInst {
696 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
697 f.debug_struct("MemInst")
698 .field("ty", &self.ty)
699 .finish_non_exhaustive()
700 }
701}
702
703impl MemInst {
704 pub fn new(ty: MemType) -> Self {
705 Self {
706 ty,
707 mem: LinearMemory::new_with_initial_pages(ty.limits.min.try_into().unwrap()),
708 }
709 }
710
711 pub fn grow(&mut self, n: u32) -> Result<(), RuntimeError> {
713 let len = n + self.mem.pages() as u32;
715 if len > Limits::MAX_MEM_PAGES {
716 return Err(RuntimeError::MemoryAccessOutOfBounds);
717 }
718
719 if self.ty.limits.max.map(|max| len > max).unwrap_or(false) {
723 return Err(RuntimeError::MemoryAccessOutOfBounds);
724 }
725 let limits_prime = Limits {
726 min: len,
727 max: self.ty.limits.max,
728 };
729
730 self.mem.grow(n.try_into().unwrap());
731
732 self.ty.limits = limits_prime;
733 Ok(())
734 }
735
736 pub fn size(&self) -> usize {
738 self.mem.len() / (crate::Limits::MEM_PAGE_SIZE as usize)
739 }
740}
741
742#[derive(Debug)]
748pub struct GlobalInst {
749 pub ty: GlobalType,
750 pub value: Value,
752}
753
754pub struct DataInst {
755 pub data: Vec<u8>,
756}
757
758impl core::fmt::Debug for DataInst {
759 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
760 f.debug_struct("DataInst").finish_non_exhaustive()
761 }
762}
763
764#[derive(Debug, Copy, Clone, PartialEq, Eq)]
766pub enum ExternVal {
767 Func(usize),
768 Table(usize),
769 Mem(usize),
770 Global(usize),
771}
772
773impl ExternVal {
774 pub fn extern_type(&self, store: &Store) -> CustomResult<ExternType> {
779 Ok(match self {
781 ExternVal::Func(func_addr) => ExternType::Func(
783 store
784 .functions
785 .get(*func_addr)
786 .ok_or(Error::InvalidImportType)?
787 .ty(),
788 ),
789 ExternVal::Table(table_addr) => ExternType::Table(
790 store
791 .tables
792 .get(*table_addr)
793 .ok_or(Error::InvalidImportType)?
794 .ty,
795 ),
796 ExternVal::Mem(mem_addr) => ExternType::Mem(
797 store
798 .memories
799 .get(*mem_addr)
800 .ok_or(Error::InvalidImportType)?
801 .ty,
802 ),
803 ExternVal::Global(global_addr) => ExternType::Global(
804 store
805 .globals
806 .get(*global_addr)
807 .ok_or(Error::InvalidImportType)?
808 .ty,
809 ),
810 })
811 }
812}
813
814pub trait ExternFilterable<T> {
820 fn funcs(self) -> impl Iterator<Item = T>;
821 fn tables(self) -> impl Iterator<Item = T>;
822 fn mems(self) -> impl Iterator<Item = T>;
823 fn globals(self) -> impl Iterator<Item = T>;
824}
825
826impl<'a, I> ExternFilterable<usize> for I
827where
828 I: Iterator<Item = &'a ExternVal>,
829{
830 fn funcs(self) -> impl Iterator<Item = usize> {
831 self.filter_map(|extern_val| {
832 if let ExternVal::Func(func_addr) = extern_val {
833 Some(*func_addr)
834 } else {
835 None
836 }
837 })
838 }
839
840 fn tables(self) -> impl Iterator<Item = usize> {
841 self.filter_map(|extern_val| {
842 if let ExternVal::Table(table_addr) = extern_val {
843 Some(*table_addr)
844 } else {
845 None
846 }
847 })
848 }
849
850 fn mems(self) -> impl Iterator<Item = usize> {
851 self.filter_map(|extern_val| {
852 if let ExternVal::Mem(mem_addr) = extern_val {
853 Some(*mem_addr)
854 } else {
855 None
856 }
857 })
858 }
859
860 fn globals(self) -> impl Iterator<Item = usize> {
861 self.filter_map(|extern_val| {
862 if let ExternVal::Global(global_addr) = extern_val {
863 Some(*global_addr)
864 } else {
865 None
866 }
867 })
868 }
869}
870
871#[derive(Debug)]
873pub struct ModuleInst<'b> {
874 pub types: Vec<FuncType>,
875 pub func_addrs: Vec<usize>,
876 pub table_addrs: Vec<usize>,
877 pub mem_addrs: Vec<usize>,
878 pub global_addrs: Vec<usize>,
879 pub elem_addrs: Vec<usize>,
880 pub data_addrs: Vec<usize>,
881 pub exports: BTreeMap<String, ExternVal>,
886
887 pub wasm_bytecode: &'b [u8],
889
890 pub sidetable: Sidetable,
892}