mirror of
https://github.com/fluencelabs/marine.git
synced 2025-06-24 20:21:39 +00:00
feat!: decouple wasmer from Marine, replace it with generic backend interface (#219)
This commit is contained in:
36
crates/wasm-backend-traits/src/caller.rs
Normal file
36
crates/wasm-backend-traits/src/caller.rs
Normal 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>;
|
||||
}
|
145
crates/wasm-backend-traits/src/errors.rs
Normal file
145
crates/wasm-backend-traits/src/errors.rs
Normal 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),
|
||||
}
|
43
crates/wasm-backend-traits/src/exports.rs
Normal file
43
crates/wasm-backend-traits/src/exports.rs
Normal 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;
|
||||
}
|
169
crates/wasm-backend-traits/src/function.rs
Normal file
169
crates/wasm-backend-traits/src/function.rs
Normal 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);
|
||||
}
|
24
crates/wasm-backend-traits/src/impl_utils.rs
Normal file
24
crates/wasm-backend-traits/src/impl_utils.rs
Normal 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()
|
||||
}
|
95
crates/wasm-backend-traits/src/imports.rs
Normal file
95
crates/wasm-backend-traits/src/imports.rs
Normal 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>>;
|
||||
}
|
56
crates/wasm-backend-traits/src/instance.rs
Normal file
56
crates/wasm-backend-traits/src/instance.rs
Normal 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>;
|
||||
}
|
96
crates/wasm-backend-traits/src/lib.rs
Normal file
96
crates/wasm-backend-traits/src/lib.rs
Normal 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>;
|
||||
}
|
47
crates/wasm-backend-traits/src/macros.rs
Normal file
47
crates/wasm-backend-traits/src/macros.rs
Normal 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);
|
||||
};
|
||||
}
|
40
crates/wasm-backend-traits/src/module.rs
Normal file
40
crates/wasm-backend-traits/src/module.rs
Normal 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>;
|
||||
}
|
41
crates/wasm-backend-traits/src/store.rs
Normal file
41
crates/wasm-backend-traits/src/store.rs
Normal 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<'_>;
|
||||
}
|
52
crates/wasm-backend-traits/src/wasi.rs
Normal file
52
crates/wasm-backend-traits/src/wasi.rs
Normal 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>];
|
||||
}
|
92
crates/wasm-backend-traits/src/wtype.rs
Normal file
92
crates/wasm-backend-traits/src/wtype.rs
Normal 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)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user