add ImportObject

This commit is contained in:
Valery Antopol 2022-02-26 17:19:34 +03:00
parent 5e7dae9dcd
commit b96013535b
14 changed files with 228 additions and 82 deletions

2
Cargo.lock generated
View File

@ -1887,6 +1887,7 @@ dependencies = [
"wasmer-interface-types-fl 0.21.1",
"wasmer-runtime-core-fl",
"wasmer-runtime-fl",
"wasmer-wasi-fl",
]
[[package]]
@ -1897,6 +1898,7 @@ dependencies = [
"wasmer-interface-types-fl 0.21.1",
"wasmer-runtime-core-fl",
"wasmer-runtime-fl",
"wasmer-wasi-fl",
]
[[package]]

View File

@ -21,7 +21,8 @@ use crate::ParserResult;
use walrus::IdsToIndices;
use wasmer_it::ast::Interfaces;
//use wasmer_core::Module as WasmerModule;
use marine_wasm_backend_traits::Module as ModuleTrait;
use marine_wasm_backend_traits::WasmBackend;
use marine_wasm_backend_traits::Module as WasmModule;
use std::borrow::Cow;
use std::path::Path;
@ -43,7 +44,9 @@ where
}
/// Extracts IT section of provided Wasm binary and converts it to a MITInterfaces.
pub fn extract_it_from_module<M: ModuleTrait>(wasmer_module: &M) -> ParserResult<Interfaces<'_>> {
pub fn extract_it_from_module<WB: WasmBackend>(
wasmer_module: &<WB as WasmBackend>::M,
) -> ParserResult<Interfaces<'_>> {
let wit_sections = wasmer_module
.custom_sections(IT_SECTION_NAME)
.ok_or(ITParserError::NoITSection)?;

View File

@ -21,7 +21,9 @@ use crate::extract_custom_sections_by_name;
use crate::try_as_one_section;
//use wasmer_core::Module as WasmerModule;
use marine_wasm_backend_traits::Module as ModuleTrait;
use marine_wasm_backend_traits::WasmBackend;
use marine_wasm_backend_traits::Module as WasmModule;
use marine_rs_sdk_main::VERSION_SECTION_NAME;
use walrus::ModuleConfig;
use walrus::Module;
@ -57,8 +59,8 @@ pub fn extract_from_module(wasm_module: &Module) -> ModuleInfoResult<Option<semv
Ok(Some(version))
}
pub fn extract_from_wasmer_module<M: ModuleTrait>(
wasmer_module: &M,
pub fn extract_from_wasmer_module<WB: WasmBackend>(
wasmer_module: &<WB as WasmBackend>::M,
) -> ModuleInfoResult<Option<semver::Version>> {
let sections = wasmer_module.custom_sections(VERSION_SECTION_NAME);

View File

@ -12,3 +12,4 @@ wasmer-it = { package = "wasmer-interface-types-fl", version = "0.21.1" }
wasmer-runtime = { package = "wasmer-runtime-fl", version = "=0.17.1" }
# dynamicfunc-fat-closures allows using state inside DynamicFunc
wasmer-core = { package = "wasmer-runtime-core-fl", version = "=0.17.1", features = ["dynamicfunc-fat-closures"] }
wasmer-wasi = { package = "wasmer-wasi-fl", version = "0.17.1" }

View File

@ -1,3 +1,5 @@
use std::fmt::Display;
use std::path::PathBuf;
use thiserror::Error;
pub struct Value {}
@ -11,25 +13,63 @@ pub enum WasmBackendError {
pub type WasmBackendResult<T> = Result<T, WasmBackendError>;
pub trait WasmBackend: Clone + 'static {
type M: Module;
type IO: ImportObject<Self>;
type E: Export;
type M: Module<Self>;
type I: Instance<Self>;
type Wasi: WasiImplementation<Self>;
fn compile(wasm: &[u8]) -> WasmBackendResult<Self::M>;
}
pub trait Module {
type I: Instance;
pub trait Module<WB: WasmBackend> {
fn custom_sections(&self, key: &str) -> Option<&[Vec<u8>]>;
fn instantiate(&self, imports: &wasmer_runtime::ImportObject) -> WasmBackendResult<Self::I>;
fn instantiate(
&self,
imports: &<WB as WasmBackend>::IO,
) -> WasmBackendResult<<WB as WasmBackend>::I>;
}
pub trait Instance {
fn export_iter<'a>(&'a self) -> Box<dyn Iterator<Item = (String, wasmer_runtime::Export)> + 'a>;
pub trait Instance<WB: WasmBackend> {
fn export_iter<'a>(&'a self)
-> Box<dyn Iterator<Item = (String, wasmer_runtime::Export)> + 'a>;
fn exports(&self) -> &wasmer_core::instance::Exports;
fn import_object(&self) -> &wasmer_runtime::ImportObject;
fn import_object(&self) -> &<WB as WasmBackend>::IO;
// maybe hide them inside impl
fn context(&self) -> &wasmer_core::vm::Ctx;
fn context_mut(&mut self) -> &mut wasmer_core::vm::Ctx;
}
pub trait Export {}
pub trait ImportObject<WB: WasmBackend>:
Clone + Extend<(String, String, <WB as WasmBackend>::E)>
{
fn new() -> Self;
fn extend_with_self(&mut self, other: Self);
fn register<S, N>(
&mut self,
name: S,
namespace: N,
) -> Option<Box<dyn wasmer_runtime::LikeNamespace>>
where
S: Into<String>,
N: wasmer_runtime::LikeNamespace + Send + 'static;
fn maybe_with_namespace<Func, InnerRet>(&self, namespace: &str, f: Func) -> Option<InnerRet>
where
Func: FnOnce(&(dyn wasmer_runtime::LikeNamespace + Send)) -> Option<InnerRet>,
InnerRet: Sized;
}
pub trait WasiImplementation<WB: WasmBackend> {
fn generate_import_object_for_version(
version: wasmer_wasi::WasiVersion,
args: Vec<Vec<u8>>,
envs: Vec<Vec<u8>>,
preopened_files: Vec<PathBuf>,
mapped_dirs: Vec<(String, PathBuf)>,
) -> Result<<WB as WasmBackend>::IO, String>;
}

View File

@ -11,3 +11,4 @@ wasmer-runtime = { package = "wasmer-runtime-fl", version = "=0.17.1" }
# dynamicfunc-fat-closures allows using state inside DynamicFunc
wasmer-core = { package = "wasmer-runtime-core-fl", version = "=0.17.1", features = ["dynamicfunc-fat-closures"] }
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.21.1" }
wasmer-wasi = { package = "wasmer-wasi-fl", version = "0.17.1" }

View File

@ -3,19 +3,26 @@ use marine_wasm_backend_traits::WasmBackendResult;
use marine_wasm_backend_traits::WasmBackendError;
use marine_wasm_backend_traits::Module;
use marine_wasm_backend_traits::Instance;
use marine_wasm_backend_traits::ImportObject;
use marine_wasm_backend_traits::Export;
use marine_wasm_backend_traits::WasiImplementation;
use std::path::PathBuf;
#[derive(Clone)]
pub struct WasmerBackend {}
impl WasmBackend for WasmerBackend {
type E = WasmerExport;
type M = WasmerModule;
type I = WasmerInstance;
type IO = WasmerImportObject;
type Wasi = WasmerWasiImplementation;
fn compile(wasm: &[u8]) -> WasmBackendResult<WasmerModule> {
wasmer_runtime::compile(wasm).map_err(|_| {
WasmBackendError::SomeError
}).map(|module| {
WasmerModule { module }
})
wasmer_runtime::compile(wasm)
.map_err(|_| WasmBackendError::SomeError)
.map(|module| WasmerModule { module })
}
}
@ -23,29 +30,31 @@ pub struct WasmerModule {
module: wasmer_core::Module,
}
impl Module for WasmerModule {
type I = WasmerInstance;
impl Module<WasmerBackend> for WasmerModule {
fn custom_sections(&self, name: &str) -> Option<&[Vec<u8>]> {
self.module.custom_sections(name)
}
fn instantiate(&self, imports: &wasmer_runtime::ImportObject) -> WasmBackendResult<Self::I> {
fn instantiate(&self, imports: &WasmerImportObject) -> WasmBackendResult<WasmerInstance> {
self.module
.instantiate(&imports)
.map_err(|_| {
WasmBackendError::SomeError
.instantiate(&imports.import_object)
.map_err(|_| WasmBackendError::SomeError)
.map(|instance| WasmerInstance {
instance,
import_object: imports.clone(),
})
.map(|instance| {WasmerInstance{instance}})
}
}
pub struct WasmerInstance {
instance: wasmer_core::Instance,
pub instance: wasmer_core::Instance,
pub import_object: WasmerImportObject,
}
impl Instance for WasmerInstance {
fn export_iter<'a>(&'a self) -> Box<dyn Iterator<Item = (String, wasmer_runtime::Export)> + 'a> {
impl Instance<WasmerBackend> for WasmerInstance {
fn export_iter<'a>(
&'a self,
) -> Box<dyn Iterator<Item = (String, wasmer_runtime::Export)> + 'a> {
let exports = self.instance.exports();
Box::new(exports)
}
@ -54,13 +63,94 @@ impl Instance for WasmerInstance {
&self.instance.exports
}
fn import_object(&self) -> &wasmer_runtime::ImportObject {
&self.instance.import_object
fn import_object(&self) -> &WasmerImportObject {
&self.import_object
}
fn context(&self) -> &wasmer_core::vm::Ctx { self.instance.context() }
fn context_mut(&mut self) -> &mut wasmer_core::vm::Ctx { self.instance.context_mut()}
fn context(&self) -> &wasmer_core::vm::Ctx {
self.instance.context()
}
fn context_mut(&mut self) -> &mut wasmer_core::vm::Ctx {
self.instance.context_mut()
}
}
#[derive(Clone)]
pub struct WasmerImportObject {
pub import_object: wasmer_runtime::ImportObject,
}
impl Extend<(String, String, WasmerExport)> for WasmerImportObject {
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = (String, String, WasmerExport)>,
{
self.import_object.extend(
iter.into_iter()
.map(|(s1, s2, export)| (s1, s2, export.export)),
)
}
}
impl ImportObject<WasmerBackend> for WasmerImportObject {
fn new() -> Self {
WasmerImportObject {
import_object: wasmer_runtime::ImportObject::new(),
}
}
fn extend_with_self(&mut self, other: Self) {
self.import_object.extend(other.import_object);
}
fn register<S, N>(
&mut self,
name: S,
namespace: N,
) -> Option<Box<dyn wasmer_runtime::LikeNamespace>>
where
S: Into<String>,
N: wasmer_runtime::LikeNamespace + Send + 'static,
{
self.import_object.register(name, namespace)
}
fn maybe_with_namespace<Func, InnerRet>(&self, namespace: &str, f: Func) -> Option<InnerRet>
where
Func: FnOnce(&(dyn wasmer_runtime::LikeNamespace + Send)) -> Option<InnerRet>,
InnerRet: Sized,
{
self.import_object.maybe_with_namespace(namespace, f)
}
}
pub struct WasmerExport {
export: wasmer_runtime::Export,
}
impl Export for WasmerExport {}
pub struct WasmerWasiImplementation {}
impl WasiImplementation<WasmerBackend> for WasmerWasiImplementation {
fn generate_import_object_for_version(
version: wasmer_wasi::WasiVersion,
args: Vec<Vec<u8>>,
envs: Vec<Vec<u8>>,
preopened_files: Vec<PathBuf>,
mapped_dirs: Vec<(String, PathBuf)>,
) -> Result<WasmerImportObject, String> {
wasmer_wasi::generate_import_object_for_version(
version,
args,
envs,
preopened_files,
mapped_dirs,
)
.map(|import_object| WasmerImportObject { import_object })
}
}
/*
pub struct WasmerExportIter {
export_iter: Box<dyn Iterator<Item = (String, wasmer_runtime::Export)> + 'a>

View File

@ -18,8 +18,11 @@ use super::IValue;
use super::IType;
use crate::HostImportError;
use marine_wasm_backend_traits::WasmBackend;
use marine_wasm_backend_traits::ImportObject;
use wasmer_wasi::WasiVersion;
use wasmer_runtime::ImportObject;
//use wasmer_runtime::ImportObject;
use wasmer_core::vm::Ctx;
use std::path::PathBuf;
@ -46,13 +49,13 @@ pub struct HostImportDescriptor {
pub error_handler: Option<Box<dyn Fn(&HostImportError) -> Option<IValue> + 'static>>,
}
pub struct MModuleConfig {
pub struct MModuleConfig<WB: WasmBackend> {
/// Maximum number of Wasm memory pages that loaded module can use.
/// Each Wasm page is 65536 bytes long.
pub max_heap_pages_count: u32,
/// Import object that will be used in module instantiation process.
pub raw_imports: ImportObject,
pub raw_imports: <WB as WasmBackend>::IO,
/// Imports from the host side that will be used in module instantiation process.
pub host_imports: HashMap<String, HostImportDescriptor>,
@ -70,12 +73,12 @@ pub struct MModuleConfig {
pub wasi_mapped_dirs: HashMap<String, PathBuf>,
}
impl Default for MModuleConfig {
impl<WB: WasmBackend> Default for MModuleConfig<WB> {
fn default() -> Self {
// some reasonable defaults
Self {
max_heap_pages_count: DEFAULT_HEAP_PAGES_COUNT,
raw_imports: ImportObject::new(),
raw_imports: <WB as WasmBackend>::IO::new(),
host_imports: HashMap::new(),
wasi_version: WasiVersion::Latest,
wasi_envs: HashMap::new(),
@ -88,7 +91,7 @@ impl Default for MModuleConfig {
// TODO: implement debug for MModuleConfig
#[allow(dead_code)]
impl MModuleConfig {
impl<WB: WasmBackend> MModuleConfig<WB> {
pub fn with_mem_pages_count(mut self, mem_pages_count: u32) -> Self {
self.max_heap_pages_count = mem_pages_count;
self

View File

@ -66,7 +66,7 @@ impl<WB: WasmBackend> Marine<WB> {
&mut self,
name: S,
wasm_bytes: &[u8],
config: MModuleConfig,
config: MModuleConfig<WB>,
) -> MResult<()> {
self.load_module_(name.into(), wasm_bytes, config)
}
@ -75,7 +75,7 @@ impl<WB: WasmBackend> Marine<WB> {
&mut self,
name: String,
wasm_bytes: &[u8],
config: MModuleConfig,
config: MModuleConfig<WB>,
) -> MResult<()> {
let _prepared_wasm_bytes =
crate::misc::prepare_module(wasm_bytes, config.max_heap_pages_count)?;

View File

@ -103,7 +103,7 @@ pub enum MError {
IncorrectWIT(String),
#[error("WASM BACKEND ERROR: {0}")]
WasmBackendError(WasmBackendError)
WasmBackendError(WasmBackendError),
}
impl From<MITInterfacesError> for MError {

View File

@ -21,15 +21,15 @@ use marine_module_info_parser::sdk_version;
use marine_min_it_version::min_sdk_version;
use marine_min_it_version::min_it_version;
use marine_wasm_backend_traits::Module;
use marine_wasm_backend_traits::WasmBackend;
//use wasmer_core::Module;
pub(crate) fn check_sdk_version<M: Module>(
name: impl Into<String>,
wasmer_module: &M,
pub(crate) fn check_sdk_version<WB: WasmBackend>(
name: String,
wasmer_module: &<WB as WasmBackend>::M,
) -> PrepareResult<()> {
let module_version = sdk_version::extract_from_wasmer_module(wasmer_module)?;
let module_version = sdk_version::extract_from_wasmer_module::<WB>(wasmer_module)?;
let module_version = match module_version {
Some(module_version) => module_version,
None => return Err(PrepareError::ModuleWithoutVersion(name.into())),

View File

@ -24,6 +24,8 @@ use crate::MModuleConfig;
use marine_wasm_backend_traits::WasmBackend;
use marine_wasm_backend_traits::Module;
use marine_wasm_backend_traits::Instance;
use marine_wasm_backend_traits::ImportObject;
use marine_wasm_backend_traits::WasiImplementation;
use marine_it_interfaces::MITInterfaces;
use marine_it_parser::extract_it_from_module;
@ -31,7 +33,7 @@ use marine_utils::SharedString;
//use wasmer_core::Instance as WasmerInstance;
use wasmer_core::import::Namespace;
//use wasmer_runtime::compile;
use wasmer_runtime::ImportObject;
//use wasmer_runtime::ImportObject;
use wasmer_it::interpreter::Interpreter;
use std::collections::HashMap;
@ -77,22 +79,22 @@ pub(crate) struct MModule<WB: WasmBackend> {
// wasmer_instance is needed because WITInstance contains dynamic functions
// that internally keep pointer to it.
#[allow(unused)]
wasmer_instance: Box<<<WB as WasmBackend>::M as Module>::I>,
wasmer_instance: Box<<WB as WasmBackend>::I>,
// import_object is needed because ImportObject::extend doesn't really deep copy
// imports, so we need to store imports of this module to prevent their removing.
#[allow(unused)]
it_import_object: ImportObject,
it_import_object: <WB as WasmBackend>::IO,
// host_import_object is needed because ImportObject::extend doesn't really deep copy
// imports, so we need to store imports of this module to prevent their removing.
#[allow(unused)]
host_import_object: ImportObject,
host_import_object: <WB as WasmBackend>::IO,
// host_closures_import_object is needed because ImportObject::extend doesn't really deep copy
// imports, so we need to store imports of this module to prevent their removing.
#[allow(unused)]
host_closures_import_object: ImportObject,
host_closures_import_object: <WB as WasmBackend>::IO,
// TODO: replace with dyn Trait
export_funcs: ExportFunctions<WB>,
@ -106,13 +108,13 @@ impl<WB: WasmBackend> MModule<WB> {
pub(crate) fn new(
name: &str,
wasm_bytes: &[u8],
config: MModuleConfig,
config: MModuleConfig<WB>,
modules: &HashMap<String, MModule<WB>>,
) -> MResult<Self> {
let wasmer_module = WB::compile(wasm_bytes)?;
crate::misc::check_sdk_version(name, &wasmer_module)?;
crate::misc::check_sdk_version::<WB>(name.to_string(), &wasmer_module)?;
let it = extract_it_from_module(&wasmer_module)?;
let it = extract_it_from_module::<WB>(&wasmer_module)?;
crate::misc::check_it_version(name, &it.version)?;
let mit = MITInterfaces::new(it);
@ -214,10 +216,10 @@ impl<WB: WasmBackend> MModule<WB> {
}
fn create_import_objects(
config: MModuleConfig,
config: MModuleConfig<WB>,
mit: &MITInterfaces<'_>,
wit_import_object: ImportObject,
) -> MResult<(ImportObject, ImportObject)> {
wit_import_object: <WB as WasmBackend>::IO,
) -> MResult<(<WB as WasmBackend>::IO, <WB as WasmBackend>::IO)> {
use crate::host_imports::create_host_import_func;
let wasi_envs = config
@ -232,7 +234,7 @@ impl<WB: WasmBackend> MModule<WB> {
let wasi_preopened_files = config.wasi_preopened_files.into_iter().collect::<Vec<_>>();
let wasi_mapped_dirs = config.wasi_mapped_dirs.into_iter().collect::<Vec<_>>();
let mut wasi_import_object = wasmer_wasi::generate_import_object_for_version(
let mut wasi_import_object = <WB as WasmBackend>::Wasi::generate_import_object_for_version(
config.wasi_version,
vec![],
wasi_envs,
@ -252,12 +254,12 @@ impl<WB: WasmBackend> MModule<WB> {
let host_import = create_host_import_func(descriptor, record_types.clone());
host_closures_namespace.insert(import_name, host_import);
}
let mut host_closures_import_object = ImportObject::new();
let mut host_closures_import_object = <WB as WasmBackend>::IO::new();
host_closures_import_object.register("host", host_closures_namespace);
wasi_import_object.extend(wit_import_object);
wasi_import_object.extend(config.raw_imports);
wasi_import_object.extend(host_closures_import_object.clone());
wasi_import_object.extend_with_self(wit_import_object);
wasi_import_object.extend_with_self(config.raw_imports);
wasi_import_object.extend_with_self(host_closures_import_object.clone());
Ok((wasi_import_object, host_closures_import_object))
}
@ -298,7 +300,7 @@ impl<WB: WasmBackend> MModule<WB> {
fn adjust_wit_imports(
wit: &MITInterfaces<'_>,
wit_instance: Arc<MaybeUninit<ITInstance<WB>>>,
) -> MResult<ImportObject> {
) -> MResult<<WB as WasmBackend>::IO> {
use marine_it_interfaces::ITAstType;
use wasmer_core::typed_func::DynamicFunc;
use wasmer_core::vm::Ctx;
@ -387,7 +389,8 @@ impl<WB: WasmBackend> MModule<WB> {
arguments,
output_types,
} => {
let interpreter: ITInterpreter<WB> = adapter_instructions.clone().try_into()?;
let interpreter: ITInterpreter<WB> =
adapter_instructions.clone().try_into()?;
let raw_import = create_raw_import(
wit_instance.clone(),
@ -412,7 +415,7 @@ impl<WB: WasmBackend> MModule<WB> {
})
.collect::<MResult<multimap::MultiMap<_, _>>>()?;
let mut import_object = ImportObject::new();
let mut import_object = <WB as WasmBackend>::IO::new();
// TODO: refactor this
for (namespace_name, funcs) in wit_import_funcs.into_iter() {

View File

@ -20,8 +20,9 @@ use super::IRecordType;
use crate::MResult;
use marine_wasm_backend_traits::WasmBackend;
use marine_wasm_backend_traits::Module;
//use marine_wasm_backend_traits::Module;
use marine_wasm_backend_traits::Instance;
use marine_wasm_backend_traits::ImportObject;
use marine_it_interfaces::MITInterfaces;
use marine_it_interfaces::ITAstType;
@ -50,7 +51,7 @@ pub(super) struct ITInstance<WB: WasmBackend> {
impl<WB: WasmBackend> ITInstance<WB> {
pub(super) fn new(
wasmer_instance: &<<WB as WasmBackend>::M as Module>::I,
wasmer_instance: &<WB as WasmBackend>::I,
module_name: &str,
wit: &MITInterfaces<'_>,
modules: &HashMap<String, MModule<WB>>,
@ -71,8 +72,8 @@ impl<WB: WasmBackend> ITInstance<WB> {
})
}
fn extract_raw_exports<I: Instance>(
wasmer_instance: &I,
fn extract_raw_exports(
wasmer_instance: &<WB as WasmBackend>::I,
it: &MITInterfaces<'_>,
) -> MResult<HashMap<usize, WITFunction<WB>>> {
use wasmer_core::DynFunc;
@ -141,7 +142,7 @@ impl<WB: WasmBackend> ITInstance<WB> {
.collect::<MResult<HashMap<_, _>>>()
}
fn extract_memories<I: Instance>(wasmer_instance: &I) -> Vec<WITMemory> {
fn extract_memories(wasmer_instance: &<WB as WasmBackend>::I) -> Vec<WITMemory> {
use wasmer_core::export::Export::Memory;
let mut memories = wasmer_instance
@ -180,7 +181,8 @@ impl<WB: WasmBackend> ITInstance<WB> {
}
}
impl<'v, WB: WasmBackend> wasm::structures::Instance<ITExport, WITFunction<WB>, WITMemory, WITMemoryView<'v>>
impl<'v, WB: WasmBackend>
wasm::structures::Instance<ITExport, WITFunction<WB>, WITMemory, WITMemoryView<'v>>
for ITInstance<WB>
{
fn export(&self, _export_name: &str) -> Option<&ITExport> {
@ -188,7 +190,10 @@ impl<'v, WB: WasmBackend> wasm::structures::Instance<ITExport, WITFunction<WB>,
None
}
fn local_or_import<I: TypedIndex + LocalImportIndex>(&self, index: I) -> Option<&WITFunction<WB>> {
fn local_or_import<I: TypedIndex + LocalImportIndex>(
&self,
index: I,
) -> Option<&WITFunction<WB>> {
self.funcs.get(&index.index())
}

View File

@ -65,11 +65,7 @@ impl Marine {
}
/// Load a new module inside Marine.
pub fn load_module<S: Into<String>>(
&mut self,
name: S,
wasm_bytes: &[u8],
) -> MResult<()> {
pub fn load_module<S: Into<String>>(&mut self, name: S, wasm_bytes: &[u8]) -> MResult<()> {
self.load_module_(name.into(), wasm_bytes)
}