Offline host module builder

This commit is contained in:
Sergey Pepyakin
2017-12-11 19:22:45 +01:00
parent 8d3b32f4a6
commit 40ea6edbe6
4 changed files with 120 additions and 37 deletions

View File

@ -3,28 +3,47 @@ use std::sync::Arc;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::collections::HashMap; use std::collections::HashMap;
use elements::{FunctionType, ValueType, GlobalType, MemoryType, TableType}; use elements::{FunctionType, ValueType, GlobalType, MemoryType, TableType};
use interpreter::store::{Store, ExternVal}; use interpreter::store::{Store, ExternVal, ModuleId, ModuleInstance};
use interpreter::value::RuntimeValue; use interpreter::value::RuntimeValue;
use interpreter::Error; use interpreter::Error;
pub struct HostModuleBuilder<'a, St> { enum HostItem {
store: &'a mut Store, Func {
exports: HashMap<String, ExternVal>, name: String,
func_type: FunctionType,
host_func: Arc<AnyFunc>,
},
Global {
name: String,
global_type: GlobalType,
init_val: RuntimeValue,
},
Memory {
name: String,
memory_type: MemoryType,
},
Table {
name: String,
table_type: TableType,
}
}
pub struct HostModuleBuilder<St> {
items: Vec<HostItem>,
_marker: PhantomData<St>, _marker: PhantomData<St>,
} }
impl<'a, St: 'static> HostModuleBuilder<'a, St> { impl<St: 'static> HostModuleBuilder<St> {
pub fn new(store: &'a mut Store) -> Self { pub fn new() -> Self {
HostModuleBuilder { HostModuleBuilder {
store: store, items: Vec::new(),
exports: HashMap::new(),
_marker: PhantomData, _marker: PhantomData,
} }
} }
pub fn with_func1< pub fn with_func1<
Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error> + 'static, Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error> + 'static,
Ret: AsReturn + 'static, Ret: AsReturnVal + 'static,
P1: FromArg + 'static, P1: FromArg + 'static,
F: Into<Func1<Cl, St, Ret, P1>>, F: Into<Func1<Cl, St, Ret, P1>>,
>( >(
@ -33,29 +52,78 @@ impl<'a, St: 'static> HostModuleBuilder<'a, St> {
f: F, f: F,
) { ) {
let func_type = Func1::<Cl, St, Ret, P1>::derive_func_type(); let func_type = Func1::<Cl, St, Ret, P1>::derive_func_type();
let type_id = self.store.alloc_func_type(func_type); let host_func = Arc::new(f.into()) as Arc<AnyFunc>;
let anyfunc = Arc::new(f.into()) as Arc<AnyFunc>; self.items.push(HostItem::Func {
name: name.to_owned(),
let func_id = self.store.alloc_host_func(type_id, anyfunc); func_type,
self.exports.insert(name.to_owned(), ExternVal::Func(func_id)); host_func,
});
} }
pub fn with_global(&mut self, name: &str, global_type: GlobalType, val: RuntimeValue) { pub fn with_global(&mut self, name: &str, global_type: GlobalType, init_val: RuntimeValue) {
let global_id = self.store.alloc_global(global_type, val); self.items.push(HostItem::Global {
self.exports.insert(name.to_owned(), ExternVal::Global(global_id)); name: name.to_owned(),
global_type,
init_val,
});
} }
pub fn with_memory(&mut self, name: &str, memory_type: &MemoryType) -> Result<(), Error> { pub fn with_memory(&mut self, name: &str, memory_type: MemoryType) {
let memory_id = self.store.alloc_memory(memory_type)?; self.items.push(HostItem::Memory {
self.exports.insert(name.to_owned(), ExternVal::Memory(memory_id)); name: name.to_owned(),
Ok(()) memory_type,
});
} }
pub fn with_table(&mut self, name: &str, table_type: &TableType) -> Result<(), Error> { pub fn with_table(&mut self, name: &str, table_type: TableType) {
let table_id = self.store.alloc_table(table_type)?; self.items.push(HostItem::Table {
self.exports.insert(name.to_owned(), ExternVal::Table(table_id)); name: name.to_owned(),
Ok(()) table_type,
});
}
pub fn build(self) -> HostModule {
HostModule {
items: self.items
}
}
}
pub struct HostModule {
items: Vec<HostItem>,
}
impl HostModule {
pub(crate) fn allocate(self, store: &mut Store) -> Result<ModuleId, Error> {
let mut exports = HashMap::new();
for item in self.items {
match item {
HostItem::Func { name, func_type, host_func } => {
let type_id = store.alloc_func_type(func_type);
let func_id = store.alloc_host_func(type_id, host_func);
exports.insert(name, ExternVal::Func(func_id));
},
HostItem::Global { name, global_type, init_val } => {
let global_id = store.alloc_global(global_type, init_val);
exports.insert(name, ExternVal::Global(global_id));
},
HostItem::Memory { name, memory_type } => {
let memory_id = store.alloc_memory(&memory_type)?;
exports.insert(name, ExternVal::Memory(memory_id));
},
HostItem::Table { name, table_type } => {
let table_id = store.alloc_table(&table_type)?;
exports.insert(name, ExternVal::Table(table_id));
}
}
}
let host_module_instance = ModuleInstance::with_exports(exports);
let module_id = store.add_module_instance(host_module_instance);
Ok(module_id)
} }
} }
@ -85,12 +153,12 @@ impl FromArg for i32 {
} }
} }
pub trait AsReturn { pub trait AsReturnVal {
fn as_return_val(self) -> Option<RuntimeValue>; fn as_return_val(self) -> Option<RuntimeValue>;
fn value_type() -> Option<ValueType>; fn value_type() -> Option<ValueType>;
} }
impl AsReturn for i32 { impl AsReturnVal for i32 {
fn as_return_val(self) -> Option<RuntimeValue> { fn as_return_val(self) -> Option<RuntimeValue> {
Some(self.into()) Some(self.into())
} }
@ -100,7 +168,7 @@ impl AsReturn for i32 {
} }
} }
impl AsReturn for () { impl AsReturnVal for () {
fn as_return_val(self) -> Option<RuntimeValue> { fn as_return_val(self) -> Option<RuntimeValue> {
None None
} }
@ -110,14 +178,14 @@ impl AsReturn for () {
} }
} }
pub struct Func1<Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error>, St, Ret: AsReturn, P1: FromArg> { pub struct Func1<Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error>, St, Ret: AsReturnVal, P1: FromArg> {
closure: Cl, closure: Cl,
_marker: PhantomData<(St, Ret, P1)>, _marker: PhantomData<(St, Ret, P1)>,
} }
impl< impl<
St: 'static, St: 'static,
Ret: AsReturn, Ret: AsReturnVal,
P1: FromArg, P1: FromArg,
Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error>, Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error>,
> AnyFunc for Func1<Cl, St, Ret, P1> { > AnyFunc for Func1<Cl, St, Ret, P1> {
@ -133,7 +201,7 @@ impl<
} }
} }
impl<St: 'static, Ret: AsReturn, P1: FromArg, Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error>> From<Cl> impl<St: 'static, Ret: AsReturnVal, P1: FromArg, Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error>> From<Cl>
for Func1<Cl, St, Ret, P1> { for Func1<Cl, St, Ret, P1> {
fn from(cl: Cl) -> Self { fn from(cl: Cl) -> Self {
Func1 { Func1 {
@ -145,7 +213,7 @@ impl<St: 'static, Ret: AsReturn, P1: FromArg, Cl: Fn(&mut St, P1) -> Result<Opti
impl< impl<
St: 'static, St: 'static,
Ret: AsReturn, Ret: AsReturnVal,
P1: FromArg, P1: FromArg,
Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error>, Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error>,
> Func1<Cl, St, Ret, P1> { > Func1<Cl, St, Ret, P1> {

View File

@ -150,3 +150,4 @@ pub use self::table::TableInstance;
pub use self::program::ProgramInstance; pub use self::program::ProgramInstance;
pub use self::value::RuntimeValue; pub use self::value::RuntimeValue;
pub use self::variable::{VariableInstance, VariableType, ExternalVariableValue}; pub use self::variable::{VariableInstance, VariableType, ExternalVariableValue};
pub use self::host::{HostModule, HostModuleBuilder, Func1, AnyFunc, AsReturnVal, FromArg};

View File

@ -3,7 +3,7 @@ use std::collections::HashMap;
use elements::Module; use elements::Module;
use interpreter::Error; use interpreter::Error;
use interpreter::store::{Store, ModuleId}; use interpreter::store::{Store, ModuleId};
use interpreter::host::HostModuleBuilder; use interpreter::host::HostModule;
/// Program instance. Program is a set of instantiated modules. /// Program instance. Program is a set of instantiated modules.
pub struct ProgramInstance { pub struct ProgramInstance {
@ -37,13 +37,15 @@ impl ProgramInstance {
} }
let module_id = self.store.instantiate_module(&module, &extern_vals, state)?; let module_id = self.store.instantiate_module(&module, &extern_vals, state)?;
self.modules.insert(name.to_string(), module_id); self.modules.insert(name.to_owned(), module_id);
Ok(module_id) Ok(module_id)
} }
pub fn with_host_module<St: 'static>(&mut self, name: &str) -> HostModuleBuilder<St> { pub fn add_host_module(&mut self, name: &str, host_module: HostModule) -> Result<ModuleId, Error> {
HostModuleBuilder::new(&mut self.store) let module_id = host_module.allocate(&mut self.store)?;
self.modules.insert(name.to_owned(), module_id);
Ok(module_id)
} }
/// Get one of the modules by name /// Get one of the modules by name

View File

@ -181,7 +181,7 @@ pub struct ExportInstance {
} }
#[derive(Default)] #[derive(Default)]
struct ModuleInstance { pub struct ModuleInstance {
types: Vec<TypeId>, types: Vec<TypeId>,
funcs: Vec<FuncId>, funcs: Vec<FuncId>,
tables: Vec<TableId>, tables: Vec<TableId>,
@ -194,6 +194,12 @@ impl ModuleInstance {
fn new() -> ModuleInstance { fn new() -> ModuleInstance {
ModuleInstance::default() ModuleInstance::default()
} }
pub fn with_exports(exports: HashMap<String, ExternVal>) -> ModuleInstance {
ModuleInstance {
exports, ..Default::default()
}
}
} }
#[derive(Default)] #[derive(Default)]
@ -474,6 +480,12 @@ impl Store {
Ok(module_id) Ok(module_id)
} }
pub fn add_module_instance(&mut self, instance: ModuleInstance) -> ModuleId {
self.modules.push(instance);
let module_id = self.modules.len() - 1;
ModuleId(module_id as u32)
}
pub fn invoke<St: 'static>( pub fn invoke<St: 'static>(
&mut self, &mut self,
func: FuncId, func: FuncId,