mod interpreter;
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", target_os = "linux", target_env = "gnu"),
all(target_arch = "s390x", target_os = "linux", target_env = "gnu")
),
feature = "wasmtime"
))]
mod jit;
mod tests;
use alloc::{string::String, vec::Vec};
use core::{fmt, iter};
use smallvec::SmallVec;
pub struct Config<'a> {
pub module_bytes: &'a [u8],
pub exec_hint: ExecHint,
pub symbols: &'a mut dyn FnMut(&str, &str, &Signature) -> Result<usize, ()>,
}
#[derive(Clone)]
pub struct VirtualMachinePrototype {
inner: VirtualMachinePrototypeInner,
}
#[derive(Clone)]
enum VirtualMachinePrototypeInner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
Jit(jit::JitPrototype),
Interpreter(interpreter::InterpreterPrototype),
}
impl VirtualMachinePrototype {
pub fn new(config: Config) -> Result<Self, NewErr> {
Ok(VirtualMachinePrototype {
inner: match config.exec_hint {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
ExecHint::ValidateAndCompile => VirtualMachinePrototypeInner::Jit(
jit::JitPrototype::new(config.module_bytes, config.symbols)?,
),
#[cfg(not(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
)))]
ExecHint::ValidateAndCompile => VirtualMachinePrototypeInner::Interpreter(
interpreter::InterpreterPrototype::new(
config.module_bytes,
interpreter::CompilationMode::Eager,
config.symbols,
)?,
),
ExecHint::ValidateAndExecuteOnce | ExecHint::Untrusted => {
VirtualMachinePrototypeInner::Interpreter(
interpreter::InterpreterPrototype::new(
config.module_bytes,
interpreter::CompilationMode::Eager,
config.symbols,
)?,
)
}
ExecHint::CompileWithNonDeterministicValidation
| ExecHint::ExecuteOnceWithNonDeterministicValidation => {
VirtualMachinePrototypeInner::Interpreter(
interpreter::InterpreterPrototype::new(
config.module_bytes,
interpreter::CompilationMode::Lazy,
config.symbols,
)?,
)
}
ExecHint::ForceWasmi { lazy_validation } => {
VirtualMachinePrototypeInner::Interpreter(
interpreter::InterpreterPrototype::new(
config.module_bytes,
if lazy_validation {
interpreter::CompilationMode::Lazy
} else {
interpreter::CompilationMode::Eager
},
config.symbols,
)?,
)
}
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
ExecHint::ForceWasmtime => VirtualMachinePrototypeInner::Jit(
jit::JitPrototype::new(config.module_bytes, config.symbols)?,
),
},
})
}
pub fn global_value(&mut self, name: &str) -> Result<u32, GlobalValueErr> {
match &mut self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
VirtualMachinePrototypeInner::Jit(inner) => inner.global_value(name),
VirtualMachinePrototypeInner::Interpreter(inner) => inner.global_value(name),
}
}
pub fn memory_max_pages(&self) -> Option<HeapPages> {
match &self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
VirtualMachinePrototypeInner::Jit(inner) => inner.memory_max_pages(),
VirtualMachinePrototypeInner::Interpreter(inner) => inner.memory_max_pages(),
}
}
pub fn prepare(self) -> Prepare {
match self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
VirtualMachinePrototypeInner::Jit(inner) => Prepare {
inner: PrepareInner::Jit(inner.prepare()),
},
VirtualMachinePrototypeInner::Interpreter(inner) => Prepare {
inner: PrepareInner::Interpreter(inner.prepare()),
},
}
}
}
impl fmt::Debug for VirtualMachinePrototype {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
VirtualMachinePrototypeInner::Jit(inner) => fmt::Debug::fmt(inner, f),
VirtualMachinePrototypeInner::Interpreter(inner) => fmt::Debug::fmt(inner, f),
}
}
}
pub struct Prepare {
inner: PrepareInner,
}
enum PrepareInner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
Jit(jit::Prepare),
Interpreter(interpreter::Prepare),
}
impl Prepare {
pub fn into_prototype(self) -> VirtualMachinePrototype {
VirtualMachinePrototype {
inner: match self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
PrepareInner::Jit(inner) => {
VirtualMachinePrototypeInner::Jit(inner.into_prototype())
}
PrepareInner::Interpreter(inner) => {
VirtualMachinePrototypeInner::Interpreter(inner.into_prototype())
}
},
}
}
pub fn memory_size(&self) -> HeapPages {
match &self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
PrepareInner::Jit(inner) => inner.memory_size(),
PrepareInner::Interpreter(inner) => inner.memory_size(),
}
}
pub fn read_memory(
&self,
offset: u32,
size: u32,
) -> Result<impl AsRef<[u8]>, OutOfBoundsError> {
Ok(match &self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
PrepareInner::Jit(inner) => either::Left(inner.read_memory(offset, size)?),
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
PrepareInner::Interpreter(inner) => either::Right(inner.read_memory(offset, size)?),
#[cfg(not(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
)))]
PrepareInner::Interpreter(inner) => inner.read_memory(offset, size)?,
})
}
pub fn write_memory(&mut self, offset: u32, value: &[u8]) -> Result<(), OutOfBoundsError> {
match &mut self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
PrepareInner::Jit(inner) => inner.write_memory(offset, value),
PrepareInner::Interpreter(inner) => inner.write_memory(offset, value),
}
}
pub fn grow_memory(&mut self, additional: HeapPages) -> Result<(), OutOfBoundsError> {
match &mut self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
PrepareInner::Jit(inner) => inner.grow_memory(additional),
PrepareInner::Interpreter(inner) => inner.grow_memory(additional),
}
}
pub fn start(
self,
function_name: &str,
params: &[WasmValue],
) -> Result<VirtualMachine, (StartErr, VirtualMachinePrototype)> {
Ok(VirtualMachine {
inner: match self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
PrepareInner::Jit(inner) => match inner.start(function_name, params) {
Ok(vm) => VirtualMachineInner::Jit(vm),
Err((err, proto)) => {
return Err((
err,
VirtualMachinePrototype {
inner: VirtualMachinePrototypeInner::Jit(proto),
},
));
}
},
PrepareInner::Interpreter(inner) => match inner.start(function_name, params) {
Ok(vm) => VirtualMachineInner::Interpreter(vm),
Err((err, proto)) => {
return Err((
err,
VirtualMachinePrototype {
inner: VirtualMachinePrototypeInner::Interpreter(proto),
},
));
}
},
},
})
}
}
impl fmt::Debug for Prepare {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
PrepareInner::Jit(inner) => fmt::Debug::fmt(inner, f),
PrepareInner::Interpreter(inner) => fmt::Debug::fmt(inner, f),
}
}
}
pub struct VirtualMachine {
inner: VirtualMachineInner,
}
enum VirtualMachineInner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
Jit(jit::Jit),
Interpreter(interpreter::Interpreter),
}
impl VirtualMachine {
pub fn run(&mut self, value: Option<WasmValue>) -> Result<ExecOutcome, RunErr> {
match &mut self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
VirtualMachineInner::Jit(inner) => inner.run(value),
VirtualMachineInner::Interpreter(inner) => inner.run(value),
}
}
pub fn memory_size(&self) -> HeapPages {
match &self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
VirtualMachineInner::Jit(inner) => inner.memory_size(),
VirtualMachineInner::Interpreter(inner) => inner.memory_size(),
}
}
pub fn read_memory(
&self,
offset: u32,
size: u32,
) -> Result<impl AsRef<[u8]>, OutOfBoundsError> {
Ok(match &self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
VirtualMachineInner::Jit(inner) => either::Left(inner.read_memory(offset, size)?),
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
VirtualMachineInner::Interpreter(inner) => {
either::Right(inner.read_memory(offset, size)?)
}
#[cfg(not(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
)))]
VirtualMachineInner::Interpreter(inner) => inner.read_memory(offset, size)?,
})
}
pub fn write_memory(&mut self, offset: u32, value: &[u8]) -> Result<(), OutOfBoundsError> {
match &mut self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
VirtualMachineInner::Jit(inner) => inner.write_memory(offset, value),
VirtualMachineInner::Interpreter(inner) => inner.write_memory(offset, value),
}
}
pub fn grow_memory(&mut self, additional: HeapPages) -> Result<(), OutOfBoundsError> {
match &mut self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
VirtualMachineInner::Jit(inner) => inner.grow_memory(additional),
VirtualMachineInner::Interpreter(inner) => inner.grow_memory(additional),
}
}
pub fn into_prototype(self) -> VirtualMachinePrototype {
VirtualMachinePrototype {
inner: match self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
VirtualMachineInner::Jit(inner) => {
VirtualMachinePrototypeInner::Jit(inner.into_prototype())
}
VirtualMachineInner::Interpreter(inner) => {
VirtualMachinePrototypeInner::Interpreter(inner.into_prototype())
}
},
}
}
}
impl fmt::Debug for VirtualMachine {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.inner {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
VirtualMachineInner::Jit(inner) => fmt::Debug::fmt(inner, f),
VirtualMachineInner::Interpreter(inner) => fmt::Debug::fmt(inner, f),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ExecHint {
ValidateAndCompile,
CompileWithNonDeterministicValidation,
ValidateAndExecuteOnce,
ExecuteOnceWithNonDeterministicValidation,
Untrusted,
ForceWasmi {
lazy_validation: bool,
},
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
ForceWasmtime,
}
impl ExecHint {
pub fn available_engines() -> impl Iterator<Item = ExecHint> {
iter::once(ExecHint::ForceWasmi {
lazy_validation: false,
})
.chain(Self::force_wasmtime_if_available())
}
pub fn force_wasmtime_if_available() -> Option<ExecHint> {
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
))]
fn value() -> Option<ExecHint> {
Some(ExecHint::ForceWasmtime)
}
#[cfg(not(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
),
feature = "wasmtime"
)))]
fn value() -> Option<ExecHint> {
None
}
value()
}
}
#[derive(
Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, derive_more::Add, derive_more::Sub,
)]
pub struct HeapPages(u32);
impl HeapPages {
pub const fn new(v: u32) -> Self {
HeapPages(v)
}
}
impl From<u32> for HeapPages {
fn from(v: u32) -> Self {
HeapPages(v)
}
}
impl From<HeapPages> for u32 {
fn from(v: HeapPages) -> Self {
v.0
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Signature {
params: SmallVec<[ValueType; 8]>,
ret_ty: Option<ValueType>,
}
#[macro_export]
macro_rules! signature {
(($($param:expr),* $(,)?) => ()) => {
$crate::executor::vm::Signature::from_components(smallvec::smallvec!($($param),*), None)
};
(($($param:expr),* $(,)?) => $ret:expr) => {
$crate::executor::vm::Signature::from_components(smallvec::smallvec!($($param),*), Some($ret))
};
}
impl Signature {
pub fn new(
params: impl Iterator<Item = ValueType>,
ret_ty: impl Into<Option<ValueType>>,
) -> Signature {
Signature {
params: params.collect(),
ret_ty: ret_ty.into(),
}
}
#[doc(hidden)]
pub(crate) fn from_components(
params: SmallVec<[ValueType; 8]>,
ret_ty: Option<ValueType>,
) -> Self {
Signature { params, ret_ty }
}
pub fn parameters(&self) -> impl ExactSizeIterator<Item = &ValueType> {
self.params.iter()
}
pub fn return_type(&self) -> Option<&ValueType> {
self.ret_ty.as_ref()
}
}
impl<'a> From<&'a Signature> for wasmi::FuncType {
fn from(sig: &'a Signature) -> Self {
wasmi::FuncType::new(
sig.params
.iter()
.copied()
.map(wasmi::core::ValType::from)
.collect::<Vec<_>>(),
sig.ret_ty.map(wasmi::core::ValType::from),
)
}
}
impl From<Signature> for wasmi::FuncType {
fn from(sig: Signature) -> wasmi::FuncType {
wasmi::FuncType::from(&sig)
}
}
impl<'a> TryFrom<&'a wasmi::FuncType> for Signature {
type Error = UnsupportedTypeError;
fn try_from(sig: &'a wasmi::FuncType) -> Result<Self, Self::Error> {
if sig.results().len() > 1 {
return Err(UnsupportedTypeError);
}
Ok(Signature {
params: sig
.params()
.iter()
.copied()
.map(ValueType::try_from)
.collect::<Result<_, _>>()?,
ret_ty: sig
.results()
.first()
.copied()
.map(ValueType::try_from)
.transpose()?,
})
}
}
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", target_os = "linux", target_env = "gnu"),
all(target_arch = "s390x", target_os = "linux", target_env = "gnu")
),
feature = "wasmtime"
))]
impl<'a> TryFrom<&'a wasmtime::FuncType> for Signature {
type Error = UnsupportedTypeError;
fn try_from(sig: &'a wasmtime::FuncType) -> Result<Self, Self::Error> {
if sig.results().len() > 1 {
return Err(UnsupportedTypeError);
}
Ok(Signature {
params: sig
.params()
.map(ValueType::try_from)
.collect::<Result<_, _>>()?,
ret_ty: sig.results().next().map(ValueType::try_from).transpose()?,
})
}
}
impl TryFrom<wasmi::FuncType> for Signature {
type Error = UnsupportedTypeError;
fn try_from(sig: wasmi::FuncType) -> Result<Self, Self::Error> {
Signature::try_from(&sig)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum WasmValue {
I32(i32),
I64(i64),
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum ValueType {
I32,
I64,
}
impl WasmValue {
pub fn ty(&self) -> ValueType {
match self {
WasmValue::I32(_) => ValueType::I32,
WasmValue::I64(_) => ValueType::I64,
}
}
pub fn into_i32(self) -> Option<i32> {
if let WasmValue::I32(v) = self {
Some(v)
} else {
None
}
}
pub fn into_i64(self) -> Option<i64> {
if let WasmValue::I64(v) = self {
Some(v)
} else {
None
}
}
}
impl TryFrom<wasmi::Val> for WasmValue {
type Error = UnsupportedTypeError;
fn try_from(val: wasmi::Val) -> Result<Self, Self::Error> {
match val {
wasmi::Val::I32(v) => Ok(WasmValue::I32(v)),
wasmi::Val::I64(v) => Ok(WasmValue::I64(v)),
_ => Err(UnsupportedTypeError),
}
}
}
impl<'a> TryFrom<&'a wasmi::Val> for WasmValue {
type Error = UnsupportedTypeError;
fn try_from(val: &'a wasmi::Val) -> Result<Self, Self::Error> {
match val {
wasmi::Val::I32(v) => Ok(WasmValue::I32(*v)),
wasmi::Val::I64(v) => Ok(WasmValue::I64(*v)),
_ => Err(UnsupportedTypeError),
}
}
}
impl From<WasmValue> for wasmi::Val {
fn from(val: WasmValue) -> Self {
match val {
WasmValue::I32(v) => wasmi::Val::I32(v),
WasmValue::I64(v) => wasmi::Val::I64(v),
}
}
}
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", target_os = "linux", target_env = "gnu"),
all(target_arch = "s390x", target_os = "linux", target_env = "gnu")
),
feature = "wasmtime"
))]
impl From<WasmValue> for wasmtime::Val {
fn from(val: WasmValue) -> Self {
match val {
WasmValue::I32(v) => wasmtime::Val::I32(v),
WasmValue::I64(v) => wasmtime::Val::I64(v),
}
}
}
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", target_os = "linux", target_env = "gnu"),
all(target_arch = "s390x", target_os = "linux", target_env = "gnu")
),
feature = "wasmtime"
))]
impl<'a> TryFrom<&'a wasmtime::Val> for WasmValue {
type Error = UnsupportedTypeError;
fn try_from(val: &'a wasmtime::Val) -> Result<Self, Self::Error> {
match val {
wasmtime::Val::I32(v) => Ok(WasmValue::I32(*v)),
wasmtime::Val::I64(v) => Ok(WasmValue::I64(*v)),
_ => Err(UnsupportedTypeError),
}
}
}
impl From<ValueType> for wasmi::core::ValType {
fn from(ty: ValueType) -> wasmi::core::ValType {
match ty {
ValueType::I32 => wasmi::core::ValType::I32,
ValueType::I64 => wasmi::core::ValType::I64,
}
}
}
impl TryFrom<wasmi::core::ValType> for ValueType {
type Error = UnsupportedTypeError;
fn try_from(val: wasmi::core::ValType) -> Result<Self, Self::Error> {
match val {
wasmi::core::ValType::I32 => Ok(ValueType::I32),
wasmi::core::ValType::I64 => Ok(ValueType::I64),
_ => Err(UnsupportedTypeError),
}
}
}
#[cfg(all(
any(
all(
target_arch = "x86_64",
any(
target_os = "windows",
all(target_os = "linux", target_env = "gnu"),
target_os = "macos"
)
),
all(target_arch = "aarch64", target_os = "linux", target_env = "gnu"),
all(target_arch = "s390x", target_os = "linux", target_env = "gnu")
),
feature = "wasmtime"
))]
impl TryFrom<wasmtime::ValType> for ValueType {
type Error = UnsupportedTypeError;
fn try_from(val: wasmtime::ValType) -> Result<Self, Self::Error> {
match val {
wasmtime::ValType::I32 => Ok(ValueType::I32),
wasmtime::ValType::I64 => Ok(ValueType::I64),
_ => Err(UnsupportedTypeError),
}
}
}
#[derive(Debug, derive_more::Display, derive_more::Error)]
pub struct UnsupportedTypeError;
#[derive(Debug)]
pub enum ExecOutcome {
Finished {
return_value: Result<Option<WasmValue>, Trap>,
},
Interrupted {
id: usize,
params: Vec<WasmValue>,
},
}
#[derive(Debug, derive_more::Display, derive_more::Error, Clone)]
#[display("{_0}")]
pub struct Trap(#[error(not(source))] String);
#[derive(Debug, derive_more::Display, derive_more::Error, Clone)]
pub enum NewErr {
#[display("{_0}")]
InvalidWasm(#[error(not(source))] String),
#[display("{_0}")]
Instantiation(#[error(not(source))] String),
#[display("Unresolved function `{module_name}`:`{function}`")]
UnresolvedFunctionImport {
function: String,
module_name: String,
},
#[display("Start function not supported")]
StartFunctionNotSupported,
#[display("If a \"memory\" symbol is provided, it must be a memory.")]
MemoryIsntMemory,
MemoryNotNamedMemory,
NoMemory,
TwoMemories,
CouldntAllocateMemory,
ImportTypeNotSupported,
}
#[derive(Debug, Clone, derive_more::Display, derive_more::Error)]
pub enum StartErr {
#[display("Function to start was not found.")]
FunctionNotFound,
#[display("Symbol to start is not a function.")]
NotAFunction,
#[display("Function to start uses unsupported signature.")]
SignatureNotSupported,
#[display("The types of the provided parameters don't match the signature.")]
InvalidParameters,
}
#[derive(Debug, derive_more::Display, derive_more::Error)]
#[display("Out of bounds when accessing virtual machine memory")]
pub struct OutOfBoundsError;
#[derive(Debug, derive_more::Display, derive_more::Error)]
pub enum RunErr {
#[display("State machine is poisoned")]
Poisoned,
#[display("Expected value of type {expected:?} but got {obtained:?} instead")]
BadValueTy {
expected: Option<ValueType>,
obtained: Option<ValueType>,
},
}
#[derive(Debug, derive_more::Display, derive_more::Error)]
pub enum GlobalValueErr {
NotFound,
Invalid,
}