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
2020-06-01 02:45:04 +03:00
use multimap ::MultiMap ;
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-01 02:45:04 +03:00
) -> Result < Self , WITFCEError > {
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 ] ,
) -> Result < Vec < IValue > , WITFCEError > {
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 00:12:23 +03:00
None = > Err ( WITFCEError ::NoSuchFunction ( format! (
" {} 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 17:20:00 +03:00
) -> Result < ( & Vec < IType > , & Vec < IType > ) , WITFCEError > {
match self . exports_funcs . get ( function_name ) {
2020-06-01 12:14:12 +03:00
Some ( ( _ , inputs , outputs ) ) = > Ok ( ( inputs , outputs ) ) ,
2020-06-01 02:45:04 +03:00
None = > Err ( WITFCEError ::NoSuchFunction ( format! (
" {} 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 17:20:00 +03:00
fn extract_wit ( wasmer_instance : & WasmerModule ) -> Result < Interfaces , WITFCEError > {
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 ,
2020-06-02 01:02:22 +03:00
) -> Result < HashMap < String , WITModuleFunc > , WITFCEError > {
2020-06-02 17:20:00 +03:00
use super ::IAstType ;
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 )
. ok_or_else ( | | WITFCEError ::NoSuchFunction (
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
return Err ( WITFCEError ::NoSuchFunction ( format! (
" {} 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 {
return Err ( WITFCEError ::NoSuchFunction ( format! (
" 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 (
interfaces : & Interfaces ,
wit_instance : Arc < MaybeUninit < WITInstance > > ,
) -> Result < ImportObject , WITFCEError > {
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 )
. ok_or_else ( | | WITFCEError ::NoSuchFunction ( format! ( " function with idx = {} hasn't been found during adjusting imports in WIT implementation " , adapter . function_type ) ) ) ? ;
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
return Err ( WITFCEError ::NoSuchFunction ( format! (
" {} 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
return Err ( WITFCEError ::WasmerResolveError ( format! (
" 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
}