summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/tinywasm/src/func.rs50
-rw-r--r--crates/tinywasm/src/instance.rs77
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs2
-rw-r--r--crates/tinywasm/src/reference.rs4
-rw-r--r--crates/tinywasm/src/store/element.rs2
-rw-r--r--crates/tinywasm/src/store/global.rs5
-rw-r--r--crates/tinywasm/src/store/mod.rs78
7 files changed, 110 insertions, 108 deletions
diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs
index 76583f2..9777a47 100644
--- a/crates/tinywasm/src/func.rs
+++ b/crates/tinywasm/src/func.rs
@@ -1,7 +1,7 @@
use crate::interpreter::stack::{CallFrame, ValueStack};
use crate::reference::StoreItem;
use crate::{Error, FunctionInstance, InterpreterRuntime, Result, Store, Trap};
-use alloc::{boxed::Box, format, rc::Rc, sync::Arc, vec, vec::Vec};
+use alloc::{borrow::Cow, boxed::Box, format, rc::Rc, sync::Arc, vec, vec::Vec};
use core::hint::cold_path;
use tinywasm_types::{ExternRef, FuncRef, FuncType, ModuleInstanceAddr, WasmType, WasmValue};
@@ -574,31 +574,30 @@ impl<'store, R: FromWasmValues> FuncExecutionTyped<'store, R> {
/// Describes the WebAssembly value types produced by a Rust value or tuple shape.
pub trait ToWasmTypes {
+ /// Static WebAssembly types for shapes that do not require runtime concatenation.
+ const WASM_TYPES: Option<&'static [WasmType]>;
+
/// Return the flattened WebAssembly value types for this tuple shape.
- fn wasm_types() -> Box<[WasmType]>;
+ fn wasm_types() -> Cow<'static, [WasmType]> {
+ Cow::Borrowed(Self::WASM_TYPES.expect("dynamic ToWasmTypes implementation must override wasm_types"))
+ }
}
/// Describes the WebAssembly value types produced by a scalar Rust type.
pub trait ToWasmType {
- /// Return the single WebAssembly value type for this scalar type.
- fn wasm_type() -> WasmType;
+ /// The single WebAssembly value type for this scalar type.
+ const WASM_TYPE: WasmType;
}
macro_rules! impl_scalar_wasm_traits {
($($T:ty => $val_ty:ident),+ $(,)?) => {
$(
impl ToWasmType for $T {
- #[inline]
- fn wasm_type() -> WasmType {
- WasmType::$val_ty
- }
+ const WASM_TYPE: WasmType = WasmType::$val_ty;
}
impl ToWasmTypes for $T {
- #[inline]
- fn wasm_types() -> Box<[WasmType]> {
- Box::new([WasmType::$val_ty])
- }
+ const WASM_TYPES: Option<&'static [WasmType]> = Some(&[WasmType::$val_ty]);
}
impl IntoWasmValues for $T {
@@ -611,9 +610,16 @@ macro_rules! impl_scalar_wasm_traits {
impl FromWasmValues for $T {
#[inline]
fn from_wasm_values(values: &[WasmValue]) -> Result<Self> {
- let value = *values.first().ok_or(Error::other("Not enough elemennts in &[WasmValue]"))?;
+ let value = *values.first().ok_or_else(|| {
+ core::hint::cold_path();
+ Error::other("Not enough elements in &[WasmValue]")
+ })?;
+
<$T>::try_from(value).map_err(|e| {
- Error::Other(format!("FromWasmValues: Could not convert WasmValue to expected type: {e:?}"))
+ core::hint::cold_path();
+ Error::Other(format!(
+ "FromWasmValues: Could not convert WasmValue to expected type: {e:?}"
+ ))
})
}
}
@@ -627,10 +633,7 @@ macro_rules! impl_tuple_traits {
where
$($T: ToWasmType,)+
{
- #[inline]
- fn wasm_types() -> Box<[WasmType]> {
- Box::new([$($T::wasm_type(),)+])
- }
+ const WASM_TYPES: Option<&'static [WasmType]> = Some(&[$($T::WASM_TYPE,)+]);
}
impl<$($T),+> IntoWasmValues for ($($T,)+)
@@ -757,12 +760,14 @@ impl<T1, T2> From<(T1, T2)> for WasmTupleChain<T1, T2> {
}
impl<T1: ToWasmTypes, T2: ToWasmTypes> ToWasmTypes for WasmTupleChain<T1, T2> {
+ const WASM_TYPES: Option<&'static [WasmType]> = None;
+
#[inline]
- fn wasm_types() -> Box<[WasmType]> {
+ fn wasm_types() -> Cow<'static, [WasmType]> {
let mut types = Vec::new();
types.extend_from_slice(&T1::wasm_types());
types.extend_from_slice(&T2::wasm_types());
- types.into_boxed_slice()
+ Cow::Owned(types)
}
}
@@ -788,10 +793,7 @@ impl<T1: FromWasmValues + ToWasmTypes, T2: FromWasmValues> FromWasmValues for Wa
}
impl ToWasmTypes for () {
- #[inline]
- fn wasm_types() -> Box<[WasmType]> {
- Box::new([])
- }
+ const WASM_TYPES: Option<&'static [WasmType]> = Some(&[]);
}
impl IntoWasmValues for () {
diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs
index a8cf14a..8cff310 100644
--- a/crates/tinywasm/src/instance.rs
+++ b/crates/tinywasm/src/instance.rs
@@ -210,25 +210,23 @@ impl ModuleInstance {
let instance = ModuleInstance(Rc::new(instance));
store.add_instance(instance.clone());
- match (elem_trapped, data_trapped) {
- (Some(trap), _) | (_, Some(trap)) => {
- cold_path();
- Err(trap.into())
- }
- _ => Ok(instance),
+ if let Some(trap) = elem_trapped.or(data_trapped) {
+ cold_path();
+ return Err(trap.into());
}
+ Ok(instance)
}
/// Get a export by name
pub fn export_addr(&self, name: &str) -> Option<ExternVal> {
- let exports = self.0.exports.iter().find(|e| *e.name == *name)?;
- let addr = match exports.kind {
- ExternalKind::Func => self.0.func_addrs.get(exports.index as usize)?,
- ExternalKind::Table => self.0.table_addrs.get(exports.index as usize)?,
- ExternalKind::Memory => self.0.mem_addrs.get(exports.index as usize)?,
- ExternalKind::Global => self.0.global_addrs.get(exports.index as usize)?,
+ let export = self.0.exports.iter().find(|e| *e.name == *name)?;
+ let addr = match export.kind {
+ ExternalKind::Func => self.0.func_addrs.get(export.index as usize)?,
+ ExternalKind::Table => self.0.table_addrs.get(export.index as usize)?,
+ ExternalKind::Memory => self.0.mem_addrs.get(export.index as usize)?,
+ ExternalKind::Global => self.0.global_addrs.get(export.index as usize)?,
};
- Some(ExternVal::new(exports.kind, *addr))
+ Some(ExternVal::new(export.kind, *addr))
}
/// Returns an iterator over all exported extern values for this instance.
@@ -288,25 +286,19 @@ impl ModuleInstance {
#[inline]
fn require_export(&self, name: &str) -> Result<ExternVal> {
- match self.export_addr(name) {
- Some(addr) => Ok(addr),
- None => {
- cold_path();
- Err(Error::Other(format!("Export not found: {name}")))
- }
- }
+ self.export_addr(name).ok_or_else(|| {
+ cold_path();
+ Error::Other(format!("Export not found: {name}"))
+ })
}
#[inline]
#[cfg(feature = "guest-debug")]
fn index_addr<T: Copy>(slice: &[T], idx: u32, kind: &str) -> Result<T> {
- match slice.get(idx as usize) {
- Some(addr) => Ok(*addr),
- None => {
- cold_path();
- Err(Error::Other(format!("{kind} index out of bounds: {idx}")))
- }
- }
+ slice.get(idx as usize).copied().ok_or_else(|| {
+ cold_path();
+ Error::Other(format!("{kind} index out of bounds: {idx}"))
+ })
}
/// Get any exported extern value by name.
@@ -376,12 +368,9 @@ impl ModuleInstance {
pub fn func_untyped(&self, store: &Store, name: &str) -> Result<Function> {
self.validate_store(store)?;
- let func_addr = match self.require_export(name)? {
- ExternVal::Func(func_addr) => func_addr,
- _ => {
- cold_path();
- return Err(Error::Other(format!("Export is not a function: {name}")));
- }
+ let ExternVal::Func(func_addr) = self.require_export(name)? else {
+ cold_path();
+ return Err(Error::Other(format!("Export is not a function: {name}")));
};
Ok(Function {
@@ -444,7 +433,20 @@ impl ModuleInstance {
store: &Store,
name: &str,
) -> Result<FunctionTyped<P, R>> {
- let func = self.func_untyped(store, name)?;
+ self.validate_store(store)?;
+
+ let ExternVal::Func(func_addr) = self.require_export(name)? else {
+ cold_path();
+ return Err(Error::Other(format!("Export is not a function: {name}")));
+ };
+
+ let func = Function {
+ item: StoreItem::new(self.0.store_id, func_addr),
+ addr: func_addr,
+ module_addr: self.id(),
+ ty: store.state.get_func(func_addr).ty().clone(),
+ };
+
Self::validate_typed_func::<P, R>(&func, name)?;
Ok(FunctionTyped { func, marker: core::marker::PhantomData })
}
@@ -462,14 +464,17 @@ impl ModuleInstance {
Ok(FunctionTyped { func, marker: core::marker::PhantomData })
}
+ #[inline]
fn validate_typed_func<P: ToWasmTypes, R: ToWasmTypes>(func: &Function, func_name: &str) -> Result<()> {
- if *func.ty.params() != *P::wasm_types() || *func.ty.results() != *R::wasm_types() {
+ let params = P::wasm_types();
+ let results = R::wasm_types();
+ if func.ty.params() != params.as_ref() || func.ty.results() != results.as_ref() {
cold_path();
#[cfg(feature = "debug")]
return Err(Error::Other(format!(
"function type mismatch for {func_name}: expected {:?}, actual {:?}",
- FuncType::new(&P::wasm_types(), &R::wasm_types()),
+ FuncType::new(&params, &results),
func.ty
)));
diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs
index 0405546..e4bb6c5 100644
--- a/crates/tinywasm/src/interpreter/executor.rs
+++ b/crates/tinywasm/src/interpreter/executor.rs
@@ -1497,8 +1497,6 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
let dst = self.pop_table_operand(self.store.state.get_table(table_addr).kind.arch())?; // d
let elem_addr = self.module.resolve_elem_addr(elem_index) as usize;
let elem = self.store.state.elements.get(elem_addr).ok_or_else(|| Trap::Other("element not found"))?;
- // Element kind storage is removed separately; table.init only depends on retained items.
- let _ = &elem.kind;
let items = elem.items.as_deref().unwrap_or(&[]);
let Some(end) = offset.checked_add(size) else {
cold_path();
diff --git a/crates/tinywasm/src/reference.rs b/crates/tinywasm/src/reference.rs
index b8a1aa1..e46db51 100644
--- a/crates/tinywasm/src/reference.rs
+++ b/crates/tinywasm/src/reference.rs
@@ -446,7 +446,7 @@ impl Global {
/// Get the current value of the global.
pub fn get(&self, store: &Store) -> Result<WasmValue> {
let global = self.instance(store)?;
- let value = global.value.get().attach_type(global.ty.ty);
+ let value = global.value.attach_type(global.ty.ty);
Ok(value.unwrap_or_else(|| unreachable!("Global value type does not match global type, this is a bug")))
}
@@ -461,7 +461,7 @@ impl Global {
cold_path();
return Err(Error::Other("invalid global value type".to_string()));
}
- global.value.set(value.into());
+ global.value = value.into();
Ok(())
}
}
diff --git a/crates/tinywasm/src/store/element.rs b/crates/tinywasm/src/store/element.rs
index 940a6de..f3a8602 100644
--- a/crates/tinywasm/src/store/element.rs
+++ b/crates/tinywasm/src/store/element.rs
@@ -1,13 +1,11 @@
use crate::TableElement;
use alloc::vec::Vec;
-use tinywasm_types::*;
/// A WebAssembly Element Instance
///
/// See <https://webassembly.github.io/spec/core/exec/runtime.html#element-instances>
#[cfg_attr(feature = "debug", derive(Debug))]
pub(crate) struct ElementInstance {
- pub(crate) kind: ElementKind,
pub(crate) items: Option<Vec<TableElement>>, // none is the element was dropped
}
diff --git a/crates/tinywasm/src/store/global.rs b/crates/tinywasm/src/store/global.rs
index 95af73f..9280494 100644
--- a/crates/tinywasm/src/store/global.rs
+++ b/crates/tinywasm/src/store/global.rs
@@ -1,5 +1,4 @@
use crate::interpreter::TinyWasmValue;
-use core::cell::Cell;
use tinywasm_types::*;
/// A WebAssembly Global Instance
@@ -7,12 +6,12 @@ use tinywasm_types::*;
/// See <https://webassembly.github.io/spec/core/exec/runtime.html#global-instances>
#[cfg_attr(feature = "debug", derive(Debug))]
pub(crate) struct GlobalInstance {
- pub(crate) value: Cell<TinyWasmValue>,
+ pub(crate) value: TinyWasmValue,
pub(crate) ty: GlobalType,
}
impl GlobalInstance {
pub(crate) fn new(ty: GlobalType, value: TinyWasmValue) -> Self {
- Self { ty, value: value.into() }
+ Self { ty, value }
}
}
diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs
index 875980a..1723bfe 100644
--- a/crates/tinywasm/src/store/mod.rs
+++ b/crates/tinywasm/src/store/mod.rs
@@ -85,7 +85,10 @@ impl Store {
#[inline]
pub(crate) fn get_module_instance_internal(&self, addr: ModuleInstanceAddr) -> ModuleInstance {
- self.get_module_instance(addr).unwrap_or_else(|| unreachable!("invalid module instance: {addr}"))
+ self.module_instances
+ .get(addr as usize)
+ .unwrap_or_else(|| unreachable!("invalid module instance: {addr}"))
+ .clone()
}
pub(crate) fn enter_execution(&mut self) -> Result<()> {
@@ -215,12 +218,12 @@ impl State {
/// Get the global at the actual index in the store
pub(crate) fn get_global_val(&self, addr: GlobalAddr) -> TinyWasmValue {
- self.get_global(addr).value.get()
+ self.get_global(addr).value
}
/// Set the global at the actual index in the store
pub(crate) fn set_global_val(&mut self, addr: GlobalAddr, value: TinyWasmValue) {
- self.get_global_mut(addr).value.set(value);
+ self.get_global_mut(addr).value = value;
}
}
@@ -300,14 +303,13 @@ impl Store {
pub(crate) fn init_globals(
&mut self,
out: &mut Vec<Addr>,
- new_globals: &[Global],
+ globals: &[Global],
func_addrs: &[FuncAddr],
) -> Result<()> {
let start = self.state.globals.len() as Addr;
- out.reserve_exact(new_globals.len());
- self.state.globals.reserve_exact(new_globals.len());
+ out.extend(start..start + globals.len() as Addr);
- for (i, global) in new_globals.iter().enumerate() {
+ for global in globals {
let value = match self.eval_const(&global.init, out, func_addrs) {
Ok(val) => val,
Err(e) => {
@@ -315,29 +317,31 @@ impl Store {
return Err(e);
}
};
-
self.state.globals.push(GlobalInstance::new(global.ty, value));
- out.push(start + i as Addr);
}
Ok(())
}
fn elem_addr(&self, item: &ElementItem, globals: &[Addr], funcs: &[FuncAddr]) -> Result<Option<u32>> {
- let res = match item {
+ match item {
+ ElementItem::Expr(expr) => match self.eval_const(expr, globals, funcs)? {
+ TinyWasmValue::ValueRef(v) => Ok(v.addr()),
+ other => {
+ cold_path();
+ Err(Error::Other(format!("expected ref type, got {other:?}")))
+ }
+ },
ElementItem::Func(addr) => match funcs.get(*addr as usize) {
- Some(func_addr) => Some(*func_addr),
+ Some(func_addr) => Ok(Some(*func_addr)),
None => {
cold_path();
- return Err(Error::Other(format!(
+ Err(Error::Other(format!(
"function {addr} not found. This should have been caught by the validator"
- )));
+ )))
}
},
- ElementItem::Expr(expr) => self.eval_ref_const(expr, globals, funcs)?,
- };
-
- Ok(res)
+ }
}
/// Add elements to the store, returning their addresses in the store
@@ -398,7 +402,7 @@ impl Store {
}
};
- self.state.elements.push(ElementInstance { kind: element.kind.clone(), items });
+ self.state.elements.push(ElementInstance { items });
elem_addrs.push((i + elem_count) as Addr);
}
@@ -428,13 +432,14 @@ impl Store {
return Err(Error::Other(format!("memory {mem_addr} not found for data segment {i}")));
};
- match mem.inner.write_all(offset as usize, &data.data) {
+ let offset = usize::try_from(offset).unwrap_or(usize::MAX);
+ match mem.inner.write_all(offset, &data.data) {
Some(()) => None,
None => {
return Ok((
data_addrs.into_boxed_slice(),
Some(crate::Trap::MemoryOutOfBounds {
- offset: offset as usize,
+ offset,
len: data.data.len(),
max: mem.inner.len(),
}),
@@ -474,6 +479,7 @@ impl Store {
}
/// Evaluate a constant expression
+ #[inline]
fn eval_const(
&self,
const_instrs: &[tinywasm_types::ConstInstruction],
@@ -495,12 +501,12 @@ impl Store {
return Err(Error::Other(format!("global {addr} not found")));
};
- Ok(global.value.get())
+ Ok(global.value)
};
let resolve_func = |idx: u32| -> Result<u32> {
- match module_func_addrs.get(idx as usize).copied() {
- Some(func_addr) => Ok(func_addr),
+ match module_func_addrs.get(idx as usize) {
+ Some(func_addr) => Ok(*func_addr),
None => {
cold_path();
Err(Error::Other(format!(
@@ -530,7 +536,7 @@ impl Store {
return Ok(val);
}
- let mut stack = Vec::with_capacity(const_instrs.len());
+ let mut stack = Vec::new();
for instr in const_instrs {
match instr {
I32Const(i) => stack.push(TinyWasmValue::Value32(*i as u32)),
@@ -560,7 +566,10 @@ impl Store {
I32Add => lhs.wrapping_add(rhs),
I32Sub => lhs.wrapping_sub(rhs),
I32Mul => lhs.wrapping_mul(rhs),
- _ => unreachable!("invalid const instruction in i32 op"),
+ _ => {
+ cold_path();
+ return Err(Error::other("invalid const instruction in i32 op"));
+ }
};
stack.push(TinyWasmValue::Value32(out as u32));
}
@@ -578,7 +587,10 @@ impl Store {
I64Add => lhs.wrapping_add(rhs),
I64Sub => lhs.wrapping_sub(rhs),
I64Mul => lhs.wrapping_mul(rhs),
- _ => unreachable!("invalid const instruction in i64 op"),
+ _ => {
+ cold_path();
+ return Err(Error::other("invalid const instruction in i64 op"));
+ }
};
stack.push(TinyWasmValue::Value64(out as u64));
}
@@ -594,19 +606,7 @@ impl Store {
cold_path();
return Err(Error::other("const expression did not reduce to single value"));
}
- Ok(value)
- }
- fn eval_ref_const(
- &self,
- const_instrs: &[tinywasm_types::ConstInstruction],
- module_global_addrs: &[Addr],
- module_func_addrs: &[FuncAddr],
- ) -> Result<Option<u32>> {
- let value = self.eval_const(const_instrs, module_global_addrs, module_func_addrs)?;
- match value {
- TinyWasmValue::ValueRef(v) => Ok(v.addr()),
- other => Err(Error::Other(format!("expected reference const value, got {other:?}"))),
- }
+ Ok(value)
}
}