Host modules now ImportResolvers

This commit is contained in:
Sergey Pepyakin
2017-12-14 15:33:40 +01:00
parent e49b849624
commit e7a9f0953e
5 changed files with 122 additions and 133 deletions

View File

@ -44,6 +44,30 @@ impl fmt::Debug for FuncInstance {
}
impl FuncInstance {
pub fn alloc_internal(
module: Rc<ModuleInstance>,
func_type: Rc<FunctionType>,
body: FuncBody,
) -> Rc<Self> {
let func = FuncInstance::Internal {
func_type,
module: module,
body: Rc::new(body),
};
Rc::new(func)
}
pub fn alloc_host(
func_type: Rc<FunctionType>,
host_func: Rc<AnyFunc>,
) -> Rc<Self> {
let func = FuncInstance::Host {
func_type,
host_func,
};
Rc::new(func)
}
pub fn func_type(&self) -> Rc<FunctionType> {
match *self {
FuncInstance::Internal { ref func_type, .. } |
@ -57,9 +81,7 @@ impl FuncInstance {
FuncInstance::Host { .. } => None,
}
}
}
impl FuncInstance {
pub fn invoke<St: 'static>(
func: Rc<FuncInstance>,
args: Vec<RuntimeValue>,

View File

@ -2,6 +2,7 @@ use std::any::Any;
use std::rc::Rc;
use std::marker::PhantomData;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use elements::{FunctionType, ValueType, GlobalType, MemoryType, TableType};
use interpreter::module::{ExternVal, ModuleInstance};
use interpreter::func::FuncInstance;
@ -10,46 +11,22 @@ use interpreter::memory::MemoryInstance;
use interpreter::table::TableInstance;
use interpreter::value::RuntimeValue;
use interpreter::Error;
enum HostItem {
Func {
name: String,
func_type: FunctionType,
host_func: Rc<AnyFunc>,
},
Global {
name: String,
global_type: GlobalType,
init_val: RuntimeValue,
},
Memory {
name: String,
memory_type: MemoryType,
},
Table {
name: String,
table_type: TableType,
},
ExternVal {
name: String,
extern_val: ExternVal,
}
}
use interpreter::ImportResolver;
pub struct HostModuleBuilder<St> {
items: Vec<HostItem>,
exports: HashMap<String, ExternVal>,
_marker: PhantomData<St>,
}
impl<St: 'static> HostModuleBuilder<St> {
pub fn new() -> Self {
HostModuleBuilder {
items: Vec::new(),
exports: HashMap::new(),
_marker: PhantomData,
}
}
pub fn with_func0<
pub fn insert_func0<
Cl: Fn(&mut St) -> Result<Option<Ret>, Error> + 'static,
Ret: AsReturnVal + 'static,
F: Into<Func0<Cl, St, Ret>>,
@ -61,12 +38,8 @@ impl<St: 'static> HostModuleBuilder<St> {
) {
let func_type = Func0::<Cl, St, Ret>::derive_func_type();
let host_func = Rc::new(f.into()) as Rc<AnyFunc>;
self.items.push(HostItem::Func {
name: name.into(),
func_type,
host_func,
});
let func = FuncInstance::alloc_host(Rc::new(func_type), host_func);
self.insert_func(name, func);
}
pub fn with_func1<
@ -82,12 +55,8 @@ impl<St: 'static> HostModuleBuilder<St> {
) {
let func_type = Func1::<Cl, St, Ret, P1>::derive_func_type();
let host_func = Rc::new(f.into()) as Rc<AnyFunc>;
self.items.push(HostItem::Func {
name: name.into(),
func_type,
host_func,
});
let func = FuncInstance::alloc_host(Rc::new(func_type), host_func);
self.insert_func(name, func);
}
pub fn with_func2<
@ -104,87 +73,97 @@ impl<St: 'static> HostModuleBuilder<St> {
) {
let func_type = Func2::<Cl, St, Ret, P1, P2>::derive_func_type();
let host_func = Rc::new(f.into()) as Rc<AnyFunc>;
self.items.push(HostItem::Func {
name: name.into(),
func_type,
host_func,
});
let func = FuncInstance::alloc_host(Rc::new(func_type), host_func);
self.insert_func(name, func);
}
pub fn with_global<N: Into<String>>(&mut self, name: N, global_type: GlobalType, init_val: RuntimeValue) {
self.items.push(HostItem::Global {
name: name.into(),
global_type,
init_val,
});
pub fn insert_func<N: Into<String>>(&mut self, name: N, func: Rc<FuncInstance>) {
self.insert(name, ExternVal::Func(func));
}
pub fn with_memory<N: Into<String>>(&mut self, name: N, memory_type: MemoryType) {
self.items.push(HostItem::Memory {
name: name.into(),
memory_type,
});
pub fn insert_global<N: Into<String>>(&mut self, name: N, global: Rc<GlobalInstance>) {
self.insert(name, ExternVal::Global(global));
}
pub fn with_table<N: Into<String>>(&mut self, name: N, table_type: TableType) {
self.items.push(HostItem::Table {
name: name.into(),
table_type,
});
pub fn insert_memory<N: Into<String>>(&mut self, name: N, memory: Rc<MemoryInstance>) {
self.insert(name, ExternVal::Memory(memory));
}
pub fn with_extern_val<N: Into<String>>(&mut self, name: N, extern_val: ExternVal) {
self.items.push(HostItem::ExternVal {
name: name.into(),
extern_val,
});
pub fn insert_table<N: Into<String>>(&mut self, name: N, table: Rc<TableInstance>) {
self.insert(name, ExternVal::Table(table));
}
pub fn with_global<N: Into<String>>(mut self, name: N, global: Rc<GlobalInstance>) -> Self {
self.insert_global(name, global);
self
}
pub fn with_memory<N: Into<String>>(mut self, name: N, memory: Rc<MemoryInstance>) -> Self {
self.insert_memory(name, memory);
self
}
pub fn with_table<N: Into<String>>(mut self, name: N, table: Rc<TableInstance>) -> Self {
self.insert_table(name, table);
self
}
fn insert<N: Into<String>>(&mut self, name: N, extern_val: ExternVal) {
match self.exports.entry(name.into()) {
Entry::Vacant(v) => v.insert(extern_val),
Entry::Occupied(o) => panic!("Duplicate export name {}", o.key()),
};
}
pub fn build(self) -> HostModule {
let internal_instance = Rc::new(ModuleInstance::with_exports(self.exports));
HostModule {
items: self.items
internal_instance
}
}
}
pub struct HostModule {
items: Vec<HostItem>,
internal_instance: Rc<ModuleInstance>,
}
impl HostModule {
pub(crate) fn allocate(self) -> Result<Rc<ModuleInstance>, Error> {
let mut exports = HashMap::new();
pub fn export_by_name(&self, name: &str) -> Option<ExternVal> {
self.internal_instance.export_by_name(name)
}
}
for item in self.items {
match item {
HostItem::Func { name, func_type, host_func } => {
let func = FuncInstance::Host {
func_type: Rc::new(func_type),
host_func: host_func,
};
exports.insert(name, ExternVal::Func(Rc::new(func)));
},
HostItem::Global { name, global_type, init_val } => {
let global = GlobalInstance::new(init_val, global_type.is_mutable());
exports.insert(name, ExternVal::Global(Rc::new(global)));
},
HostItem::Memory { name, memory_type } => {
let memory = MemoryInstance::new(&memory_type)?;
exports.insert(name, ExternVal::Memory(Rc::new(memory)));
},
HostItem::Table { name, table_type } => {
let table = TableInstance::new(&table_type)?;
exports.insert(name, ExternVal::Table(Rc::new(table)));
}
HostItem::ExternVal { name, extern_val } => {
exports.insert(name, extern_val);
}
}
impl ImportResolver for HostModule {
fn resolve_func(
&self,
field_name: &str,
func_type: &FunctionType,
) -> Result<Rc<FuncInstance>, Error> {
self.internal_instance.resolve_func(field_name, func_type)
}
let host_module_instance = ModuleInstance::with_exports(exports);
Ok(Rc::new(host_module_instance))
fn resolve_global(
&self,
field_name: &str,
global_type: &GlobalType,
) -> Result<Rc<GlobalInstance>, Error> {
self.internal_instance.resolve_global(field_name, global_type)
}
fn resolve_memory(
&self,
field_name: &str,
memory_type: &MemoryType,
) -> Result<Rc<MemoryInstance>, Error> {
self.internal_instance.resolve_memory(field_name, memory_type)
}
fn resolve_table(
&self,
field_name: &str,
table_type: &TableType,
) -> Result<Rc<TableInstance>, Error> {
self.internal_instance.resolve_table(field_name, table_type)
}
}

View File

@ -118,7 +118,7 @@ impl ModuleInstance {
self.exports.borrow_mut().insert(name.into(), extern_val);
}
fn alloc_module_internal(
fn alloc_module(
module: &Module,
extern_vals: &[ExternVal],
instance: &Rc<ModuleInstance>,
@ -207,7 +207,11 @@ impl ModuleInstance {
opcodes: body.code().clone(),
labels: labels,
};
let func_instance = alloc_func(instance, func_type, func_body);
let func_instance = FuncInstance::alloc_internal(
Rc::clone(instance),
func_type,
func_body
);
instance.push_func(func_instance);
}
}
@ -280,7 +284,7 @@ impl ModuleInstance {
) -> Result<Rc<ModuleInstance>, Error> {
let instance = Rc::new(ModuleInstance::new());
ModuleInstance::alloc_module_internal(module, extern_vals, &instance)?;
ModuleInstance::alloc_module(module, extern_vals, &instance)?;
for element_segment in module
.elements_section()
@ -521,19 +525,6 @@ fn alloc_func_type(func_type: FunctionType) -> Rc<FunctionType> {
Rc::new(func_type)
}
fn alloc_func(
module: &Rc<ModuleInstance>,
func_type: Rc<FunctionType>,
body: FuncBody,
) -> Rc<FuncInstance> {
let func = FuncInstance::Internal {
func_type,
module: Rc::clone(module),
body: Rc::new(body),
};
Rc::new(func)
}
fn alloc_table(table_type: &TableType) -> Result<Rc<TableInstance>, Error> {
let table = TableInstance::new(table_type)?;
Ok(Rc::new(table))

View File

@ -59,10 +59,8 @@ impl ProgramInstance {
&mut self,
name: &str,
host_module: HostModule,
) -> Result<Rc<ModuleInstance>, Error> {
let module_instance = host_module.allocate()?;
self.modules.insert(name.to_owned(), Rc::clone(&module_instance));
Ok(module_instance)
) {
self.resolvers.insert(name.to_owned(), Box::new(host_module) as Box<ImportResolver>);
}
pub fn insert_loaded_module(&mut self, name: &str, module: Rc<ModuleInstance>) {

View File

@ -4,11 +4,10 @@ use std::rc::Rc;
use builder::module;
use elements::{ExportEntry, Internal, ImportEntry, External, GlobalEntry, GlobalType,
InitExpr, ValueType, Opcodes, Opcode, TableType, MemoryType};
use interpreter::{Error, UserError, ProgramInstance};
use interpreter::value::RuntimeValue;
use interpreter::host::{HostModuleBuilder, HostModule};
use interpreter::memory::MemoryInstance;
use interpreter::ModuleInstance;
use interpreter::{
Error, GlobalInstance, HostModule, HostModuleBuilder, MemoryInstance,
ModuleInstance, ProgramInstance, RuntimeValue, UserError
};
use super::utils::program_with_default_env;
#[test]
@ -151,7 +150,7 @@ fn build_env_module() -> HostModule {
builder.with_func2("err", |_: &mut FunctionExecutor, _unused1: i32, _unused2: i32| -> Result<Option<i32>, Error> {
Err(Error::User(Box::new(UserErrorWithCode { error_code: 777 })))
});
builder.with_memory("memory", MemoryType::new(256, None));
builder.insert_memory("memory", Rc::new(MemoryInstance::new(&MemoryType::new(256, None)).unwrap()));
builder.build()
}
@ -159,8 +158,8 @@ fn build_env_module() -> HostModule {
fn native_env_function() {
let mut program = program_with_default_env();
let env_host_module = build_env_module();
let env_module = program.add_host_module("env", env_host_module).unwrap();
let env_memory = env_module.export_by_name("memory").unwrap().as_memory().unwrap();
let env_memory = env_host_module.export_by_name("memory").unwrap().as_memory().unwrap();
program.add_host_module("env", env_host_module);
let mut state = FunctionExecutor {
memory: env_memory,
@ -224,7 +223,7 @@ fn native_env_global() {
let module_constructor = |host_module: HostModule| {
let mut program = ProgramInstance::new();
program.add_host_module("env", host_module)?;
program.add_host_module("env", host_module);
let module = module()
.with_import(ImportEntry::new("env".into(), "ext_global".into(), External::Global(GlobalType::new(ValueType::I32, false))))
@ -249,7 +248,7 @@ fn native_env_global() {
// now add simple variable natively => ok
{
let mut host_module_builder = HostModuleBuilder::<State>::new();
host_module_builder.with_global("ext_global", GlobalType::new(ValueType::I32, false), RuntimeValue::I32(777));
host_module_builder.insert_global("ext_global", Rc::new(GlobalInstance::new(RuntimeValue::I32(777), false)));
assert_eq!(module_constructor(host_module_builder.build()).unwrap().unwrap(), RuntimeValue::I32(777));
}
}
@ -258,8 +257,8 @@ fn native_env_global() {
fn native_custom_error() {
let mut program = program_with_default_env();
let env_host_module = build_env_module();
let env_module = program.add_host_module("env", env_host_module).unwrap();
let env_memory = env_module.export_by_name("memory").unwrap().as_memory().unwrap();
let env_memory = env_host_module.export_by_name("memory").unwrap().as_memory().unwrap();
program.add_host_module("env", env_host_module);
let mut state = FunctionExecutor {
memory: env_memory,