diff --git a/src/core/error.rs b/src/core/error.rs index a7977eb5..84150700 100644 --- a/src/core/error.rs +++ b/src/core/error.rs @@ -48,6 +48,11 @@ pub enum StoreInstantiationError { TooManyMemories(usize), } +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum LinkerError { + UnmetImport, +} + #[derive(Debug, PartialEq, Eq, Clone)] pub enum Error { /// The magic number at the very start of the given WASM file is invalid. @@ -107,6 +112,7 @@ pub enum Error { TooManyLocals(usize), UnsupportedProposal(Proposal), Overflow, + LinkerError(LinkerError), } impl Display for Error { @@ -264,6 +270,7 @@ impl Display for Error { f.write_fmt(format_args!("Unsupported proposal: {:?}", proposal)) } Error::Overflow => f.write_str("Overflow"), + Error::LinkerError(err) => err.fmt(f) } } } @@ -316,6 +323,15 @@ impl Display for StoreInstantiationError { } } +impl Display for LinkerError { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + use LinkerError::*; + match self { + UnmetImport => f.write_str("Unmet import"), + } + } +} + pub type Result = core::result::Result; impl From for Error { diff --git a/src/execution/function_ref.rs b/src/execution/function_ref.rs index a9286866..a0b36968 100644 --- a/src/execution/function_ref.rs +++ b/src/execution/function_ref.rs @@ -4,6 +4,8 @@ use alloc::vec::Vec; use crate::execution::{hooks::HookSet, value::InteropValueList, RuntimeInstance}; use crate::{RuntimeError, ValType, Value}; +use super::store::Store; + pub struct FunctionRef { pub(crate) module_name: String, pub(crate) function_name: String, @@ -22,8 +24,9 @@ impl FunctionRef { &self, runtime: &mut RuntimeInstance, params: Param, + store: &mut Store, ) -> Result { - runtime.invoke(self, params) + runtime.invoke(self, params, store) } pub fn invoke_dynamic( @@ -31,8 +34,9 @@ impl FunctionRef { runtime: &mut RuntimeInstance, params: Vec, ret_types: &[ValType], + store: &mut Store, ) -> Result, RuntimeError> { - runtime.invoke_dynamic(self, params, ret_types) + runtime.invoke_dynamic(self, params, ret_types, store) } // pub fn get_return_types(&self) -> Vec( @@ -42,6 +42,7 @@ pub(super) fn run( lut: &Lut, stack: &mut Stack, mut hooks: H, + store: &mut Store, ) -> Result<(), RuntimeError> { let func_inst = modules[*current_module_idx] .store diff --git a/src/execution/mod.rs b/src/execution/mod.rs index 208cf611..3426bde0 100644 --- a/src/execution/mod.rs +++ b/src/execution/mod.rs @@ -53,15 +53,16 @@ where } impl<'b> RuntimeInstance<'b, EmptyHookSet> { - pub fn new(validation_info: &'_ ValidationInfo<'b>) -> CustomResult { - Self::new_with_hooks(DEFAULT_MODULE, validation_info, EmptyHookSet) + pub fn new(validation_info: &'_ ValidationInfo<'b>, store: &mut Store) -> CustomResult { + Self::new_with_hooks(DEFAULT_MODULE, validation_info, EmptyHookSet, store) } pub fn new_named( module_name: &str, validation_info: &'_ ValidationInfo<'b>, + store: &mut Store, ) -> CustomResult { - Self::new_with_hooks(module_name, validation_info, EmptyHookSet) + Self::new_with_hooks(module_name, validation_info, EmptyHookSet, store) } } @@ -73,6 +74,7 @@ where module_name: &str, validation_info: &'_ ValidationInfo<'b>, hook_set: H, + store: &mut Store, ) -> CustomResult { trace!("Starting instantiation of bytecode"); @@ -95,7 +97,7 @@ where function_index: start, exported: false, }; - instance.invoke::<(), ()>(&start_fn, ())?; + instance.invoke::<(), ()>(&start_fn, (), store)?; } Ok(instance) @@ -173,24 +175,42 @@ where &mut self, function_ref: &FunctionRef, params: Param, + store: &mut Store, ) -> Result { // First, verify that the function reference is valid let (module_idx, func_idx) = self.verify_function_ref(function_ref)?; // -=-= Verification =-=- - trace!("{:?}", self.modules[module_idx].store.funcs); + // trace!("{:?}", self.modules[module_idx].store.funcs); + trace!("{:?}", self.modules[module_idx].functions); - let func_inst = self.modules[module_idx] - .store - .funcs + let func_inst_idx = self.modules[module_idx] + .functions .get(func_idx) .ok_or(RuntimeError::FunctionNotFound)? - .try_into_local() + .clone(); + + let func_inst = store + .functions + .get(func_inst_idx) .ok_or(RuntimeError::FunctionNotFound)?; - let func_ty = self.modules[module_idx] - .fn_types - .get(func_inst.ty) - .unwrap_validated(); + + let func_ty = func_inst.ty(); + + // let func_ty = self.modules + + // let func_inst = self.modules[module_idx] + // .store + // .funcs + // .get(func_idx) + // .ok_or(RuntimeError::FunctionNotFound)? + // .try_into_local() + // .ok_or(RuntimeError::FunctionNotFound)?; + + // let func_ty = self.modules[module_idx] + // .fn_types + // .get(func_inst.ty_idx) + // .unwrap_validated(); // Check correct function parameters and return types if func_ty.params.valtypes != Param::TYS { @@ -204,7 +224,7 @@ where let mut stack = Stack::new(); let locals = Locals::new( params.into_values().into_iter(), - func_inst.locals.iter().cloned(), + func_inst.try_into_local().unwrap().locals.iter().cloned(), ); // setting `usize::MAX` as return address for the outermost function ensures that we @@ -212,7 +232,7 @@ where stack.push_stackframe( module_idx, func_idx, - func_ty, + &func_ty, locals, usize::MAX, usize::MAX, @@ -226,6 +246,7 @@ where self.lut.as_ref().ok_or(RuntimeError::UnmetImport)?, &mut stack, EmptyHookSet, + store, )?; // Pop return values from stack @@ -247,22 +268,24 @@ where function_ref: &FunctionRef, params: Vec, ret_types: &[ValType], + store: &mut Store, ) -> Result, RuntimeError> { // First, verify that the function reference is valid let (module_idx, func_idx) = self.verify_function_ref(function_ref)?; // -=-= Verification =-=- - let func_inst = self.modules[module_idx] - .store - .funcs + let func_inst_idx = self.modules[module_idx] + .functions .get(func_idx) .ok_or(RuntimeError::FunctionNotFound)? - .try_into_local() + .clone(); + + let func_inst = store + .functions + .get(func_inst_idx) .ok_or(RuntimeError::FunctionNotFound)?; - let func_ty = self.modules[module_idx] - .fn_types - .get(func_inst.ty) - .unwrap_validated(); + + let func_ty = func_inst.ty(); // Verify that the given parameters match the function parameters let param_types = params.iter().map(|v| v.to_ty()).collect::>(); @@ -278,8 +301,11 @@ where // Prepare a new stack with the locals for the entry function let mut stack = Stack::new(); - let locals = Locals::new(params.into_iter(), func_inst.locals.iter().cloned()); - stack.push_stackframe(module_idx, func_idx, func_ty, locals, 0, 0); + let locals = Locals::new( + params.into_iter(), + func_inst.try_into_local().unwrap().locals.iter().cloned(), + ); + stack.push_stackframe(module_idx, func_idx, &func_ty, locals, 0, 0); let mut currrent_module_idx = module_idx; // Run the interpreter @@ -289,19 +315,21 @@ where self.lut.as_ref().ok_or(RuntimeError::UnmetImport)?, &mut stack, EmptyHookSet, + &mut store, )?; - let func_inst = self.modules[module_idx] - .store - .funcs + let func_inst_idx = self.modules[module_idx] + .functions .get(func_idx) .ok_or(RuntimeError::FunctionNotFound)? - .try_into_local() + .clone(); + + let func_inst = store + .functions + .get(func_inst_idx) .ok_or(RuntimeError::FunctionNotFound)?; - let func_ty = self.modules[module_idx] - .fn_types - .get(func_inst.ty) - .unwrap_validated(); + + let func_ty = func_inst.ty(); // Pop return values from stack let return_values = func_ty @@ -334,22 +362,24 @@ where &mut self, function_ref: &FunctionRef, params: Vec, + store: &mut Store, ) -> Result, RuntimeError> { // First, verify that the function reference is valid let (module_idx, func_idx) = self.verify_function_ref(function_ref)?; // -=-= Verification =-=- - let func_inst = self.modules[module_idx] - .store - .funcs + let func_inst_idx = self.modules[module_idx] + .functions .get(func_idx) .ok_or(RuntimeError::FunctionNotFound)? - .try_into_local() + .clone(); + + let func_inst = store + .functions + .get(func_inst_idx) .ok_or(RuntimeError::FunctionNotFound)?; - let func_ty = self.modules[module_idx] - .fn_types - .get(func_inst.ty) - .unwrap_validated(); + + let func_ty = func_inst.ty(); // Verify that the given parameters match the function parameters let param_types = params.iter().map(|v| v.to_ty()).collect::>(); @@ -371,19 +401,21 @@ where self.lut.as_ref().ok_or(RuntimeError::UnmetImport)?, &mut stack, EmptyHookSet, + &mut store, )?; - let func_inst = self.modules[module_idx] - .store - .funcs + let func_inst_idx = self.modules[module_idx] + .functions .get(func_idx) .ok_or(RuntimeError::FunctionNotFound)? - .try_into_local() + .clone(); + + let func_inst = store + .functions + .get(func_inst_idx) .ok_or(RuntimeError::FunctionNotFound)?; - let func_ty = self.modules[module_idx] - .fn_types - .get(func_inst.ty) - .unwrap_validated(); + + let func_ty = func_inst.ty(); // Pop return values from stack let return_values = func_ty diff --git a/src/execution/store.rs b/src/execution/store.rs index 9407b0d5..4197f4b9 100644 --- a/src/execution/store.rs +++ b/src/execution/store.rs @@ -1,4 +1,5 @@ use alloc::collections::btree_map::BTreeMap; +use alloc::collections::btree_set::BTreeSet; use alloc::string::{String, ToString}; use alloc::vec; use alloc::vec::Vec; @@ -11,7 +12,7 @@ use crate::core::reader::types::element::{ElemItems, ElemMode}; use crate::core::reader::types::export::ExportDesc; use crate::core::reader::types::global::Global; use crate::core::reader::types::import::ImportDesc; -use crate::core::reader::types::{MemType, TableType, ValType}; +use crate::core::reader::types::{FuncType, MemType, TableType, ValType}; use crate::core::reader::WasmReader; use crate::core::sidetable::Sidetable; use crate::execution::value::{Ref, Value}; @@ -22,6 +23,8 @@ use crate::{Error, RefType, ValidationInfo}; use super::execution_info::ExecutionInfo; use super::UnwrapValidatedExt; +use crate::core::error::LinkerError; + /// The store represents all global state that can be manipulated by WebAssembly programs. It /// consists of the runtime representation of all instances of functions, tables, memories, and /// globals, element segments, and data segments that have been allocated during the life time of @@ -114,7 +117,7 @@ impl<'b> Store<'b> { exports: module.exports, }; - self.module_names.insert(name, self.modules.len()); + self.module_names.insert(name.clone(), self.modules.len()); self.modules.push(execution_info); // TODO: At this point of the code, we can continue in two ways with imports/exports: @@ -127,22 +130,43 @@ impl<'b> Store<'b> { // TODO: failing is harder since we already modified 'self'. We will circle back to this later. - for module in &mut self.modules { - for fn_store_idx in &mut module.functions { - let func = &self.functions[*fn_store_idx]; + // let temp = Vec::new(); + + for module_idx in 0..self.modules.len() { + for function_idx in 0..self.modules[module_idx].functions.len() { + let fn_store_idx = self.modules[module_idx].functions[function_idx]; + let func: &FuncInst = &self.functions[fn_store_idx]; if let FuncInst::Imported(import) = func { let resolved_idx = self.lookup_function(&import.module_name, &import.function_name); if resolved_idx.is_none() && import.module_name == name { // TODO: Failed resolution... BAD! + return Err(Error::LinkerError(LinkerError::UnmetImport)); } else { - *fn_store_idx = resolved_idx.unwrap(); + self.modules[module_idx].functions[function_idx] = resolved_idx.unwrap(); } } } } + // for module in &self.modules { + // for fn_store_idx in &module.functions { + // let func: &FuncInst = &self.functions[*fn_store_idx]; + // if let FuncInst::Imported(import) = func { + // let resolved_idx = + // self.lookup_function(&import.module_name, &import.function_name); + + // if resolved_idx.is_none() && import.module_name == name { + // // TODO: Failed resolution... BAD! + // return Err(Error::LinkerError(LinkerError::UnmetImport)); + // } else { + // // *fn_store_idx = resolved_idx.unwrap(); + // } + // } + // } + // } + Ok(()) } @@ -234,6 +258,7 @@ impl<'b> ValidationInfo<'b> { code_expr, // TODO figure out where we want our sidetables sidetable: sidetable.clone(), + function_type: self.types[*ty].clone(), }) }); @@ -242,6 +267,7 @@ impl<'b> ValidationInfo<'b> { ty: *type_idx, module_name: import.module_name.clone(), function_name: import.name.clone(), + function_type: self.types[*type_idx].clone(), })), _ => None, }); @@ -464,6 +490,7 @@ pub struct LocalFuncInst { pub locals: Vec, pub code_expr: Span, pub sidetable: Sidetable, + pub function_type: FuncType, } #[derive(Debug)] @@ -471,16 +498,24 @@ pub struct ImportedFuncInst { pub ty: TypeIdx, pub module_name: String, pub function_name: String, + pub function_type: FuncType, } impl FuncInst { - pub fn ty(&self) -> TypeIdx { + pub fn ty_idx(&self) -> TypeIdx { match self { FuncInst::Local(f) => f.ty, FuncInst::Imported(f) => f.ty, } } + pub fn ty(&self) -> FuncType { + match self { + FuncInst::Local(f) => f.function_type.clone(), + FuncInst::Imported(f) => f.function_type.clone(), + } + } + pub fn try_into_local(&self) -> Option<&LocalFuncInst> { match self { FuncInst::Local(f) => Some(f),