feat!: decouple wasmer from Marine, replace it with generic backend interface (#219)

This commit is contained in:
Valery Antopol
2023-03-15 00:43:51 +03:00
committed by GitHub
parent b0e9b2c104
commit d3a773df4f
157 changed files with 5375 additions and 2179 deletions

View File

@ -0,0 +1,36 @@
/*
* Copyright 2023 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::AsContextMut;
use crate::FuncGetter;
use crate::WasmBackend;
/// `Caller` is a structure used to pass context to imports.
/// It serves as a handle to `Store`, and also provides access to `Memory` and export functions
/// from the caller instance, if there is one.
pub trait Caller<WB: WasmBackend>:
FuncGetter<WB, (i32, i32), i32>
+ FuncGetter<WB, (i32, i32), ()>
+ FuncGetter<WB, i32, i32>
+ FuncGetter<WB, i32, ()>
+ FuncGetter<WB, (), i32>
+ FuncGetter<WB, (), ()>
+ AsContextMut<WB>
{
/// Gets the `Memory` from the caller instance.
/// Returns `None` if function was called directly from host.
fn memory(&mut self, memory_index: u32) -> Option<<WB as WasmBackend>::Memory>;
}

View File

@ -0,0 +1,145 @@
/*
* Copyright 2023 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::WType;
use thiserror::Error;
pub type WasmBackendResult<T> = Result<T, WasmBackendError>;
pub type ResolveResult<T> = Result<T, ResolveError>;
pub type RuntimeResult<T> = Result<T, RuntimeError>;
pub type ModuleCreationResult<T> = Result<T, ModuleCreationError>;
pub type InstantiationResult<T> = Result<T, InstantiationError>;
pub type WasiResult<T> = Result<T, WasiError>;
/*
General error design goals:
* expose as much detail as possible
* make as much domain-specific errors as possible implementation-independent
So, Error enums should follow this principle:
* errors fully expressible without implementation info should have implementation-independent view
* errors not fully expressible without implementation info should have some common view and a way to get implmententation-specific details
* "Other" type for all errors not suited for listed options
*/
#[derive(Debug, Error)]
pub enum WasmBackendError {
#[error(transparent)]
ResolveError(#[from] ResolveError),
#[error(transparent)]
RuntimeError(#[from] RuntimeError),
#[error(transparent)]
ModuleCreationError(#[from] ModuleCreationError),
#[error(transparent)]
ImportError(#[from] ImportError),
#[error(transparent)]
InstantiationError(#[from] InstantiationError),
#[error(transparent)]
InitializationError(anyhow::Error),
}
#[derive(Debug, Error)]
pub enum ResolveError {
#[error("export not found: {0}")]
ExportNotFound(String),
#[error("export type mismatch: expected {expected}, found {actual}")]
ExportTypeMismatch {
expected: &'static str,
actual: &'static str,
},
#[error(transparent)]
Other(#[from] anyhow::Error),
}
#[derive(Debug, Error)]
pub enum RuntimeError {
#[error("Unsupported type encountered: {0}")]
UnsupportedType(WType),
#[error(transparent)]
Trap(anyhow::Error),
#[error(transparent)]
UserError(#[from] UserError),
#[error("A function returned invalid number of results: expected {expected}, got {actual}")]
IncorrectResultsNumber { expected: usize, actual: usize },
#[error(transparent)]
Other(anyhow::Error),
}
#[derive(Debug, Error)]
pub enum ModuleCreationError {
#[error(transparent)]
FailedToCompileWasm(anyhow::Error),
#[error("{0}")]
FailedToExtractCustomSections(String), // TODO: use a proper error type
#[error(transparent)]
Other(anyhow::Error),
}
#[derive(Debug, Error)]
pub enum ImportError {
#[error("Duplicate import")]
DuplicateImport(String, String),
#[error(transparent)]
Other(#[from] anyhow::Error),
}
#[derive(Debug, Error)]
pub enum InstantiationError {
#[error(transparent)]
RuntimeError(RuntimeError),
#[error(transparent)]
Other(#[from] anyhow::Error),
}
#[derive(Debug, Error)]
pub enum WasiError {
#[error(transparent)]
IOError(#[from] std::io::Error),
#[error(transparent)]
EngineWasiError(#[from] anyhow::Error),
#[error("Cumulative size of args array exceeds 2^32")]
TooLargeArgsArray,
#[error("Cumulative size of envs array exceeds 2^32")]
TooLargeEnvsArray,
}
#[derive(Debug, Error)]
pub enum UserError {
#[error(transparent)]
Recoverable(anyhow::Error),
#[error(transparent)]
Unrecoverable(anyhow::Error),
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2023 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pub static STANDARD_MEMORY_EXPORT_NAME: &str = "memory";
pub static STANDARD_MEMORY_INDEX: u32 = 0;
use crate::DelayedContextLifetime;
use crate::WasmBackend;
/// Contains Wasm exports necessary for internal usage.
pub enum Export<WB: WasmBackend> {
Memory(<WB as WasmBackend>::Memory),
Function(<WB as WasmBackend>::Function),
Other,
}
// TODO: add read/write/etc methods to the `Memory` trait,
// and then make a generic implementation of interface-types traits
/// A wasm memory handle.
/// As it is only a handle to an object in `Store`, cloning is cheap.
pub trait Memory<WB: WasmBackend>:
it_memory_traits::Memory<<WB as WasmBackend>::MemoryView, DelayedContextLifetime<WB>>
+ Clone
+ Send
+ Sync
+ 'static
{
/// Get the size of the allocated memory in bytes.
fn size(&self, store: &mut <WB as WasmBackend>::ContextMut<'_>) -> usize;
}

View File

@ -0,0 +1,169 @@
/*
* Copyright 2023 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::AsContextMut;
use crate::FuncSig;
use crate::impl_for_each_function_signature;
use crate::RuntimeResult;
use crate::WasmBackend;
use crate::WValue;
/// A Wasm function handle, it can be either a function from a host or an export from an `Instance`.
/// As it is only a handle to an object in `Store`, cloning is cheap
pub trait Function<WB: WasmBackend>: Send + Sync {
/// Creates a new function with dynamic signature.
/// The signature check is performed at runtime.
fn new<F>(store: &mut impl AsContextMut<WB>, sig: FuncSig, func: F) -> Self
where
F: for<'c> Fn(&[WValue]) -> Vec<WValue> + Sync + Send + 'static;
/// Creates a new function with dynamic signature that needs a context.
fn new_with_caller<F>(store: &mut impl AsContextMut<WB>, sig: FuncSig, func: F) -> Self
where
F: for<'c> Fn(<WB as WasmBackend>::Caller<'c>, &[WValue]) -> Vec<WValue>
+ Sync
+ Send
+ 'static;
/// Creates a new function with static signature.
/// Requires less runtime checks when called.
fn new_typed<Params, Results, Env>(
store: &mut impl AsContextMut<WB>,
func: impl IntoFunc<WB, Params, Results, Env>,
) -> Self;
/// Returns the signature of the function.
/// The signature is constructed each time this function is called, so
/// it is not recommended to use this function extensively.
fn signature(&self, store: &mut impl AsContextMut<WB>) -> FuncSig;
/// Calls the wasm function.
/// # Panics:
/// If given a store different from the one that stores the function.
/// # Errors:
/// See `RuntimeError` documentation.
fn call(
&self,
store: &mut impl AsContextMut<WB>,
args: &[WValue],
) -> RuntimeResult<Vec<WValue>>;
}
/// A helper trait for creating a function with a static signature.
/// Should not be implemented by users.
/// Implemented for all functions that meet the following criteria:
/// * implement Send + Sync + 'static
/// * take or not take Caller as first parameter
/// * take from 0 to 16 i32 parameters
/// * return () or i32
pub trait IntoFunc<WB: WasmBackend, Params, Results, Env> {
fn into_func(self, ctx: &mut impl AsContextMut<WB>) -> <WB as WasmBackend>::Function;
}
/// An indicator of using Caller argument.
pub struct WithEnv {}
/// An indicator of using Caller argument.
pub struct WithoutEnv {}
#[macro_export]
macro_rules! replace_with {
($from:ident -> $to:ident) => {
$to
};
}
macro_rules! impl_into_func {
($num:tt $($args:ident)*) => (paste::paste!{
#[allow(non_snake_case)]
impl<WB, F> IntoFunc<WB, ($(replace_with!($args -> i32),)*), (), WithoutEnv> for F
where
WB: WasmBackend,
F: Fn($(replace_with!($args -> i32),)*) + Send + Sync + 'static,
{
fn into_func(self, ctx: &mut impl AsContextMut<WB>) -> <WB as WasmBackend>::Function {
<WB as WasmBackend>::Function:: [< new_typed_ $num >] (ctx.as_context_mut(), self)
}
}
#[allow(non_snake_case)]
impl<WB, F> IntoFunc<WB, ($(replace_with!($args -> i32),)*), (), WithEnv> for F
where
WB: WasmBackend,
F: Fn(<WB as WasmBackend>::Caller<'_>, $(replace_with!($args -> i32),)*) + Send + Sync + 'static,
{
fn into_func(self, ctx: &mut impl AsContextMut<WB>) -> <WB as WasmBackend>::Function {
<WB as WasmBackend>::Function:: [< new_typed_with_env_ $num >] (ctx.as_context_mut(), self)
}
}
#[allow(non_snake_case)]
impl<WB, F> IntoFunc<WB, ($(replace_with!($args -> i32),)*), i32, WithoutEnv> for F
where
WB: WasmBackend,
F: Fn($(replace_with!($args -> i32),)*) -> i32 + Send + Sync + 'static,
{
fn into_func(self, ctx: &mut impl AsContextMut<WB>) -> <WB as WasmBackend>::Function {
<WB as WasmBackend>::Function:: [< new_typed_ $num _r >] (ctx.as_context_mut(), self)
}
}
#[allow(non_snake_case)]
impl<WB, F> IntoFunc<WB, ($(replace_with!($args -> i32),)*), i32, WithEnv> for F
where
WB: WasmBackend,
F: Fn(<WB as WasmBackend>::Caller<'_>, $(replace_with!($args -> i32),)*) -> i32 + Send + Sync + 'static,
{
fn into_func(self, ctx: &mut impl AsContextMut<WB>) -> <WB as WasmBackend>::Function {
<WB as WasmBackend>::Function:: [< new_typed_with_env_ $num _r >] (ctx.as_context_mut(), self)
}
}
});
}
impl_for_each_function_signature!(impl_into_func);
macro_rules! declare_func_construction {
($num:tt $($args:ident)*) => (paste::paste!{
#[allow(non_snake_case)]
fn [< new_typed_ $num >]<F>(ctx: <WB as WasmBackend>::ContextMut<'_>, func: F) -> <WB as WasmBackend>::Function
where F: Fn($(replace_with!($args -> i32),)*) + Send + Sync + 'static
{
let func = move |_: <WB as WasmBackend>::Caller<'_>, $($args,)*| { func($($args,)*)};
Self:: [< new_typed_with_env_ $num >] (ctx, func)
}
#[allow(non_snake_case)]
fn [< new_typed_with_env_ $num >]<F>(ctx: <WB as WasmBackend>::ContextMut<'_>, func: F) -> <WB as WasmBackend>::Function
where F: Fn(<WB as WasmBackend>::Caller<'_>, $(replace_with!($args -> i32),)*) + Send + Sync + 'static;
#[allow(non_snake_case)]
fn [< new_typed_ $num _r>]<F>(ctx: <WB as WasmBackend>::ContextMut<'_>, func: F) -> <WB as WasmBackend>::Function
where F: Fn($(replace_with!($args -> i32),)*) -> i32 + Send + Sync + 'static
{
let func = move |_: <WB as WasmBackend>::Caller<'_>, $($args,)*| -> i32 { func($($args,)*)};
Self:: [< new_typed_with_env_ $num _r >] (ctx, func)
}
#[allow(non_snake_case)]
fn [< new_typed_with_env_ $num _r>]<F>(ctx: <WB as WasmBackend>::ContextMut<'_>, func: F) -> <WB as WasmBackend>::Function
where F: Fn(<WB as WasmBackend>::Caller<'_>, $(replace_with!($args -> i32),)*) -> i32 + Send + Sync + 'static;
});
}
pub trait FuncConstructor<WB: WasmBackend> {
impl_for_each_function_signature!(declare_func_construction);
}

View File

@ -0,0 +1,24 @@
pub use multimap::MultiMap;
pub fn custom_sections(bytes: &[u8]) -> Result<MultiMap<String, Vec<u8>>, String> {
use wasmparser::Parser;
use wasmparser::Payload;
Parser::new(0)
.parse_all(bytes)
.filter_map(|payload| {
let payload = match payload {
Ok(payload) => payload,
Err(e) => return Some(Err(e.to_string())),
};
match payload {
Payload::CustomSection(reader) => {
let name = reader.name().to_string();
let data = reader.data().to_vec();
Some(Ok((name, data)))
}
_ => None,
}
})
.collect()
}

View File

@ -0,0 +1,95 @@
/*
* Copyright 2023 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::errors::*;
use crate::AsContext;
use crate::WasmBackend;
use crate::WType;
use std::borrow::Cow;
/// A "Linker" object, that is used to match functions with module imports during instantiation.
/// Cloning is a cheap operation for this object. All clones refer to the same data in store.
pub trait Imports<WB: WasmBackend>: Clone {
/// Creates a new empty object.
fn new(store: &mut <WB as WasmBackend>::Store) -> Self;
/// Inserts a function with name `name` to the namespace `module`.
/// # Errors:
/// An error returned if such combination of `module` and `name` already has an associated function.
fn insert(
&mut self,
store: &impl AsContext<WB>,
module: impl Into<String>,
name: impl Into<String>,
func: <WB as WasmBackend>::Function,
) -> Result<(), ImportError>;
/// Inserts several named functions to the same namespace `module` at once, an equivalent to multiple calls of `insert`.
/// # Errors:
/// An error returned if such combination of `module` and `name` already has an associated function.
///
fn register<S, I>(
&mut self,
store: &impl AsContext<WB>,
name: S,
namespace: I,
) -> Result<(), ImportError>
where
S: Into<String>,
I: IntoIterator<Item = (String, <WB as WasmBackend>::Function)>;
}
/// A type representing function signature.
#[derive(Clone)]
pub struct FuncSig {
params: Cow<'static, [WType]>,
returns: Cow<'static, [WType]>,
}
impl FuncSig {
pub fn new<Params, Returns>(params: Params, returns: Returns) -> Self
where
Params: Into<Cow<'static, [WType]>>,
Returns: Into<Cow<'static, [WType]>>,
{
Self {
params: params.into(),
returns: returns.into(),
}
}
pub fn params(&self) -> &[WType] {
&self.params
}
pub fn returns(&self) -> &[WType] {
&self.returns
}
}
pub type FuncFromCaller<WB, Args, Rets> = Box<
dyn FnMut(&mut <WB as WasmBackend>::ContextMut<'_>, Args) -> RuntimeResult<Rets>
+ Sync
+ Send
+ 'static,
>;
pub trait FuncGetter<WB: WasmBackend, Args, Rets> {
/// Gets an export function from the calling instance.
fn get_func(&mut self, name: &str) -> ResolveResult<FuncFromCaller<WB, Args, Rets>>;
}

View File

@ -0,0 +1,56 @@
/*
* Copyright 2023 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::AsContextMut;
use crate::Export;
use crate::ResolveResult;
use crate::WasmBackend;
/// A handle to an instantiated Wasm module. Cloning is cheap.
pub trait Instance<WB: WasmBackend>: Clone {
/// Returns an `Iterator` to all exports of this instance.
fn export_iter<'a>(
&'a self,
store: <WB as WasmBackend>::ContextMut<'a>,
) -> Box<dyn Iterator<Item = (&'a str, Export<WB>)> + 'a>;
/// Returns nth exported memory, None if there is no nth memory.
/// No guaranties is known for memory order, but almost always a module has only one memory,
/// hence the only valid value for `memory_index` is 0.
fn get_nth_memory(
&self,
store: &mut impl AsContextMut<WB>,
memory_index: u32, // TODO: refactor memory indexing with enums
) -> Option<<WB as WasmBackend>::Memory>;
/// Returns a memory export with given name.
/// # Errors:
/// Returns an error if there is no export with such name, or it is not a memory.
fn get_memory(
&self,
store: &mut impl AsContextMut<WB>,
memory_name: &str,
) -> ResolveResult<<WB as WasmBackend>::Memory>;
/// Returns an exported function with the given name.
/// # Errors:
/// Returns an error if there is no export with such name, or it is not a function.
fn get_function(
&self,
store: &mut impl AsContextMut<WB>,
name: &str,
) -> ResolveResult<<WB as WasmBackend>::Function>;
}

View File

@ -0,0 +1,96 @@
/*
* Copyright 2023 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pub mod errors;
pub mod exports;
pub mod imports;
pub mod store;
pub mod wasi;
pub mod wtype;
pub mod module;
pub mod instance;
pub mod caller;
pub mod function;
pub mod macros;
/// Helper functions for backend implementations.
pub mod impl_utils;
pub mod prelude {
pub use crate::errors::*;
pub use crate::exports::*;
pub use crate::imports::*;
pub use crate::store::*;
pub use crate::wasi::*;
pub use crate::wtype::*;
pub use crate::module::*;
pub use crate::instance::*;
pub use crate::caller::*;
pub use crate::function::*;
pub use crate::WasmBackend;
pub use crate::DelayedContextLifetime;
}
pub use prelude::*;
pub use macros::*;
use it_memory_traits::MemoryView;
use std::marker::PhantomData;
/// A core trait for any backend. It serves two purposes:
/// * handles initialization of the library if needed
/// * provides access to all public types -- like `mod` but for trait impls.
pub trait WasmBackend: Clone + Default + 'static {
/// A type that stores all the data, while most of the types are handles to data from `Store`.
type Store: Store<Self>;
/// A compiled, but not instantiated module.
type Module: Module<Self>;
/// An object that holds all the functions that are given to `Module` as imports.
type Imports: Imports<Self>; // maybe rename to Linker?
/// An instantiated module ready to be executed.
type Instance: Instance<Self>;
/// A temporary immutable handle to `Store`.
type Context<'c>: Context<Self>;
/// A temporary mutable handle to `Store`
type ContextMut<'c>: ContextMut<Self>;
/// A type that is used to pass context to imports.
type Caller<'c>: Caller<Self>;
/// A function contained in `Store`, either host one or from wasm.
type Function: Function<Self> + FuncConstructor<Self>;
/// A wasm memory.
type Memory: Memory<Self>;
/// A view to the wasm memory.
type MemoryView: MemoryView<DelayedContextLifetime<Self>>;
/// Type that provides all WASI-related APIs.
type Wasi: WasiImplementation<Self>;
/// Creates a new wasm backend with default configuration. In future, a configuration
/// may be passed as argument.
fn new() -> WasmBackendResult<Self>;
}
/// This struct is a helper, that allows passing `<WB as WasmBackend>::ContextMut` as template parameter,
/// but not specify a lifetime. Any local lifetime can be used instead.
pub struct DelayedContextLifetime<WB: WasmBackend> {
_data: PhantomData<WB>,
}
impl<WB: WasmBackend> it_memory_traits::Store for DelayedContextLifetime<WB> {
type ActualStore<'c> = <WB as WasmBackend>::ContextMut<'c>;
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 2023 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// Copypasted from Wasmtime.
/// A helper macros for implementing anything for 0-16 generic parameters.
/// The expected argument signature is this:
/// ```
/// macro_rules! example_arg {
/// ($num:tt $($args:ident)*) => ();
/// }
/// ```
/// https://github.com/bytecodealliance/wasmtime/blob/812b4b5229eac29b18b5c70a48536a514d73a8a6/crates/wasmtime/src/func.rs#LL242C14-L242C41
#[macro_export]
macro_rules! impl_for_each_function_signature {
($mac:ident) => {
$mac!(0);
$mac!(1 A1);
$mac!(2 A1 A2);
$mac!(3 A1 A2 A3);
$mac!(4 A1 A2 A3 A4);
$mac!(5 A1 A2 A3 A4 A5);
$mac!(6 A1 A2 A3 A4 A5 A6);
$mac!(7 A1 A2 A3 A4 A5 A6 A7);
$mac!(8 A1 A2 A3 A4 A5 A6 A7 A8);
$mac!(9 A1 A2 A3 A4 A5 A6 A7 A8 A9);
$mac!(10 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10);
$mac!(11 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11);
$mac!(12 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12);
$mac!(13 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13);
$mac!(14 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14);
$mac!(15 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15);
$mac!(16 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15 A16);
};
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2023 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::ModuleCreationResult;
use crate::InstantiationResult;
use crate::WasmBackend;
/// A handle to compiled wasm module.
pub trait Module<WB: WasmBackend>: Sized {
/// Compiles a wasm bytes into a module and extracts custom sections.
fn new(store: &mut <WB as WasmBackend>::Store, wasm: &[u8]) -> ModuleCreationResult<Self>;
/// Returns custom sections corresponding to `name`, empty slice if there is no sections.
fn custom_sections(&self, name: &str) -> &[Vec<u8>];
/// Instantiates module by allocating memory, VM state and linking imports with ones from `import` argument.
/// Does not call `_start` or `_initialize` functions.
///
/// # Panics:
///
/// If the `Store` given is not the same with `Store` used to create `Imports` and this object.
fn instantiate(
&self,
store: &mut <WB as WasmBackend>::Store,
imports: &<WB as WasmBackend>::Imports,
) -> InstantiationResult<<WB as WasmBackend>::Instance>;
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2023 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::WasmBackend;
/// `Store` is an object that stores modules, instances, functions memories and so on.
/// `Store` is grow-only: once something added, it will not be removed until Store is destroyed.
/// Some of the implementations can limit allocated resources.
/// For example, Wasmtime cannot have more than 10000 instances in one `Store`.
///
/// Most of the functions in this crate require a handle to `Store` to work.
pub trait Store<WB: WasmBackend>: AsContextMut<WB> {
fn new(backend: &WB) -> Self;
}
/// A temporary immutable handle to store
pub trait Context<WB: WasmBackend>: AsContext<WB> {}
/// A temporary mutable handle to store
pub trait ContextMut<WB: WasmBackend>: AsContextMut<WB> {}
pub trait AsContext<WB: WasmBackend> {
fn as_context(&self) -> <WB as WasmBackend>::Context<'_>;
}
pub trait AsContextMut<WB: WasmBackend>: AsContext<WB> {
fn as_context_mut(&mut self) -> <WB as WasmBackend>::ContextMut<'_>;
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2023 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::WasiError;
use crate::WasmBackend;
use std::path::PathBuf;
use std::collections::HashMap;
use std::collections::HashSet;
/// A type that provides WASI functionality to the given Wasm backend.
pub trait WasiImplementation<WB: WasmBackend> {
/// Configures WASI state and adds WASI functions to the `imports` object.
/// # Errors:
/// Returns an error if failed to open a preopen directory/file.
fn register_in_linker(
store: &mut <WB as WasmBackend>::ContextMut<'_>,
linker: &mut <WB as WasmBackend>::Imports,
config: WasiParameters,
) -> Result<(), WasiError>;
/// Optional API for getting current WASI state.
/// Returns None if not supported by current backend.
fn get_wasi_state<'s>(
instance: &'s mut <WB as WasmBackend>::Instance,
) -> Box<dyn WasiState + 's>;
}
#[derive(Default)]
pub struct WasiParameters {
pub args: Vec<Vec<u8>>,
pub envs: HashMap<Vec<u8>, Vec<u8>>,
pub preopened_files: HashSet<PathBuf>,
pub mapped_dirs: HashMap<String, PathBuf>,
}
pub trait WasiState {
fn envs(&self) -> &[Vec<u8>];
}

View File

@ -0,0 +1,92 @@
/*
* Copyright 2023 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#[derive(Debug, Clone, PartialEq)]
pub enum WValue {
/// The `i32` type.
I32(i32),
/// The `i64` type.
I64(i64),
/// The `f32` type.
F32(f32),
/// The `f64` type.
F64(f64),
}
impl From<i32> for WValue {
fn from(value: i32) -> Self {
WValue::I32(value)
}
}
impl From<i64> for WValue {
fn from(value: i64) -> Self {
WValue::I64(value)
}
}
impl From<f32> for WValue {
fn from(value: f32) -> Self {
WValue::F32(value)
}
}
impl From<f64> for WValue {
fn from(value: f64) -> Self {
WValue::F64(value)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum WType {
/// The `i32` type.
I32,
/// The `i64` type.
I64,
/// The `f32` type.
F32,
/// The `f64` type.
F64,
/// The `v128` type, unsupported.
V128,
/// ExternRef type, unsupported.
ExternRef,
/// FuncRef type, unsupported.
FuncRef,
}
impl WType {
pub fn is_supported(&self) -> bool {
!matches!(self, Self::ExternRef | Self::FuncRef | Self::V128)
}
}
impl WValue {
pub fn to_u128(&self) -> u128 {
match *self {
Self::I32(x) => x as u128,
Self::I64(x) => x as u128,
Self::F32(x) => f32::to_bits(x) as u128,
Self::F64(x) => f64::to_bits(x) as u128,
}
}
}
impl std::fmt::Display for WType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}