mirror of
https://github.com/fluencelabs/marine.git
synced 2024-12-12 14:55:32 +00:00
introduce service-like functionality
This commit is contained in:
parent
880bb6f87e
commit
b258caa8d6
27
Cargo.lock
generated
27
Cargo.lock
generated
@ -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]]
|
||||||
|
@ -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>;
|
||||||
|
@ -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"
|
||||||
|
@ -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"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
@ -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 {
|
|
||||||
|
|
||||||
}
|
|
37
wit_fce/src/misc/slice_pretty_printer.rs
Normal file
37
wit_fce/src/misc/slice_pretty_printer.rs
Normal 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
102
wit_fce/src/vm/config.rs
Normal 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
124
wit_fce/src/vm/errors.rs
Normal 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
91
wit_fce/src/vm/fce.rs
Normal 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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
wit_fce/src/vm/fce_service.rs
Normal file
38
wit_fce/src/vm/fce_service.rs
Normal 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>;
|
||||||
|
}
|
@ -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 {
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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<_>>();
|
@ -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>();
|
41
wit_fce/src/vm/instance/mod.rs
Normal file
41
wit_fce/src/vm/instance/mod.rs
Normal 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;
|
||||||
|
}
|
@ -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),
|
@ -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,
|
@ -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
28
wit_fce/src/vm/mod.rs
Normal 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
80
wit_fce/src/vm/prepare.rs
Normal 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()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user