mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-14 15:31:44 +00:00
Host modules now ImportResolvers
This commit is contained in:
@ -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>,
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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>) {
|
||||
|
@ -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,
|
||||
|
Reference in New Issue
Block a user