diff --git a/crates/wasmi/src/engine/mod.rs b/crates/wasmi/src/engine/mod.rs index 78b3047ac3..f0518aae5a 100644 --- a/crates/wasmi/src/engine/mod.rs +++ b/crates/wasmi/src/engine/mod.rs @@ -285,23 +285,19 @@ impl EngineInner { Results: CallResults, { self.initialize_args(params); - let signature = match func.as_internal(ctx.as_context()) { + match func.as_internal(ctx.as_context()) { FuncEntityInternal::Wasm(wasm_func) => { - let signature = wasm_func.signature(); let mut frame = self.stack.call_wasm_root(wasm_func, &self.code_map)?; let mut cache = InstanceCache::from(frame.instance()); self.execute_wasm_func(ctx.as_context_mut(), &mut frame, &mut cache)?; - signature } FuncEntityInternal::Host(host_func) => { - let signature = host_func.signature(); let host_func = host_func.clone(); self.stack .call_host_root(ctx.as_context_mut(), host_func, &self.func_types)?; - signature } }; - let results = self.write_results_back(signature, results); + let results = self.write_results_back(results); Ok(results) } @@ -311,9 +307,7 @@ impl EngineInner { Params: CallParams, { self.stack.clear(); - for param in params.feed_params() { - self.stack.values.push(param); - } + self.stack.values.extend(params.call_params()); } /// Writes the results of the function execution back into the `results` buffer. @@ -325,31 +319,11 @@ impl EngineInner { /// # Panics /// /// - If the `results` buffer length does not match the remaining amount of stack values. - fn write_results_back( - &mut self, - func_type: DedupFuncType, - results: Results, - ) -> ::Results + fn write_results_back(&mut self, results: Results) -> ::Results where Results: CallResults, { - let result_types = self.func_types.resolve_func_type(func_type).results(); - assert_eq!( - self.stack.values.len(), - results.len_results(), - "expected {} values on the stack after function execution but found {}", - results.len_results(), - self.stack.values.len(), - ); - assert_eq!(results.len_results(), result_types.len()); - results.feed_results( - self.stack - .values - .drain() - .iter() - .zip(result_types) - .map(|(raw_value, value_type)| raw_value.with_type(*value_type)), - ) + results.call_results(self.stack.values.drain()) } /// Executes the top most Wasm function on the [`Stack`] until the [`Stack`] is empty. diff --git a/crates/wasmi/src/engine/traits.rs b/crates/wasmi/src/engine/traits.rs index 6c907c63fd..b16535367b 100644 --- a/crates/wasmi/src/engine/traits.rs +++ b/crates/wasmi/src/engine/traits.rs @@ -1,5 +1,6 @@ use crate::core::Value; use core::{iter, slice}; +use wasmi_core::UntypedValue; /// Types implementing this trait may be used as parameters for function execution. /// @@ -12,33 +13,45 @@ use core::{iter, slice}; /// [`Engine`]: [`crate::Engine`] pub trait CallParams { /// The iterator over the parameter values. - type Params: Iterator; - - /// Returns the number of given parameter values. - /// - /// # Note - /// - /// Used by the [`Engine`] to determine how many parameters are received. - /// - /// [`Engine`]: [`crate::Engine`] - fn len_params(&self) -> usize; + type Params: ExactSizeIterator; /// Feeds the parameter values from the caller. - fn feed_params(self) -> Self::Params; + fn call_params(self) -> Self::Params; } impl<'a> CallParams for &'a [Value] { - type Params = iter::Copied>; + type Params = CallParamsValueIter<'a>; - fn len_params(&self) -> usize { - self.len() + #[inline] + fn call_params(self) -> Self::Params { + CallParamsValueIter { + iter: self.iter().copied(), + } } +} + +/// An iterator over the [`UntypedValue`] call parameters. +#[derive(Debug)] +pub struct CallParamsValueIter<'a> { + iter: iter::Copied>, +} - fn feed_params(self) -> Self::Params { - self.iter().copied() +impl<'a> Iterator for CallParamsValueIter<'a> { + type Item = UntypedValue; + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().map(UntypedValue::from) } } +impl ExactSizeIterator for CallParamsValueIter<'_> {} + /// Types implementing this trait may be used as results for function execution. /// /// # Note @@ -53,43 +66,22 @@ pub trait CallResults { /// The type of the returned results value. type Results; - /// Returns the number of expected result values. - /// - /// # Note - /// - /// Used by the [`Engine`] to determine how many results are expected. - /// - /// [`Engine`]: [`crate::Engine`] - fn len_results(&self) -> usize; - /// Feeds the result values back to the caller. /// /// # Panics /// /// If the given `results` do not match the expected amount. - fn feed_results(self, results: T) -> Self::Results - where - T: IntoIterator, - T::IntoIter: ExactSizeIterator; + fn call_results(self, results: &[UntypedValue]) -> Self::Results; } impl<'a> CallResults for &'a mut [Value] { type Results = Self; - fn len_results(&self) -> usize { - self.len() - } - - fn feed_results(self, results: T) -> Self::Results - where - T: IntoIterator, - T::IntoIter: ExactSizeIterator, - { - let results = results.into_iter(); - assert_eq!(self.len_results(), results.len()); - for (dst, src) in self.iter_mut().zip(results) { - *dst = src; - } + fn call_results(self, results: &[UntypedValue]) -> Self::Results { + assert_eq!(self.len(), results.len()); + self.iter_mut().zip(results).for_each(|(dst, src)| { + *dst = src.with_type(dst.value_type()); + }); self } } diff --git a/crates/wasmi/src/func/into_func.rs b/crates/wasmi/src/func/into_func.rs index 079aaaadff..327ea5936e 100644 --- a/crates/wasmi/src/func/into_func.rs +++ b/crates/wasmi/src/func/into_func.rs @@ -69,8 +69,8 @@ macro_rules! impl_into_func { #[allow(non_snake_case)] fn into_func(self) -> (FuncType, HostFuncTrampoline) { let signature = FuncType::new( - ::value_types(), - ::value_types(), + ::types(), + ::types(), ); let trampoline = HostFuncTrampoline::new( move |caller: Caller, params_results: FuncParams| -> Result { @@ -197,31 +197,32 @@ pub trait WasmTypeList: DecodeUntypedSlice + EncodeUntypedSlice + Sized { /// The [`ValueType`] sequence as array. type Types: IntoIterator + AsRef<[ValueType]> - + AsMut<[ValueType]>; + + AsMut<[ValueType]> + + Copy + + Clone; /// The iterator type of the sequence of [`ValueType`]. type TypesIter: ExactSizeIterator + DoubleEndedIterator + FusedIterator; - /// The [`Value`] sequence as array. - type Values: IntoIterator - + AsRef<[Value]> - + AsMut<[Value]>; + type Values: IntoIterator + + AsRef<[UntypedValue]> + + AsMut<[UntypedValue]> + + Copy + + Clone; /// The iterator type of the sequence of [`Value`]. - type ValuesIter: ExactSizeIterator + DoubleEndedIterator + FusedIterator; + type ValuesIter: ExactSizeIterator + DoubleEndedIterator + FusedIterator; /// Returns an array representing the [`ValueType`] sequence of `Self`. - fn value_types() -> Self::Types; + fn types() -> Self::Types; - /// Returns an array representing the [`Value`] sequence of `self`. + /// Returns an array representing the [`UntypedValue`] sequence of `self`. fn values(self) -> Self::Values; - /// Consumes the [`Value`] iterator and creates `Self` if possible. + /// Consumes the [`UntypedValue`] iterator and creates `Self` if possible. /// /// Returns `None` if construction of `Self` is impossible. - fn from_values(values: T) -> Option - where - T: Iterator; + fn from_values(values: &[UntypedValue]) -> Option; } impl WasmTypeList for T1 @@ -232,31 +233,25 @@ where type Types = [ValueType; 1]; type TypesIter = array::IntoIter; - type Values = [Value; 1]; - type ValuesIter = array::IntoIter; + type Values = [UntypedValue; 1]; + type ValuesIter = array::IntoIter; #[inline] - fn value_types() -> Self::Types { + fn types() -> Self::Types { [::value_type()] } #[inline] fn values(self) -> Self::Values { - [>::into(self)] + [>::into(self)] } - fn from_values(mut values: T) -> Option - where - T: Iterator, - { - let value: T1 = values.next().and_then(Value::try_into)?; - if values.next().is_some() { - // Note: If the iterator yielded more items than - // necessary we create no value from this procedure - // as it is likely a bug. - return None; + #[inline] + fn from_values(values: &[UntypedValue]) -> Option { + if let [value] = *values { + return Some(value.into()); } - Some(value) + None } } @@ -272,37 +267,34 @@ macro_rules! impl_wasm_type_list { type Types = [ValueType; $n]; type TypesIter = array::IntoIter; - type Values = [Value; $n]; - type ValuesIter = array::IntoIter; + type Values = [UntypedValue; $n]; + type ValuesIter = array::IntoIter; - fn value_types() -> Self::Types { + #[inline] + fn types() -> Self::Types { [$( <$tuple as WasmType>::value_type() ),*] } + #[inline] #[allow(non_snake_case)] fn values(self) -> Self::Values { let ($($tuple,)*) = self; [$( - <$tuple as Into>::into($tuple) + <$tuple as Into>::into($tuple) ),*] } - fn from_values(mut values: T) -> Option - where - T: Iterator, - { - let result = ($( - values.next().and_then(Value::try_into::<$tuple>)?, - )*); - if values.next().is_some() { - // Note: If the iterator yielded more items than - // necessary we create no value from this procedure - // as it is likely a bug. - return None + #[inline] + #[allow(non_snake_case)] + fn from_values(values: &[UntypedValue]) -> Option { + if let [$($tuple),*] = *values { + return Some( + ( $( Into::into($tuple), )* ) + ) } - Some(result) + None } } }; diff --git a/crates/wasmi/src/func/mod.rs b/crates/wasmi/src/func/mod.rs index df7cacdcdb..63d1cd0566 100644 --- a/crates/wasmi/src/func/mod.rs +++ b/crates/wasmi/src/func/mod.rs @@ -302,6 +302,10 @@ impl Func { if expected_outputs.len() != outputs.len() { return Err(FuncError::MismatchingResults { func: *self }).map_err(Into::into); } + outputs + .iter_mut() + .zip(expected_outputs.iter().copied().map(Value::default)) + .for_each(|(output, expected_output)| *output = expected_output); // Note: Cloning an [`Engine`] is intentionally a cheap operation. ctx.as_context().store.engine().clone().execute_func( ctx.as_context_mut(), diff --git a/crates/wasmi/src/func/typed_func.rs b/crates/wasmi/src/func/typed_func.rs index f6fd9320c1..80f8a2cee4 100644 --- a/crates/wasmi/src/func/typed_func.rs +++ b/crates/wasmi/src/func/typed_func.rs @@ -1,13 +1,12 @@ use super::{into_func::WasmTypeList, Func, FuncError}; use crate::{ - core::Value, engine::{CallParams, CallResults}, AsContext, AsContextMut, Error, }; use core::{fmt, fmt::Debug, marker::PhantomData}; -use wasmi_core::Trap; +use wasmi_core::{Trap, UntypedValue}; /// A typed [`Func`] instance. /// @@ -69,8 +68,8 @@ where let func_type = func.func_type(&ctx); let (expected_params, expected_results) = func_type.params_results(); let (actual_params, actual_results) = ( - ::value_types(), - ::value_types(), + ::types(), + ::types(), ); if actual_params.as_ref() != expected_params { return Err(Error::Func(FuncError::MismatchingParameters { func })); @@ -115,11 +114,8 @@ where { type Params = ::ValuesIter; - fn len_params(&self) -> usize { - ::LEN - } - - fn feed_params(self) -> Self::Params { + #[inline] + fn call_params(self) -> Self::Params { ::values(self).into_iter() } } @@ -159,19 +155,9 @@ where { type Results = Results; - fn len_results(&self) -> usize { - ::LEN - } - - fn feed_results(self, results: T) -> Self::Results - where - T: IntoIterator, - T::IntoIter: ExactSizeIterator, - { - let results = results.into_iter(); - assert_eq!(self.len_results(), results.len()); + fn call_results(self, results: &[UntypedValue]) -> Self::Results { ::from_values(results) - .expect("unable to construct typed results from value iterator") + .expect("unable to construct typed results from call results") } }