@ -2,8 +2,8 @@ use crate::func::HostFunc;
use crate ::instance ::InstancePre ;
use crate ::store ::StoreOpaque ;
use crate ::{
AsContextMut , Caller , Engine , Extern , ExternType , Func , FuncType , ImportType , Instance ,
IntoFunc , Module , StoreContextMut , Val , ValRaw ,
AsContext , AsContext Mut, Caller , Engine , Extern , ExternType , Func , FuncType , ImportType ,
Instance , In toFunc , Module , StoreContextMut , Val , ValRaw ,
} ;
use anyhow ::{ bail , Context , Result } ;
use log ::warn ;
@ -113,10 +113,25 @@ struct ImportKey {
#[ derive(Clone) ]
pub ( crate ) enum Definition {
Extern ( Extern ) ,
Extern ( Extern , DefinitionType ) ,
HostFunc ( Arc < HostFunc > ) ,
}
/// This is a sort of slimmed down `ExternType` which notably doesn't have a
/// `FuncType`, which is an allocation, and additionally retains the current
/// size of the table/memory.
#[ derive(Clone) ]
pub ( crate ) enum DefinitionType {
Func ( wasmtime_runtime ::VMSharedSignatureIndex ) ,
Global ( wasmtime_environ ::Global ) ,
// Note that tables and memories store not only the original type
// information but additionally the current size of the table/memory, as
// this is used during linking since the min size specified in the type may
// no longer be the current size of the table/memory.
Table ( wasmtime_environ ::Table , u32 ) ,
Memory ( wasmtime_environ ::Memory , u64 ) ,
}
macro_rules ! generate_wrap_async_func {
( $num :tt $( $args :ident ) * ) = > ( paste ::paste ! {
/// Asynchronous analog of [`Linker::func_wrap`].
@ -296,7 +311,7 @@ impl<T> Linker<T> {
/// let mut linker = Linker::new(&engine);
/// let ty = GlobalType::new(ValType::I32, Mutability::Const);
/// let global = Global::new(&mut store, ty, Val::I32(0x1234))?;
/// linker.define(" host", "offset", global)?;
/// linker.define(&store, " host", "offset", global)?;
///
/// let wat = r#"
/// (module
@ -312,12 +327,14 @@ impl<T> Linker<T> {
/// ```
pub fn define (
& mut self ,
store : impl AsContext < Data = T > ,
module : & str ,
name : & str ,
item : impl Into < Extern > ,
) -> Result < & mut Self > {
let store = store . as_context ( ) ;
let key = self . import_key ( module , Some ( name ) ) ;
self . insert ( key , Definition ::Extern ( item . into ( ) ) ) ? ;
self . insert ( key , Definition ::new ( store . 0 , item . into ( ) ) ) ? ;
Ok ( self )
}
@ -327,9 +344,15 @@ impl<T> Linker<T> {
/// This is only relevant when working with the module linking proposal
/// where one-level names are allowed (in addition to two-level names).
/// Otherwise this method need not be used.
pub fn define_name ( & mut self , name : & str , item : impl Into < Extern > ) -> Result < & mut Self > {
pub fn define_name (
& mut self ,
store : impl AsContext < Data = T > ,
name : & str ,
item : impl Into < Extern > ,
) -> Result < & mut Self > {
let store = store . as_context ( ) ;
let key = self . import_key ( name , None ) ;
self . insert ( key , Definition ::Extern ( item . into ( ) ) ) ? ;
self . insert ( key , Definition ::new ( store . 0 , item . into ( ) ) ) ? ;
Ok ( self )
}
@ -542,9 +565,18 @@ impl<T> Linker<T> {
module_name : & str ,
instance : Instance ,
) -> Result < & mut Self > {
for export in instance . exports ( store . as_context_mut ( ) ) {
let key = self . import_key ( module_name , Some ( export . name ( ) ) ) ;
self . insert ( key , Definition ::Extern ( export . into_extern ( ) ) ) ? ;
let mut store = store . as_context_mut ( ) ;
let exports = instance
. exports ( & mut store )
. map ( | e | {
(
self . import_key ( module_name , Some ( e . name ( ) ) ) ,
e . into_extern ( ) ,
)
} )
. collect ::< Vec < _ > > ( ) ;
for ( key , export ) in exports {
self . insert ( key , Definition ::new ( store . 0 , export ) ) ? ;
}
Ok ( self )
}
@ -814,11 +846,11 @@ impl<T> Linker<T> {
let mut store = store . as_context_mut ( ) ;
for export in module . exports ( ) {
if let Some ( func_ty ) = export . ty ( ) . func ( ) {
let instance_pre = self . instantiate_pre ( & mut store , module ) ? ;
let instance_pre = self . instantiate_pre ( module ) ? ;
let export_name = export . name ( ) . to_owned ( ) ;
let func = mk_func ( & mut store , func_ty , export_name , instance_pre ) ;
let key = self . import_key ( module_name , Some ( export . name ( ) ) ) ;
self . insert ( key , Definition ::Extern ( func . into ( ) ) ) ? ;
self . insert ( key , Definition ::new ( store . 0 , func . into ( ) ) ) ? ;
} else if export . name ( ) = = "memory" & & export . ty ( ) . memory ( ) . is_some ( ) {
// Allow an exported "memory" memory for now.
} else if export . name ( ) = = "__indirect_function_table" & & export . ty ( ) . table ( ) . is_some ( )
@ -1003,7 +1035,8 @@ impl<T> Linker<T> {
mut store : impl AsContextMut < Data = T > ,
module : & Module ,
) -> Result < Instance > {
self . instantiate_pre ( & mut store , module ) ? . instantiate ( store )
self . _instantiate_pre ( module , Some ( store . as_context_mut ( ) . 0 ) ) ?
. instantiate ( store )
}
/// Attempts to instantiate the `module` provided. This is the same as
@ -1018,14 +1051,13 @@ impl<T> Linker<T> {
where
T : Send ,
{
self . instantiate_pre ( & mut store , module ) ?
self . _ instantiate_pre( module , Some ( store . as_context_mut ( ) . 0 ) ) ?
. instantiate_async ( store )
. await
}
/// Performs all checks necessary for instantiating `module` with this
/// linker within `store`, except that instantiation doesn't actually
/// finish.
/// linker, except that instantiation doesn't actually finish.
///
/// This method is used for front-loading type-checking information as well
/// as collecting the imports to use to instantiate a module with. The
@ -1060,7 +1092,7 @@ impl<T> Linker<T> {
/// )
/// "#;
/// let module = Module::new(&engine, wat)?;
/// let instance_pre = linker.instantiate_pre(&mut store, &m odule)?;
/// let instance_pre = linker.instantiate_pre(&module)?;
///
/// // Finish instantiation after the type-checking has all completed...
/// let instance = instance_pre.instantiate(&mut store)?;
@ -1078,17 +1110,36 @@ impl<T> Linker<T> {
/// # Ok(())
/// # }
/// ```
pub fn instantiate_pre (
pub fn instantiate_pre ( & self , module : & Module ) -> Result < InstancePre < T > > {
self . _instantiate_pre ( module , None )
}
/// This is split out to optionally take a `store` so that when the
/// `.instantiate` API is used we can get fresh up-to-date type information
/// for memories and their current size, if necessary.
///
/// Note that providing a `store` here is not required for correctness
/// per-se. If one is not provided, such as the with the `instantiate_pre`
/// API, then the type information used for memories and tables will reflect
/// their size when inserted into the linker rather than their current size.
/// This isn't expected to be much of a problem though since
/// per-store-`Linker` types are likely using `.instantiate(..)` and
/// per-`Engine` linkers don't have memories/tables in them.
fn _instantiate_pre (
& self ,
mut store : impl AsContextMut < Data = T > ,
module : & Module ,
store : Option < & StoreOpaque > ,
) -> Result < InstancePre < T > > {
let store = store . as_context_mut ( ) . 0 ;
let imports = module
let mut imports = module
. imports ( )
. map ( | import | self . _get_by_import ( & import ) )
. collect ::< Result < _ , _ > > ( ) ? ;
unsafe { InstancePre ::new ( store , module , imports ) }
. collect ::< Result < Vec < _ > , _ > > ( ) ? ;
if let Some ( store ) = store {
for import in imports . iter_mut ( ) {
import . update_size ( store ) ;
}
}
unsafe { InstancePre ::new ( module , imports ) }
}
/// Returns an iterator over all items defined in this `Linker`, in
@ -1217,12 +1268,24 @@ impl<T> Default for Linker<T> {
}
impl Definition {
fn new ( store : & StoreOpaque , item : Extern ) -> Definition {
let ty = DefinitionType ::from ( store , & item ) ;
Definition ::Extern ( item , ty )
}
pub ( crate ) fn ty ( & self ) -> DefinitionType {
match self {
Definition ::Extern ( _ , ty ) = > ty . clone ( ) ,
Definition ::HostFunc ( func ) = > DefinitionType ::Func ( func . sig_index ( ) ) ,
}
}
/// Note the unsafety here is due to calling `HostFunc::to_func`. The
/// requirement here is that the `T` that was originally used to create the
/// `HostFunc` matches the `T` on the store.
pub ( crate ) unsafe fn to_extern ( & self , store : & mut StoreOpaque ) -> Extern {
match self {
Definition ::Extern ( e ) = > e . clone ( ) ,
Definition ::Extern ( e , _ ) = > e . clone ( ) ,
Definition ::HostFunc ( func ) = > func . to_func ( store ) . into ( ) ,
}
}
@ -1231,17 +1294,56 @@ impl Definition {
/// `HostFunc::to_func_store_rooted`.
pub ( crate ) unsafe fn to_extern_store_rooted ( & self , store : & mut StoreOpaque ) -> Extern {
match self {
Definition ::Extern ( e ) = > e . clone ( ) ,
Definition ::Extern ( e , _ ) = > e . clone ( ) ,
Definition ::HostFunc ( func ) = > func . to_func_store_rooted ( store ) . into ( ) ,
}
}
pub ( crate ) fn comes_from_same_store ( & self , store : & StoreOpaque ) -> bool {
match self {
Definition ::Extern ( e ) = > e . comes_from_same_store ( store ) ,
Definition ::Extern ( e , _ ) = > e . comes_from_same_store ( store ) ,
Definition ::HostFunc ( _func ) = > true ,
}
}
fn update_size ( & mut self , store : & StoreOpaque ) {
match self {
Definition ::Extern ( Extern ::Memory ( m ) , DefinitionType ::Memory ( _ , size ) ) = > {
* size = m . internal_size ( store ) ;
}
Definition ::Extern ( Extern ::SharedMemory ( m ) , DefinitionType ::Memory ( _ , size ) ) = > {
* size = m . size ( ) ;
}
Definition ::Extern ( Extern ::Table ( m ) , DefinitionType ::Table ( _ , size ) ) = > {
* size = m . internal_size ( store ) ;
}
_ = > { }
}
}
}
impl DefinitionType {
pub ( crate ) fn from ( store : & StoreOpaque , item : & Extern ) -> DefinitionType {
let data = store . store_data ( ) ;
match item {
Extern ::Func ( f ) = > DefinitionType ::Func ( f . sig_index ( data ) ) ,
Extern ::Table ( t ) = > DefinitionType ::Table ( * t . wasmtime_ty ( data ) , t . internal_size ( store ) ) ,
Extern ::Global ( t ) = > DefinitionType ::Global ( * t . wasmtime_ty ( data ) ) ,
Extern ::Memory ( t ) = > {
DefinitionType ::Memory ( * t . wasmtime_ty ( data ) , t . internal_size ( store ) )
}
Extern ::SharedMemory ( t ) = > DefinitionType ::Memory ( * t . ty ( ) . wasmtime_memory ( ) , t . size ( ) ) ,
}
}
pub ( crate ) fn desc ( & self ) -> & 'static str {
match self {
DefinitionType ::Func ( _ ) = > "function" ,
DefinitionType ::Table ( . . ) = > "table" ,
DefinitionType ::Memory ( . . ) = > "memory" ,
DefinitionType ::Global ( _ ) = > "global" ,
}
}
}
/// Modules can be interpreted either as Commands or Reactors.