introduce service-like functionality

This commit is contained in:
vms 2020-06-02 17:20:00 +03:00
parent 880bb6f87e
commit b258caa8d6
20 changed files with 735 additions and 204 deletions

27
Cargo.lock generated
View File

@ -17,7 +17,7 @@ dependencies = [
"tokio", "tokio",
"wasmer-runtime 0.17.0 (git+http://github.com/fluencelabs/wasmer?branch=fluence)", "wasmer-runtime 0.17.0 (git+http://github.com/fluencelabs/wasmer?branch=fluence)",
"wasmer-runtime-core 0.17.0 (git+http://github.com/fluencelabs/wasmer?branch=fluence)", "wasmer-runtime-core 0.17.0 (git+http://github.com/fluencelabs/wasmer?branch=fluence)",
"wasmer-wasi", "wasmer-wasi 0.17.0 (git+http://github.com/fluencelabs/wasmer?branch=fluence)",
] ]
[[package]] [[package]]
@ -2143,6 +2143,26 @@ dependencies = [
"winapi 0.3.8", "winapi 0.3.8",
] ]
[[package]]
name = "wasmer-wasi"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88bd5bfd3824c2e5cdef44db3c278b58bff917bf3347e79b34730cf2a952acc0"
dependencies = [
"bincode",
"byteorder",
"generational-arena",
"getrandom",
"libc",
"log",
"serde",
"thiserror",
"time",
"typetag",
"wasmer-runtime-core 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8",
]
[[package]] [[package]]
name = "wasmer-win-exception-handler" name = "wasmer-win-exception-handler"
version = "0.17.0" version = "0.17.0"
@ -2255,12 +2275,15 @@ dependencies = [
[[package]] [[package]]
name = "wit_fce" name = "wit_fce"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"multimap", "multimap",
"parity-wasm",
"pwasm-utils",
"wasmer-interface-types", "wasmer-interface-types",
"wasmer-runtime 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-wasi 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]

View File

@ -20,7 +20,7 @@ use crate::vm::module::fce_result::FCEResult;
use sha2::digest::generic_array::GenericArray; use sha2::digest::generic_array::GenericArray;
use sha2::digest::FixedOutput; use sha2::digest::FixedOutput;
/// Application interface of a FCE module. Intended to use by FCE instance itself. /// Application interface of a FCE module. Intended to use by FCE vm.instance itself.
pub(crate) trait ModuleAPI { pub(crate) trait ModuleAPI {
/// Invokes a module supplying byte array and expecting byte array with some outcome back. /// Invokes a module supplying byte array and expecting byte array with some outcome back.
fn invoke(&mut self, argument: &[u8]) -> Result<FCEResult, FCEError>; fn invoke(&mut self, argument: &[u8]) -> Result<FCEResult, FCEError>;

View File

@ -1,11 +1,15 @@
[package] [package]
name = "wit_fce" name = "wit_fce"
version = "0.1.0" version = "0.2.0"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
edition = "2018" edition = "2018"
[dependencies] [dependencies]
wasmer-runtime = "0.17.0" wasmer-runtime = "0.17.0"
wasmer-runtime-core = { version = "0.17.0", features = ["dynamicfunc-fat-closures"] } # dynamicfunc-fat-closures allows using state inside DynamicFunc
wasmer-interface-types = { git = "http://github.com/fluencelabs/interface-types" } wasmer-core = { package = "wasmer-runtime-core", version = "0.17.0", features = ["dynamicfunc-fat-closures"] }
wasmer-wit = { package = "wasmer-interface-types", git = "http://github.com/fluencelabs/interface-types" }
wasmer-wasi = "0.17.0"
multimap = "0.8.1" multimap = "0.8.1"
parity-wasm = "0.41.0"
pwasm-utils = "0.12.0"

View File

@ -16,15 +16,13 @@
#![feature(get_mut_unchecked)] #![feature(get_mut_unchecked)]
#![feature(new_uninit)] #![feature(new_uninit)]
mod instance; mod vm;
mod misc;
use crate::instance::wit_module::WITModule; use vm::IValue;
use vm::FCE;
use std::collections::HashMap; use vm::FCEModuleConfig;
use std::sync::Arc; use vm::FCEService;
use wasmer_interface_types::values::InterfaceValue;
use wasmer_runtime::{func, imports, ImportObject};
use wasmer_runtime_core::vm::Ctx;
const IPFS_NODE: &str = const IPFS_NODE: &str =
"/Users/mike/dev/work/fluence/wasm/fce/target/wasm32-unknown-unknown/release/ipfs_node_wit.wasm"; "/Users/mike/dev/work/fluence/wasm/fce/target/wasm32-unknown-unknown/release/ipfs_node_wit.wasm";
@ -35,34 +33,26 @@ const IPFS_RPC: &str =
fn main() { fn main() {
let ipfs_node_bytes = std::fs::read(IPFS_NODE).unwrap(); let ipfs_node_bytes = std::fs::read(IPFS_NODE).unwrap();
let ipfs_rpc_bytes = std::fs::read(IPFS_RPC).unwrap(); let ipfs_rpc_bytes = std::fs::read(IPFS_RPC).unwrap();
let imports = imports! {
"logger" => { let mut fce = FCE::new();
"log_utf8_string" => func!(logger_log_utf8_string), let config = FCEModuleConfig::default();
},
"host" => {
"ipfs" => func!(ipfs_call),
}
};
let mut import_object = ImportObject::new();
import_object.extend(imports);
let mut modules = HashMap::new();
println!("loading ipfs node module"); println!("loading ipfs node module");
let ipfs_node = WITModule::new(&ipfs_node_bytes, import_object.clone(), &modules) fce.register_module("node", &ipfs_node_bytes, config.clone())
.expect("module successfully created"); .expect("module successfully created");
modules.insert("node".to_string(), Arc::new(ipfs_node));
println!("loading ipfs rpc module"); println!("loading ipfs rpc module");
let mut ipfs_rpc = WITModule::new(&ipfs_rpc_bytes, import_object, &modules) fce.register_module("rpc", &ipfs_rpc_bytes, config.clone())
.expect("module successfully created"); .expect("module successfully created");
let result1 = ipfs_rpc let result = fce
.call("invoke", &[InterfaceValue::String("0xffffff".to_string())]) .call("node_rpc", "invoke", &[IValue::String("aaaa".to_string())])
.unwrap(); .unwrap();
println!("stack state {:?}", result1); println!("execution result {:?}", result);
} }
/*
fn logger_log_utf8_string(ctx: &mut Ctx, offset: i32, size: i32) { fn logger_log_utf8_string(ctx: &mut Ctx, offset: i32, size: i32) {
use wasmer_runtime_core::memory::ptr::{Array, WasmPtr}; use wasmer_runtime_core::memory::ptr::{Array, WasmPtr};
@ -73,6 +63,7 @@ fn logger_log_utf8_string(ctx: &mut Ctx, offset: i32, size: i32) {
} }
} }
fn ipfs_call(ctx: &mut Ctx, ptr: i32, size: i32) { fn ipfs_call(ctx: &mut Ctx, ptr: i32, size: i32) {
use wasmer_runtime_core::memory::ptr::{Array, WasmPtr}; use wasmer_runtime_core::memory::ptr::{Array, WasmPtr};
@ -82,3 +73,4 @@ fn ipfs_call(ctx: &mut Ctx, ptr: i32, size: i32) {
None => println!("fce logger: incorrect UTF8 string's been supplied to logger"), None => println!("fce logger: incorrect UTF8 string's been supplied to logger"),
} }
} }
*/

View File

@ -14,13 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
use crate::instance::wit_module::WITModule; mod slice_pretty_printer;
use std::collections::HashMap; pub use slice_pretty_printer::SlicePrettyPrinter;
use wasmer_interface_types::values::InterfaceValue;
use wasmer_runtime::{func, imports, ImportObject};
use wasmer_runtime_core::vm::Ctx;
pub struct WITFCE {
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2020 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 struct SlicePrettyPrinter<'a>(pub &'a [u8]);
impl<'a> std::fmt::LowerHex for SlicePrettyPrinter<'a> {
fn fmt(&self, fmtr: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
fmtr.write_fmt(format_args!("0x"))?;
for byte in self.0 {
fmtr.write_fmt(format_args!("{:02x}", byte))?;
}
Ok(())
}
}
impl<'a> std::fmt::UpperHex for SlicePrettyPrinter<'a> {
fn fmt(&self, fmtr: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
fmtr.write_fmt(format_args!("0x"))?;
for byte in self.0 {
fmtr.write_fmt(format_args!("{:02X}", byte))?;
}
Ok(())
}
}

102
wit_fce/src/vm/config.rs Normal file
View File

@ -0,0 +1,102 @@
/*
* Copyright 2020 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 wasmer_wasi::WasiVersion;
use std::path::PathBuf;
use wasmer_runtime::ImportObject;
#[derive(Clone)]
pub struct FCEModuleConfig {
/// Maximum number of Wasm memory pages that loaded module can use.
/// Each Wasm pages is 65536 bytes long.
pub mem_pages_count: u32,
/// If true, registers the logger Wasm module with name 'logger'.
/// This functionality is just for debugging, and this module will be disabled in future.
pub logger_enabled: bool,
/// Import object that will be used in module instantiation process.
pub import_object: ImportObject,
/// Desired WASI version.
pub wasi_version: WasiVersion,
/// Environment variables for loaded modules.
pub wasi_envs: Vec<Vec<u8>>,
/// List of available directories for loaded modules.
pub wasi_preopened_files: Vec<PathBuf>,
/// Mapping between paths.
pub wasi_mapped_dirs: Vec<(String, PathBuf)>,
}
impl Default for FCEModuleConfig {
fn default() -> Self {
// some reasonable defaults
Self {
// 65536*1600 ~ 100 Mb
mem_pages_count: 1600,
logger_enabled: true,
import_object: ImportObject::new(),
wasi_version: WasiVersion::Latest,
wasi_envs: vec![],
wasi_preopened_files: vec![],
wasi_mapped_dirs: vec![]
}
}
}
// TODO: implement debug for FCEModuleConfig
impl FCEModuleConfig {
#[allow(dead_code)]
pub fn with_mem_pages_count(mut self, mem_pages_count: u32) -> Self {
self.mem_pages_count = mem_pages_count;
self
}
#[allow(dead_code)]
pub fn with_logger_enable(mut self, logger_enable: bool) -> Self {
self.logger_enabled = logger_enable;
self
}
#[allow(dead_code)]
pub fn with_wasi_version(mut self, wasi_version: WasiVersion) -> Self {
self.wasi_version = wasi_version;
self
}
#[allow(dead_code)]
pub fn with_wasi_envs(mut self, envs: Vec<Vec<u8>>) -> Self {
self.wasi_envs = envs;
self
}
#[allow(dead_code)]
pub fn with_wasi_preopened_files(mut self, preopened_files: Vec<PathBuf>) -> Self {
self.wasi_preopened_files = preopened_files;
self
}
#[allow(dead_code)]
pub fn with_wasi_mapped_dirs(mut self, mapped_dirs: Vec<(String, PathBuf)>) -> Self {
self.wasi_mapped_dirs = mapped_dirs;
self
}
}

124
wit_fce/src/vm/errors.rs Normal file
View File

@ -0,0 +1,124 @@
/*
* Copyright 2020 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 wasmer_runtime::error::{
CallError, CompileError, CreationError, Error as WasmerError, ResolveError, RuntimeError,
};
use std::error::Error;
#[derive(Debug)]
pub enum FCEError {
/// Errors for I/O errors raising while opening a file.
IOError(String),
/// This error type is produced by Wasmer during resolving a Wasm function.
WasmerResolveError(String),
/// Error related to calling a main Wasm module.
WasmerInvokeError(String),
/// Error that raises during compilation Wasm code by Wasmer.
WasmerCreationError(String),
/// Error that raises during creation of some Wasm objects (like table and memory) by Wasmer.
WasmerCompileError(String),
/// Error that raises on the preparation step.
PrepareError(String),
/// Indicates that there is already a module with such name.
NonUniqueModuleName,
/// Returns where there is no module with such name.
NoSuchModule,
/// Indicates that modules currently in use and couldn't be deleted.
ModuleInUse,
}
impl Error for FCEError {}
impl std::fmt::Display for FCEError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
FCEError::IOError(msg) => write!(f, "IOError: {}", msg),
FCEError::WasmerResolveError(msg) => write!(f, "WasmerResolveError: {}", msg),
FCEError::WasmerInvokeError(msg) => write!(f, "WasmerInvokeError: {}", msg),
FCEError::WasmerCompileError(msg) => write!(f, "WasmerCompileError: {}", msg),
FCEError::WasmerCreationError(msg) => write!(f, "WasmerCreationError: {}", msg),
FCEError::PrepareError(msg) => {
write!(f, "Prepare error: {}, probably module is mailformed", msg)
}
FCEError::NonUniqueModuleName => write!(f, "FCE already has module with such name"),
FCEError::NoSuchModule => write!(f, "FCE doesn't have a module with such name"),
FCEError::ModuleInUse => {
write!(f, "Module is used by other modules and couldn't be deleted")
}
}
}
}
impl From<CreationError> for FCEError {
fn from(err: CreationError) -> Self {
FCEError::WasmerCreationError(format!("{}", err))
}
}
impl From<CompileError> for FCEError {
fn from(err: CompileError) -> Self {
FCEError::WasmerCompileError(format!("{}", err))
}
}
impl From<parity_wasm::elements::Error> for FCEError {
fn from(err: parity_wasm::elements::Error) -> Self {
FCEError::PrepareError(format!("{}", err))
}
}
impl From<CallError> for FCEError {
fn from(err: CallError) -> Self {
match err {
CallError::Resolve(err) => FCEError::WasmerResolveError(format!("{}", err)),
CallError::Runtime(err) => FCEError::WasmerInvokeError(format!("{}", err)),
}
}
}
impl From<ResolveError> for FCEError {
fn from(err: ResolveError) -> Self {
FCEError::WasmerResolveError(format!("{}", err))
}
}
impl From<RuntimeError> for FCEError {
fn from(err: RuntimeError) -> Self {
FCEError::WasmerInvokeError(format!("{}", err))
}
}
impl From<WasmerError> for FCEError {
fn from(err: WasmerError) -> Self {
FCEError::WasmerInvokeError(format!("{}", err))
}
}
impl From<std::io::Error> for FCEError {
fn from(err: std::io::Error) -> Self {
FCEError::IOError(format!("{}", err))
}
}

91
wit_fce/src/vm/fce.rs Normal file
View File

@ -0,0 +1,91 @@
/*
* Copyright 2020 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 super::instance::FCEModule;
use super::*;
use std::sync::Arc;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
pub struct FCE {
// set of modules registered inside FCE
modules: HashMap<String, Arc<FCEModule>>,
}
impl FCE {
pub fn new() -> Self {
Self {
modules: HashMap::new(),
}
}
}
impl Default for FCE {
fn default() -> Self {
Self::new()
}
}
impl FCEService for FCE {
fn call(&mut self, module_name: &str, func_name: &str, argument: &[IValue]) -> Result<Vec<IValue>, FCEError> {
match self.modules.get_mut(module_name) {
// TODO: refactor errors
Some(mut module) => unsafe {
Ok(Arc::get_mut_unchecked(&mut module).call(func_name, argument).unwrap())
},
None => Err(FCEError::NoSuchModule),
}
}
fn register_module<S>(
&mut self,
module_name: S,
wasm_bytes: &[u8],
config: FCEModuleConfig,
) -> Result<(), FCEError>
where
S: Into<String>,
{
let prepared_wasm_bytes =
super::prepare::prepare_module(wasm_bytes, config.mem_pages_count)?;
let module = FCEModule::new(
&prepared_wasm_bytes,
config.import_object,
&self.modules,
).unwrap();
match self.modules.entry(module_name.into()) {
Entry::Vacant(entry) => {
entry.insert(Arc::new(module));
Ok(())
},
Entry::Occupied(_) => Err(FCEError::NonUniqueModuleName),
}
}
fn unregister_module(&mut self, module_name: &str) -> Result<(), FCEError> {
match self.modules.entry(module_name.to_string()) {
Entry::Vacant(_) => Err(FCEError::NoSuchModule),
Entry::Occupied(module) => {
module.remove_entry();
Ok(())
}
}
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2020 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 super::config::FCEModuleConfig;
use super::errors::FCEError;
use super::IValue;
/// Describes a service behaviour in the Fluence network.
pub trait FCEService {
/// Invokes a module supplying byte array and expecting byte array with some outcome back.
fn call(&mut self, module_name: &str, function_name: &str, arguments: &[IValue]) -> Result<Vec<IValue>, FCEError>;
/// Registers new module in the FCE Service.
fn register_module<S>(
&mut self,
module_name: S,
wasm_bytes: &[u8],
config: FCEModuleConfig,
) -> Result<(), FCEError>
where
S: Into<String>;
/// Unregisters previously registered module.
fn unregister_module(&mut self, module_name: &str) -> Result<(), FCEError>;
}

View File

@ -14,12 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
use std::error::Error; use wasmer_wit::errors::InstructionError;
use wasmer_interface_types::errors::InstructionError;
use wasmer_runtime::error::{ use wasmer_runtime::error::{
CallError, CompileError, CreationError, Error as WasmerError, ResolveError, RuntimeError, CallError, CompileError, CreationError, Error as WasmerError, ResolveError, RuntimeError,
}; };
use std::error::Error;
#[derive(Debug)] #[derive(Debug)]
#[allow(unused)] #[allow(unused)]
pub enum WITFCEError { pub enum WITFCEError {

View File

@ -14,15 +14,17 @@
* limitations under the License. * limitations under the License.
*/ */
use wasmer_interface_types::interpreter::wasm; use super::{IValue, IType};
use wasmer_interface_types::{types::InterfaceType, values::InterfaceValue}; use wasmer_wit::interpreter::wasm;
// In current implementation export simply does nothing. // In current implementation export simply does nothing, because there is no more
// explicit instruction call-export in this version of wasmer-interface-types,
// but explicit Exports is still required by wasmer-interface-types::Interpreter.
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct WITExport { pub(crate) struct WITExport {
pub(crate) inputs: Vec<InterfaceType>, inputs: Vec<IType>,
pub(crate) outputs: Vec<InterfaceType>, outputs: Vec<IType>,
pub(crate) function: fn(arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()>, function: fn(arguments: &[IValue]) -> Result<Vec<IValue>, ()>,
} }
impl WITExport { impl WITExport {
@ -45,15 +47,15 @@ impl wasm::structures::Export for WITExport {
self.outputs.len() self.outputs.len()
} }
fn inputs(&self) -> &[InterfaceType] { fn inputs(&self) -> &[IType] {
&self.inputs &self.inputs
} }
fn outputs(&self) -> &[InterfaceType] { fn outputs(&self) -> &[IType] {
&self.outputs &self.outputs
} }
fn call(&self, arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()> { fn call(&self, arguments: &[IValue]) -> Result<Vec<IValue>, ()> {
(self.function)(arguments) (self.function)(arguments)
} }
} }

View File

@ -14,91 +14,76 @@
* limitations under the License. * limitations under the License.
*/ */
use crate::instance::errors::WITFCEError; use super::wit_prelude::*;
use crate::instance::exports::WITExport; use super::{IType, IValue, WValue};
use crate::instance::memory::{WITMemory, WITMemoryView};
use crate::instance::wit_function::WITFunction;
use crate::instance::wit_instance::WITInstance;
use wasmer_interface_types as wit; use wasmer_wit::ast::Interfaces;
use wasmer_interface_types::ast::{Interfaces, Type}; use wasmer_wit::interpreter::Interpreter;
use wasmer_interface_types::interpreter::Interpreter;
use wasmer_interface_types::values::InterfaceValue;
use wasmer_runtime::{compile, ImportObject}; use wasmer_runtime::{compile, ImportObject};
use wasmer_runtime_core::Instance as WasmerInstance; use wasmer_core::Module as WasmerModule;
use wasmer_core::Instance as WasmerInstance;
use wasmer_core::import::Namespace;
use multimap::MultiMap; use multimap::MultiMap;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryInto; use std::convert::TryInto;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use std::sync::Arc; use std::sync::Arc;
use wasmer_interface_types::interpreter::stack::Stackable;
use wasmer_interface_types::types::InterfaceType;
use wasmer_runtime_core::import::Namespace;
const WIT_SECTION_NAME: &str = "interface-types"; const WIT_SECTION_NAME: &str = "interface-types";
type WITInterpreter = type WITInterpreter =
Interpreter<WITInstance, WITExport, WITFunction, WITMemory, WITMemoryView<'static>>; Interpreter<WITInstance, WITExport, WITFunction, WITMemory, WITMemoryView<'static>>;
type WITModuleFunc = (WITInterpreter, Vec<InterfaceType>, Vec<InterfaceType>); // TODO: introduce new trait instead of type
type WITModuleFunc = (WITInterpreter, Vec<IType>, Vec<IType>);
pub struct WITModule { pub struct FCEModule {
// it is needed because of WITInstance contains dynamic functions
// that internally keep pointer to Wasmer instance.
#[allow(unused)] #[allow(unused)]
instance: WasmerInstance, wamser_instance: WasmerInstance,
wit_instance: Arc<WITInstance>, wit_instance: Arc<WITInstance>,
funcs: HashMap<String, WITModuleFunc>, exports_funcs: HashMap<String, WITModuleFunc>,
} }
impl WITModule { impl FCEModule {
pub fn new( pub fn new(
wasm_bytes: &[u8], wasm_bytes: &[u8],
imports: ImportObject, imports: ImportObject,
modules: &HashMap<String, Arc<WITModule>>, modules: &HashMap<String, Arc<FCEModule>>,
) -> Result<Self, WITFCEError> { ) -> Result<Self, WITFCEError> {
let wasmer_instance = compile(&wasm_bytes)?; let wasmer_module = compile(&wasm_bytes)?;
let wit = Self::extract_wit(&wasmer_module)?;
let wit_sections = wasmer_instance let wit_exports = Self::instantiate_wit_exports(&wit)?;
.custom_sections(WIT_SECTION_NAME)
.ok_or_else(|| WITFCEError::NoWITSection)?;
if wit_sections.len() > 1 {
return Err(WITFCEError::MultipleWITSections);
}
let (remainder, interfaces) = wit::decoders::binary::parse::<()>(&wit_sections[0])
.map_err(|_e| WITFCEError::WITParseError)?;
if remainder.len() > 1 {
return Err(WITFCEError::WITRemainderNotEmpty);
}
let mut wit_instance = Arc::new_uninit(); let mut wit_instance = Arc::new_uninit();
let mut import_object = Self::adjust_imports(&wit, wit_instance.clone())?;
let callable_exports = Self::extract_wit_exports(&interfaces)?;
let mut import_object = Self::adjust_imports(&interfaces, wit_instance.clone())?;
import_object.extend(imports); import_object.extend(imports);
let wasmer_instance = wasmer_instance.instantiate(&import_object)?; let wasmer_instance = wasmer_module.instantiate(&import_object)?;
let wit_instance = unsafe { let wit_instance = unsafe {
// get_mut_unchecked here is safe because currently only this modules have reference to // get_mut_unchecked here is safe because currently only this modules have reference to
// it and the environment is single-threaded // it and the environment is single-threaded
*Arc::get_mut_unchecked(&mut wit_instance) = *Arc::get_mut_unchecked(&mut wit_instance) =
MaybeUninit::new(WITInstance::new(&wasmer_instance, &interfaces, modules)?); MaybeUninit::new(WITInstance::new(&wasmer_instance, &wit, modules)?);
std::mem::transmute::<_, Arc<WITInstance>>(wit_instance) std::mem::transmute::<_, Arc<WITInstance>>(wit_instance)
}; };
Ok(Self { Ok(Self {
instance: wasmer_instance, wamser_instance: wasmer_instance,
wit_instance, wit_instance,
funcs: callable_exports, exports_funcs: wit_exports,
}) })
} }
pub fn call( pub fn call(
&mut self, &mut self,
function_name: &str, function_name: &str,
args: &[InterfaceValue], args: &[IValue],
) -> Result<Vec<InterfaceValue>, WITFCEError> { ) -> Result<Vec<IValue>, WITFCEError> {
match self.funcs.get(function_name) { use wasmer_wit::interpreter::stack::Stackable;
match self.exports_funcs.get(function_name) {
Some(func) => { Some(func) => {
let result = func let result = func
.0 .0
@ -117,8 +102,8 @@ impl WITModule {
pub fn get_func_signature( pub fn get_func_signature(
&self, &self,
function_name: &str, function_name: &str,
) -> Result<(&Vec<InterfaceType>, &Vec<InterfaceType>), WITFCEError> { ) -> Result<(&Vec<IType>, &Vec<IType>), WITFCEError> {
match self.funcs.get(function_name) { match self.exports_funcs.get(function_name) {
Some((_, inputs, outputs)) => Ok((inputs, outputs)), Some((_, inputs, outputs)) => Ok((inputs, outputs)),
None => Err(WITFCEError::NoSuchFunction(format!( None => Err(WITFCEError::NoSuchFunction(format!(
"{} has't been found during its signature looking up", "{} has't been found during its signature looking up",
@ -127,23 +112,43 @@ impl WITModule {
} }
} }
fn extract_wit_exports( fn extract_wit(wasmer_instance: &WasmerModule) -> Result<Interfaces, WITFCEError> {
interfaces: &Interfaces, let wit_sections = wasmer_instance
.custom_sections(WIT_SECTION_NAME)
.ok_or_else(|| WITFCEError::NoWITSection)?;
if wit_sections.len() > 1 {
return Err(WITFCEError::MultipleWITSections);
}
let (remainder, interfaces) = wasmer_wit::decoders::binary::parse::<()>(&wit_sections[0])
.map_err(|_e| WITFCEError::WITParseError)?;
if remainder.len() > 1 {
return Err(WITFCEError::WITRemainderNotEmpty);
}
Ok(interfaces)
}
fn instantiate_wit_exports(
wit: &Interfaces,
) -> Result<HashMap<String, WITModuleFunc>, WITFCEError> { ) -> Result<HashMap<String, WITModuleFunc>, WITFCEError> {
let exports_type_to_names = interfaces use super::IAstType;
let exports_type_to_names = wit
.exports .exports
.iter() .iter()
.map(|export| (export.function_type, export.name.to_string())) .map(|export| (export.function_type, export.name.to_string()))
.collect::<MultiMap<_, _>>(); .collect::<MultiMap<_, _>>();
let adapter_type_to_instructions = interfaces let adapter_type_to_instructions = wit
.adapters .adapters
.iter() .iter()
.map(|adapter| (adapter.function_type, &adapter.instructions)) .map(|adapter| (adapter.function_type, &adapter.instructions))
.collect::<HashMap<_, _>>(); .collect::<HashMap<_, _>>();
let mut wit_callable_exports = HashMap::new(); let mut wit_callable_exports = HashMap::new();
for i in interfaces.implementations.iter() { for i in wit.implementations.iter() {
let export_function_names = match exports_type_to_names.get_vec(&i.core_function_type) { let export_function_names = match exports_type_to_names.get_vec(&i.core_function_type) {
Some(export_function_names) => export_function_names, Some(export_function_names) => export_function_names,
None => continue, None => continue,
@ -156,7 +161,7 @@ impl WITModule {
format!("adapter function with idx = {} hasn't been found during extracting exports by implementations", i.adapter_function_type) format!("adapter function with idx = {} hasn't been found during extracting exports by implementations", i.adapter_function_type)
))?; ))?;
if i.adapter_function_type >= interfaces.types.len() as u32 { if i.adapter_function_type >= wit.types.len() as u32 {
// TODO: change error type // TODO: change error type
return Err(WITFCEError::NoSuchFunction(format!( return Err(WITFCEError::NoSuchFunction(format!(
"{} function id is bigger than WIT interface types count", "{} function id is bigger than WIT interface types count",
@ -164,8 +169,8 @@ impl WITModule {
))); )));
}; };
if let Type::Function { inputs, outputs } = if let IAstType::Function { inputs, outputs } =
&interfaces.types[i.adapter_function_type as usize] &wit.types[i.adapter_function_type as usize]
{ {
for export_function_name in export_function_names.iter() { for export_function_name in export_function_names.iter() {
// TODO: handle errors // TODO: handle errors
@ -191,16 +196,16 @@ impl WITModule {
interfaces: &Interfaces, interfaces: &Interfaces,
wit_instance: Arc<MaybeUninit<WITInstance>>, wit_instance: Arc<MaybeUninit<WITInstance>>,
) -> Result<ImportObject, WITFCEError> { ) -> Result<ImportObject, WITFCEError> {
use crate::instance::{itype_to_wtype, wval_to_ival}; use super::IAstType;
use wasmer_interface_types::ast::Type as IType; use super::type_converters::{itype_to_wtype, wval_to_ival};
use wasmer_runtime_core::typed_func::DynamicFunc; use wasmer_core::typed_func::DynamicFunc;
use wasmer_runtime_core::types::{FuncSig, Value}; use wasmer_core::types::FuncSig;
use wasmer_runtime_core::vm::Ctx; use wasmer_core::vm::Ctx;
// returns function that will be called from imports of Wasmer module // returns function that will be called from imports of Wasmer module
fn dyn_func_from_imports<F>(inputs: Vec<InterfaceType>, func: F) -> DynamicFunc<'static> fn dyn_func_from_imports<F>(inputs: Vec<IType>, func: F) -> DynamicFunc<'static>
where where
F: Fn(&mut Ctx, &[Value]) -> Vec<Value> + 'static, F: Fn(&mut Ctx, &[WValue]) -> Vec<WValue> + 'static,
{ {
let signature = inputs.iter().map(itype_to_wtype).collect::<Vec<_>>(); let signature = inputs.iter().map(itype_to_wtype).collect::<Vec<_>>();
DynamicFunc::new(Arc::new(FuncSig::new(signature, vec![])), func) DynamicFunc::new(Arc::new(FuncSig::new(signature, vec![])), func)
@ -245,7 +250,7 @@ impl WITModule {
))); )));
} }
if let IType::Function { inputs, .. } = if let IAstType::Function { inputs, .. } =
&interfaces.types[adapter.function_type as usize] &interfaces.types[adapter.function_type as usize]
{ {
let instructions = &adapter.instructions; let instructions = &adapter.instructions;
@ -253,7 +258,7 @@ impl WITModule {
let wit_instance = wit_instance.clone(); let wit_instance = wit_instance.clone();
let wit_inner_import = let wit_inner_import =
Box::new(move |_: &mut Ctx, inputs: &[Value]| -> Vec<Value> { Box::new(move |_: &mut Ctx, inputs: &[WValue]| -> Vec<WValue> {
// copy here to because otherwise wit_instance will be consumed by the closure // copy here to because otherwise wit_instance will be consumed by the closure
let wit_instance_callable = wit_instance.clone(); let wit_instance_callable = wit_instance.clone();
let converted_inputs = inputs.iter().map(wval_to_ival).collect::<Vec<_>>(); let converted_inputs = inputs.iter().map(wval_to_ival).collect::<Vec<_>>();

View File

@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
use wasmer_interface_types::interpreter::wasm; use wasmer_wit::interpreter::wasm;
use wasmer_runtime_core::memory::{Memory, MemoryView}; use wasmer_core::memory::{Memory, MemoryView};
pub struct WITMemoryView<'a>(pub MemoryView<'a, u8>); pub(super) struct WITMemoryView<'a>(pub(super) MemoryView<'a, u8>);
impl<'a> std::ops::Deref for WITMemoryView<'a> { impl<'a> std::ops::Deref for WITMemoryView<'a> {
type Target = [std::cell::Cell<u8>]; type Target = [std::cell::Cell<u8>];
@ -27,7 +27,7 @@ impl<'a> std::ops::Deref for WITMemoryView<'a> {
} }
#[derive(Clone)] #[derive(Clone)]
pub struct WITMemory(pub Memory); pub(super) struct WITMemory(pub(super) Memory);
impl std::ops::Deref for WITMemory { impl std::ops::Deref for WITMemory {
type Target = Memory; type Target = Memory;
@ -40,7 +40,7 @@ impl wasm::structures::MemoryView for WITMemoryView<'_> {}
impl<'a> wasm::structures::Memory<WITMemoryView<'a>> for WITMemory { impl<'a> wasm::structures::Memory<WITMemoryView<'a>> for WITMemory {
fn view(&self) -> WITMemoryView<'a> { fn view(&self) -> WITMemoryView<'a> {
use wasmer_runtime_core::vm::LocalMemory; use wasmer_core::vm::LocalMemory;
let LocalMemory { base, .. } = unsafe { *self.0.vm_local_memory() }; let LocalMemory { base, .. } = unsafe { *self.0.vm_local_memory() };
let length = self.0.size().bytes().0 / std::mem::size_of::<u8>(); let length = self.0.size().bytes().0 / std::mem::size_of::<u8>();

View File

@ -0,0 +1,41 @@
/*
* Copyright 2020 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.
*/
mod errors;
mod exports;
mod memory;
mod wit_function;
mod wit_instance;
mod type_converters;
mod fce_module;
pub(crate) use fce_module::FCEModule;
pub use wasmer_wit::types::InterfaceType as IType;
pub use wasmer_wit::values::InterfaceValue as IValue;
pub(self) use wasmer_wit::ast::Type as IAstType;
pub(self) use wasmer_core::types::Type as WType;
pub(self) use wasmer_core::types::Value as WValue;
// types that often used together
pub(self) mod wit_prelude {
pub(super) use super::wit_instance::WITInstance;
pub(super) use super::exports::WITExport;
pub(super) use super::errors::WITFCEError;
pub(super) use super::wit_function::WITFunction;
pub(super) use super::memory::WITMemoryView;
pub(super) use super::memory::WITMemory;
}

View File

@ -14,18 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
pub mod errors; /// Contains converters of types and values between Wasmer and wasmer_interface_types.
pub mod exports;
pub mod memory;
pub mod wit_function;
pub mod wit_instance;
pub mod wit_module;
use wasmer_interface_types::types::InterfaceType as IType; use super::{WType, WValue, IType, IValue};
use wasmer_interface_types::values::InterfaceValue as IValue;
use wasmer_runtime_core::types::{Type as WType, Value as WValue};
pub fn wtype_to_itype(ty: &WType) -> IType { pub(super) fn wtype_to_itype(ty: &WType) -> IType {
match ty { match ty {
WType::I32 => IType::I32, WType::I32 => IType::I32,
WType::I64 => IType::I64, WType::I64 => IType::I64,
@ -35,7 +28,7 @@ pub fn wtype_to_itype(ty: &WType) -> IType {
} }
} }
pub fn itype_to_wtype(ty: &IType) -> WType { pub(super) fn itype_to_wtype(ty: &IType) -> WType {
match ty { match ty {
IType::I32 => WType::I32, IType::I32 => WType::I32,
IType::I64 => WType::I64, IType::I64 => WType::I64,
@ -45,7 +38,7 @@ pub fn itype_to_wtype(ty: &IType) -> WType {
} }
} }
pub fn ival_to_wval(value: &IValue) -> WValue { pub(super) fn ival_to_wval(value: &IValue) -> WValue {
match value { match value {
IValue::I32(v) => WValue::I32(*v), IValue::I32(v) => WValue::I32(*v),
IValue::I64(v) => WValue::I64(*v), IValue::I64(v) => WValue::I64(*v),
@ -55,7 +48,7 @@ pub fn ival_to_wval(value: &IValue) -> WValue {
} }
} }
pub fn wval_to_ival(value: &WValue) -> IValue { pub(super) fn wval_to_ival(value: &WValue) -> IValue {
match value { match value {
WValue::I32(v) => IValue::I32(*v), WValue::I32(v) => IValue::I32(*v),
WValue::I64(v) => IValue::I64(*v), WValue::I64(v) => IValue::I64(*v),

View File

@ -14,38 +14,41 @@
* limitations under the License. * limitations under the License.
*/ */
use crate::instance::errors::WITFCEError; use super::errors::WITFCEError;
use crate::instance::wit_module::WITModule; use super::fce_module::FCEModule;
use super::{IType, IValue, WValue};
use wasmer_wit::interpreter::wasm;
use wasmer_core::instance::DynFunc;
use std::sync::Arc; use std::sync::Arc;
use wasmer_interface_types::interpreter::wasm;
use wasmer_interface_types::{types::InterfaceType, values::InterfaceValue};
use wasmer_runtime_core::instance::DynFunc;
use wasmer_runtime_core::types::Value;
#[derive(Clone)] #[derive(Clone)]
enum WITFunctionInner { enum WITFunctionInner {
Export { Export {
func: Arc<DynFunc<'static>>, func: Arc<DynFunc<'static>>,
inputs: Vec<InterfaceType>, inputs: Vec<IType>,
outputs: Vec<InterfaceType>, outputs: Vec<IType>,
}, },
Import { Import {
// TODO: use WITInstance here instead of WITModule // TODO: use dyn Callable here
wit_module: Arc<WITModule>, wit_module: Arc<FCEModule>,
func_name: String, func_name: String,
inputs: Vec<InterfaceType>, inputs: Vec<IType>,
outputs: Vec<InterfaceType>, outputs: Vec<IType>,
}, },
} }
/// Represents all import and export functions that could be called from WIT context by call-core.
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct WITFunction { pub(super) struct WITFunction {
inner: WITFunctionInner, inner: WITFunctionInner,
} }
impl WITFunction { impl WITFunction {
pub fn from_export(dyn_func: DynFunc<'static>) -> Result<Self, WITFCEError> { /// Creates functions from a "usual" (not WIT) module export.
use super::wtype_to_itype; pub(super) fn from_export(dyn_func: DynFunc<'static>) -> Result<Self, WITFCEError> {
use super::type_converters::wtype_to_itype;
let signature = dyn_func.signature(); let signature = dyn_func.signature();
let inputs = signature let inputs = signature
@ -68,7 +71,8 @@ impl WITFunction {
Ok(Self { inner }) Ok(Self { inner })
} }
pub fn from_import(wit_module: Arc<WITModule>, func_name: String) -> Result<Self, WITFCEError> { /// Creates function from a module import.
pub(super) fn from_import(wit_module: Arc<FCEModule>, func_name: String) -> Result<Self, WITFCEError> {
let func_type = wit_module.as_ref().get_func_signature(&func_name)?; let func_type = wit_module.as_ref().get_func_signature(&func_name)?;
let inputs = func_type.0.clone(); let inputs = func_type.0.clone();
let outputs = func_type.1.clone(); let outputs = func_type.1.clone();
@ -84,16 +88,6 @@ impl WITFunction {
} }
} }
/*
impl std::ops::Deref for WITFuncs {
type Target = DynFunc<'static>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
*/
impl wasm::structures::LocalImport for WITFunction { impl wasm::structures::LocalImport for WITFunction {
fn inputs_cardinality(&self) -> usize { fn inputs_cardinality(&self) -> usize {
match &self.inner { match &self.inner {
@ -109,28 +103,28 @@ impl wasm::structures::LocalImport for WITFunction {
} }
} }
fn inputs(&self) -> &[InterfaceType] { fn inputs(&self) -> &[IType] {
match &self.inner { match &self.inner {
WITFunctionInner::Export { ref inputs, .. } => inputs, WITFunctionInner::Export { ref inputs, .. } => inputs,
WITFunctionInner::Import { ref inputs, .. } => inputs, WITFunctionInner::Import { ref inputs, .. } => inputs,
} }
} }
fn outputs(&self) -> &[InterfaceType] { fn outputs(&self) -> &[IType] {
match &self.inner { match &self.inner {
WITFunctionInner::Export { ref outputs, .. } => outputs, WITFunctionInner::Export { ref outputs, .. } => outputs,
WITFunctionInner::Import { ref outputs, .. } => outputs, WITFunctionInner::Import { ref outputs, .. } => outputs,
} }
} }
fn call(&self, arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()> { fn call(&self, arguments: &[IValue]) -> Result<Vec<IValue>, ()> {
use super::{ival_to_wval, wval_to_ival}; use super::type_converters::{ival_to_wval, wval_to_ival};
match &self.inner { match &self.inner {
WITFunctionInner::Export { func, .. } => func WITFunctionInner::Export { func, .. } => func
.as_ref() .as_ref()
.call(&arguments.iter().map(ival_to_wval).collect::<Vec<Value>>()) .call(&arguments.iter().map(ival_to_wval).collect::<Vec<WValue>>())
.map(|results| results.iter().map(wval_to_ival).collect()) .map(|result| result.iter().map(wval_to_ival).collect())
.map_err(|_| ()), .map_err(|_| ()),
WITFunctionInner::Import { WITFunctionInner::Import {
wit_module, wit_module,

View File

@ -14,38 +14,34 @@
* limitations under the License. * limitations under the License.
*/ */
use crate::instance::errors::WITFCEError; use super::wit_prelude::*;
use crate::instance::exports::WITExport; use super::fce_module::FCEModule;
use crate::instance::memory::{WITMemory, WITMemoryView};
use crate::instance::wit_function::WITFunction;
use wasmer_interface_types::interpreter::wasm; use wasmer_wit::interpreter::wasm;
use wasmer_runtime_core::Instance as WasmerInstance; use super::IAstType;
use wasmer_wit::ast::Interfaces;
use wasmer_wit::interpreter::wasm::structures::{
LocalImportIndex, TypedIndex,
};
use wasmer_core::Instance as WasmerInstance;
use crate::instance::wit_module::WITModule;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use wasmer_interface_types::ast::Interfaces;
use wasmer_interface_types::ast::Type;
use wasmer_interface_types::interpreter::wasm::structures::{
LocalImport, LocalImportIndex, TypedIndex,
};
use wasmer_interface_types::types::InterfaceType;
/// Contains all import and export functions that could be called from WIT context by call-core.
#[derive(Clone)] #[derive(Clone)]
pub struct WITInstance { pub(super) struct WITInstance {
// represent all import and export functions that could be called from WIT context
funcs: HashMap<usize, WITFunction>, funcs: HashMap<usize, WITFunction>,
memories: Vec<WITMemory>, memories: Vec<WITMemory>,
} }
impl WITInstance { impl WITInstance {
pub fn new( pub(super) fn new(
wasmer_instance: &WasmerInstance, wasmer_instance: &WasmerInstance,
interfaces: &Interfaces, interfaces: &Interfaces,
modules: &HashMap<String, Arc<WITModule>>, modules: &HashMap<String, Arc<FCEModule>>,
) -> Result<Self, WITFCEError> { ) -> Result<Self, WITFCEError> {
let mut exports = Self::extract_exports(&wasmer_instance, interfaces)?; let mut exports = Self::extract_raw_exports(&wasmer_instance, interfaces)?;
let imports = Self::extract_imports(modules, interfaces, exports.len())?; let imports = Self::extract_imports(modules, interfaces, exports.len())?;
let memories = Self::extract_memories(&wasmer_instance); let memories = Self::extract_memories(&wasmer_instance);
@ -55,25 +51,12 @@ impl WITInstance {
Ok(Self { funcs, memories }) Ok(Self { funcs, memories })
} }
#[allow(unused)] fn extract_raw_exports(
pub fn get_func_signature(
&self,
func_idx: usize,
) -> Result<(Vec<InterfaceType>, Vec<InterfaceType>), WITFCEError> {
match self.funcs.get(&func_idx) {
Some(func) => Ok((func.inputs().to_owned(), func.outputs().to_owned())),
None => Err(WITFCEError::NoSuchFunction(format!(
"function with idx = {} hasn't been found during its signature looking up",
func_idx
))),
}
}
fn extract_exports(
wasmer_instance: &WasmerInstance, wasmer_instance: &WasmerInstance,
interfaces: &Interfaces, interfaces: &Interfaces,
) -> Result<HashMap<usize, WITFunction>, WITFCEError> { ) -> Result<HashMap<usize, WITFunction>, WITFCEError> {
use wasmer_runtime_core::DynFunc; use wasmer_core::DynFunc;
let module_exports = &wasmer_instance.exports; let module_exports = &wasmer_instance.exports;
interfaces interfaces
@ -95,7 +78,7 @@ impl WITInstance {
/// Extracts only those imports that don't have implementations. /// Extracts only those imports that don't have implementations.
fn extract_imports( fn extract_imports(
modules: &HashMap<String, Arc<WITModule>>, modules: &HashMap<String, Arc<FCEModule>>,
interfaces: &Interfaces, interfaces: &Interfaces,
start_index: usize, start_index: usize,
) -> Result<HashMap<usize, WITFunction>, WITFCEError> { ) -> Result<HashMap<usize, WITFunction>, WITFCEError> {
@ -104,7 +87,7 @@ impl WITInstance {
.implementations .implementations
.iter() .iter()
.map(|i| (i.core_function_type, i.adapter_function_type)) .map(|i| (i.core_function_type, i.adapter_function_type))
.collect::<HashMap<_, _>>(); .collect::<HashMap<u32, u32>>();
let mut non_wit_callable_imports = HashMap::new(); let mut non_wit_callable_imports = HashMap::new();
@ -127,7 +110,7 @@ impl WITInstance {
} }
fn extract_memories(wasmer_instance: &WasmerInstance) -> Vec<WITMemory> { fn extract_memories(wasmer_instance: &WasmerInstance) -> Vec<WITMemory> {
use wasmer_runtime_core::export::Export::Memory; use wasmer_core::export::Export::Memory;
let mut memories = wasmer_instance let mut memories = wasmer_instance
.exports() .exports()
@ -148,11 +131,11 @@ impl WITInstance {
} }
} }
impl<'instance> wasm::structures::Instance<WITExport, WITFunction, WITMemory, WITMemoryView<'_>> impl wasm::structures::Instance<WITExport, WITFunction, WITMemory, WITMemoryView<'_>>
for WITInstance for WITInstance
{ {
fn export(&self, _export_name: &str) -> Option<&WITExport> { fn export(&self, _export_name: &str) -> Option<&WITExport> {
// exports aren't needed for this version of WIT // exports aren't used in this version of WIT
None None
} }
@ -171,7 +154,7 @@ impl<'instance> wasm::structures::Instance<WITExport, WITFunction, WITMemory, WI
} }
} }
fn wit_type(&self, _index: u32) -> Option<&Type> { fn wit_type(&self, _index: u32) -> Option<&IAstType> {
None None
} }
} }

28
wit_fce/src/vm/mod.rs Normal file
View File

@ -0,0 +1,28 @@
/*
* Copyright 2020 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.
*/
mod fce;
mod instance;
mod fce_service;
mod config;
mod prepare;
mod errors;
pub use fce::FCE;
pub use fce_service::FCEService;
pub use config::FCEModuleConfig;
pub use errors::FCEError;
pub use instance::{IType, IValue};

80
wit_fce/src/vm/prepare.rs Normal file
View File

@ -0,0 +1,80 @@
/*
* Copyright 2020 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.
*/
// Similar to
// https://github.com/paritytech/substrate/blob/master/srml/contracts/src/wasm/prepare.rs
// https://github.com/nearprotocol/nearcore/blob/master/runtime/near-vm-runner/src/prepare.rs
use super::errors::FCEError;
use parity_wasm::{
builder, elements,
elements::{MemorySection, MemoryType},
};
struct ModuleBootstrapper {
module: elements::Module,
}
impl<'a> ModuleBootstrapper {
fn init(module_code: &[u8]) -> Result<Self, FCEError> {
let module = elements::deserialize_buffer(module_code)?;
Ok(Self { module })
}
fn set_mem_pages_count(self, mem_pages_count: u32) -> Self {
let Self { mut module } = self;
// At now, there is could be only one memory section, so
// it needs just to extract previous initial page count,
// delete an old entry and add create a new one with updated limits
let mem_initial = match module.memory_section_mut() {
Some(section) => match section.entries_mut().pop() {
Some(entry) => entry.limits().initial(),
None => 0,
},
None => 0,
};
let memory_entry = MemoryType::new(mem_initial, Some(mem_pages_count));
let mut default_mem_section = MemorySection::default();
module
.memory_section_mut()
.unwrap_or_else(|| &mut default_mem_section)
.entries_mut()
.push(memory_entry);
let builder = builder::from_module(module);
Self {
module: builder.build(),
}
}
fn into_wasm(self) -> Result<Vec<u8>, FCEError> {
elements::serialize(self.module).map_err(Into::into)
}
}
/// Prepares a Wasm module:
/// - set memory page count
pub fn prepare_module(module: &[u8], mem_pages_count: u32) -> Result<Vec<u8>, FCEError> {
ModuleBootstrapper::init(module)?
.set_mem_pages_count(mem_pages_count)
.into_wasm()
}