Files
marine/wit_fce/src/vm/instance/fce_module.rs

303 lines
11 KiB
Rust
Raw Normal View History

2020-05-30 01:55:39 +03:00
/*
* 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.
*/
2020-06-02 17:20:00 +03:00
use super::wit_prelude::*;
use super::{IType, IValue, WValue};
use wasmer_wit::ast::Interfaces;
use wasmer_wit::interpreter::Interpreter;
2020-05-30 01:55:39 +03:00
use wasmer_runtime::{compile, ImportObject};
2020-06-02 17:20:00 +03:00
use wasmer_core::Module as WasmerModule;
use wasmer_core::Instance as WasmerInstance;
use wasmer_core::import::Namespace;
2020-05-30 01:55:39 +03:00
use std::collections::HashMap;
use std::convert::TryInto;
2020-06-01 02:45:04 +03:00
use std::mem::MaybeUninit;
use std::sync::Arc;
2020-05-30 01:55:39 +03:00
const WIT_SECTION_NAME: &str = "interface-types";
2020-06-01 02:45:04 +03:00
type WITInterpreter =
Interpreter<WITInstance, WITExport, WITFunction, WITMemory, WITMemoryView<'static>>;
2020-06-02 17:20:00 +03:00
// TODO: introduce new trait instead of type
type WITModuleFunc = (WITInterpreter, Vec<IType>, Vec<IType>);
2020-05-30 01:55:39 +03:00
2020-06-02 17:20:00 +03:00
pub struct FCEModule {
// it is needed because of WITInstance contains dynamic functions
// that internally keep pointer to Wasmer instance.
2020-06-02 00:12:23 +03:00
#[allow(unused)]
2020-06-02 17:20:00 +03:00
wamser_instance: WasmerInstance,
2020-06-01 02:45:04 +03:00
wit_instance: Arc<WITInstance>,
2020-06-02 17:20:00 +03:00
exports_funcs: HashMap<String, WITModuleFunc>,
2020-05-30 01:55:39 +03:00
}
2020-06-02 17:20:00 +03:00
impl FCEModule {
2020-06-01 02:45:04 +03:00
pub fn new(
wasm_bytes: &[u8],
imports: ImportObject,
2020-06-02 17:20:00 +03:00
modules: &HashMap<String, Arc<FCEModule>>,
2020-06-02 19:16:15 +03:00
) -> Result<Self, FCEError> {
2020-06-02 17:20:00 +03:00
let wasmer_module = compile(&wasm_bytes)?;
let wit = Self::extract_wit(&wasmer_module)?;
let wit_exports = Self::instantiate_wit_exports(&wit)?;
2020-05-30 01:55:39 +03:00
2020-06-01 02:45:04 +03:00
let mut wit_instance = Arc::new_uninit();
2020-06-02 17:20:00 +03:00
let mut import_object = Self::adjust_imports(&wit, wit_instance.clone())?;
2020-06-01 02:45:04 +03:00
import_object.extend(imports);
2020-05-30 01:55:39 +03:00
2020-06-02 17:20:00 +03:00
let wasmer_instance = wasmer_module.instantiate(&import_object)?;
2020-05-30 01:55:39 +03:00
2020-06-01 02:45:04 +03:00
let wit_instance = unsafe {
2020-06-02 00:12:23 +03:00
// get_mut_unchecked here is safe because currently only this modules have reference to
// it and the environment is single-threaded
2020-06-01 02:45:04 +03:00
*Arc::get_mut_unchecked(&mut wit_instance) =
2020-06-02 17:20:00 +03:00
MaybeUninit::new(WITInstance::new(&wasmer_instance, &wit, modules)?);
2020-06-01 02:45:04 +03:00
std::mem::transmute::<_, Arc<WITInstance>>(wit_instance)
};
2020-05-30 01:55:39 +03:00
Ok(Self {
2020-06-02 17:20:00 +03:00
wamser_instance: wasmer_instance,
2020-05-30 01:55:39 +03:00
wit_instance,
2020-06-02 17:20:00 +03:00
exports_funcs: wit_exports,
2020-05-30 01:55:39 +03:00
})
}
pub fn call(
&mut self,
function_name: &str,
2020-06-02 17:20:00 +03:00
args: &[IValue],
2020-06-02 19:16:15 +03:00
) -> Result<Vec<IValue>, FCEError> {
2020-06-02 17:20:00 +03:00
use wasmer_wit::interpreter::stack::Stackable;
match self.exports_funcs.get(function_name) {
2020-05-30 01:55:39 +03:00
Some(func) => {
2020-06-02 00:12:23 +03:00
let result = func
.0
.run(args, Arc::make_mut(&mut self.wit_instance))?
.as_slice()
.to_owned();
2020-05-30 01:55:39 +03:00
Ok(result)
}
2020-06-02 19:16:15 +03:00
None => Err(FCEError::NoSuchFunction(format!(
2020-06-02 00:12:23 +03:00
"{} hasn't been found while calling",
function_name
))),
2020-06-01 02:45:04 +03:00
}
}
pub fn get_func_signature(
&self,
function_name: &str,
2020-06-02 19:16:15 +03:00
) -> Result<(&Vec<IType>, &Vec<IType>), FCEError> {
2020-06-02 17:20:00 +03:00
match self.exports_funcs.get(function_name) {
2020-06-01 12:14:12 +03:00
Some((_, inputs, outputs)) => Ok((inputs, outputs)),
2020-06-02 19:16:15 +03:00
None => Err(FCEError::NoSuchFunction(format!(
2020-06-01 02:45:04 +03:00
"{} has't been found during its signature looking up",
function_name
))),
2020-05-30 01:55:39 +03:00
}
}
2020-06-01 02:45:04 +03:00
2020-06-02 19:16:15 +03:00
fn extract_wit(wasmer_module: &WasmerModule) -> Result<Interfaces<'_>, FCEError> {
let wit_sections = wasmer_module
2020-06-02 17:20:00 +03:00
.custom_sections(WIT_SECTION_NAME)
2020-06-02 19:16:15 +03:00
.ok_or_else(|| FCEError::NoWITSection)?;
2020-06-02 17:20:00 +03:00
if wit_sections.len() > 1 {
2020-06-02 19:16:15 +03:00
return Err(FCEError::MultipleWITSections);
2020-06-02 17:20:00 +03:00
}
let (remainder, interfaces) = wasmer_wit::decoders::binary::parse::<()>(&wit_sections[0])
2020-06-02 19:16:15 +03:00
.map_err(|_e| FCEError::WITParseError)?;
2020-06-02 17:20:00 +03:00
if remainder.len() > 1 {
2020-06-02 19:16:15 +03:00
return Err(FCEError::WITRemainderNotEmpty);
2020-06-02 17:20:00 +03:00
}
Ok(interfaces)
}
fn instantiate_wit_exports(
2020-06-02 19:16:15 +03:00
wit: &Interfaces<'_>,
) -> Result<HashMap<String, WITModuleFunc>, FCEError> {
2020-06-02 17:20:00 +03:00
use super::IAstType;
2020-06-02 19:16:15 +03:00
use multimap::MultiMap;
2020-06-02 17:20:00 +03:00
let exports_type_to_names = wit
2020-06-01 02:45:04 +03:00
.exports
.iter()
.map(|export| (export.function_type, export.name.to_string()))
.collect::<MultiMap<_, _>>();
2020-06-02 17:20:00 +03:00
let adapter_type_to_instructions = wit
2020-06-01 02:45:04 +03:00
.adapters
.iter()
.map(|adapter| (adapter.function_type, &adapter.instructions))
.collect::<HashMap<_, _>>();
let mut wit_callable_exports = HashMap::new();
2020-06-02 17:20:00 +03:00
for i in wit.implementations.iter() {
2020-06-01 02:45:04 +03:00
let export_function_names = match exports_type_to_names.get_vec(&i.core_function_type) {
Some(export_function_names) => export_function_names,
None => continue,
};
// * just to remove reference
let adapter_instructions = *adapter_type_to_instructions
.get(&i.adapter_function_type)
2020-06-02 19:16:15 +03:00
.ok_or_else(|| FCEError::NoSuchFunction(
2020-06-01 02:45:04 +03:00
format!("adapter function with idx = {} hasn't been found during extracting exports by implementations", i.adapter_function_type)
))?;
2020-06-02 17:20:00 +03:00
if i.adapter_function_type >= wit.types.len() as u32 {
2020-06-01 12:14:12 +03:00
// TODO: change error type
2020-06-02 19:16:15 +03:00
return Err(FCEError::NoSuchFunction(format!(
2020-06-01 12:14:12 +03:00
"{} function id is bigger than WIT interface types count",
i.adapter_function_type
)));
};
2020-06-01 02:45:04 +03:00
2020-06-02 17:20:00 +03:00
if let IAstType::Function { inputs, outputs } =
&wit.types[i.adapter_function_type as usize]
2020-06-01 12:14:12 +03:00
{
for export_function_name in export_function_names.iter() {
// TODO: handle errors
let interpreter: WITInterpreter = adapter_instructions.try_into().unwrap();
wit_callable_exports.insert(
export_function_name.to_owned(),
(interpreter, inputs.clone(), outputs.clone()),
);
}
} else {
2020-06-02 19:16:15 +03:00
return Err(FCEError::NoSuchFunction(format!(
2020-06-01 12:14:12 +03:00
"type with idx = {} isn't a function type",
i.adapter_function_type
)));
2020-06-01 02:45:04 +03:00
}
}
Ok(wit_callable_exports)
}
// this function deals only with import functions that have an adaptor implementation
fn adjust_imports(
2020-06-02 19:16:15 +03:00
interfaces: &Interfaces<'_>,
2020-06-01 02:45:04 +03:00
wit_instance: Arc<MaybeUninit<WITInstance>>,
2020-06-02 19:16:15 +03:00
) -> Result<ImportObject, FCEError> {
2020-06-02 17:20:00 +03:00
use super::IAstType;
use super::type_converters::{itype_to_wtype, wval_to_ival};
use wasmer_core::typed_func::DynamicFunc;
use wasmer_core::types::FuncSig;
use wasmer_core::vm::Ctx;
2020-06-01 02:45:04 +03:00
// returns function that will be called from imports of Wasmer module
2020-06-02 17:20:00 +03:00
fn dyn_func_from_imports<F>(inputs: Vec<IType>, func: F) -> DynamicFunc<'static>
2020-06-01 02:45:04 +03:00
where
2020-06-02 17:20:00 +03:00
F: Fn(&mut Ctx, &[WValue]) -> Vec<WValue> + 'static,
2020-06-01 02:45:04 +03:00
{
let signature = inputs.iter().map(itype_to_wtype).collect::<Vec<_>>();
DynamicFunc::new(Arc::new(FuncSig::new(signature, vec![])), func)
}
// uses to filter out import functions that have an adapter implementation
let adapter_to_core = interfaces
.implementations
.iter()
.map(|i| (i.adapter_function_type, i.core_function_type))
.collect::<HashMap<_, _>>();
// all wit imports
let mut export_type_to_name = interfaces
.imports
.iter()
.map(|import| {
(
import.function_type,
(import.namespace.to_string(), import.name.to_string()),
)
})
.collect::<HashMap<_, _>>();
let mut import_namespaces: HashMap<String, Namespace> = HashMap::new();
for adapter in interfaces.adapters.iter() {
let core_function_idx = adapter_to_core
.get(&adapter.function_type)
2020-06-02 19:16:15 +03:00
.ok_or_else(|| FCEError::NoSuchFunction(format!("function with idx = {} hasn't been found during adjusting imports in WIT implementation", adapter.function_type)))?;
2020-06-01 02:45:04 +03:00
let (namespace, func_name) = match export_type_to_name.remove(core_function_idx) {
Some(v) => (v.0, v.1),
None => continue,
};
if adapter.function_type >= interfaces.types.len() as u32 {
// TODO: change error type
2020-06-02 19:16:15 +03:00
return Err(FCEError::NoSuchFunction(format!(
2020-06-01 02:45:04 +03:00
"{} function id is bigger than WIT interface types count",
adapter.function_type
)));
}
2020-06-02 17:20:00 +03:00
if let IAstType::Function { inputs, .. } =
2020-06-01 02:45:04 +03:00
&interfaces.types[adapter.function_type as usize]
{
let instructions = &adapter.instructions;
let interpreter: WITInterpreter = instructions.try_into().unwrap();
let wit_instance = wit_instance.clone();
2020-06-02 01:02:22 +03:00
let wit_inner_import =
2020-06-02 17:20:00 +03:00
Box::new(move |_: &mut Ctx, inputs: &[WValue]| -> Vec<WValue> {
2020-06-02 01:02:22 +03:00
// copy here to because otherwise wit_instance will be consumed by the closure
let wit_instance_callable = wit_instance.clone();
let converted_inputs = inputs.iter().map(wval_to_ival).collect::<Vec<_>>();
unsafe {
// error here will be propagated by the special error instruction
let _ = interpreter.run(
&converted_inputs,
Arc::make_mut(&mut wit_instance_callable.assume_init()),
);
}
// wit import functions should only change the stack state -
// the result will be returned by an export function
vec![]
});
let wit_import = dyn_func_from_imports(inputs.clone(), wit_inner_import);
// TODO: refactor this
let mut module_namespace = Namespace::new();
module_namespace.insert(func_name.clone(), wit_import);
import_namespaces.insert(namespace, module_namespace);
2020-06-01 02:45:04 +03:00
} else {
// TODO: change error type
2020-06-02 19:16:15 +03:00
return Err(FCEError::WasmerResolveError(format!(
2020-06-01 02:45:04 +03:00
"WIT type with idx = {} doesn't refer to function",
adapter.function_type
)));
}
}
let mut import_object = ImportObject::new();
for (namespace_name, namespace) in import_namespaces.into_iter() {
import_object.register(namespace_name, namespace);
}
Ok(import_object)
}
2020-05-30 01:55:39 +03:00
}