Program import matching

This commit is contained in:
Sergey Pepyakin 2017-12-11 14:58:02 +01:00
parent 02ad77f93c
commit 929d62b286
3 changed files with 71 additions and 49 deletions

View File

@ -1,64 +1,49 @@
use std::sync::Arc;
use std::collections::HashMap; use std::collections::HashMap;
use parking_lot::RwLock;
use elements::Module; use elements::Module;
use interpreter::Error; use interpreter::Error;
use interpreter::module::{ModuleInstance, ModuleInstanceInterface}; use interpreter::module::{ExecutionParams};
use interpreter::store::{Store, ModuleId};
/// Program instance. Program is a set of instantiated modules. /// Program instance. Program is a set of instantiated modules.
pub struct ProgramInstance { pub struct ProgramInstance {
/// Shared data reference. store: Store,
essence: Arc<ProgramInstanceEssence>, modules: HashMap<String, ModuleId>,
}
/// Program instance essence.
pub struct ProgramInstanceEssence {
/// Loaded modules.
modules: RwLock<HashMap<String, Arc<ModuleInstanceInterface>>>,
} }
impl ProgramInstance { impl ProgramInstance {
/// Create new program instance. /// Create new program instance.
pub fn new() -> Self { pub fn new() -> Self {
ProgramInstance { ProgramInstance {
essence: Arc::new(ProgramInstanceEssence::new()), store: Store::new(),
modules: HashMap::new(),
} }
} }
/// Instantiate module with validation. /// Instantiate module with validation.
pub fn add_module<'a>(&self, name: &str, module: Module, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<Arc<ModuleInstance>, Error> { pub fn add_module<'a>(
let mut module_instance = ModuleInstance::new(Arc::downgrade(&self.essence), name.into(), module)?; &mut self,
module_instance.instantiate(externals)?; name: &str,
module: Module,
start_exec_params: ExecutionParams,
) -> Result<ModuleId, Error> {
let extern_vals = Vec::new();
for import_entry in module.import_section().map(|s| s.entries()).unwrap_or(&[]) {
let module = self.modules[import_entry.module()];
let extern_val = module
.resolve_export(&self.store, import_entry.field())
.ok_or_else(|| Error::Function(format!("Module {} doesn't have export {}", import_entry.module(), import_entry.field())))?;
extern_vals.push(extern_val);
}
let module_instance = Arc::new(module_instance); let module_id = self.store.instantiate_module(&module, &extern_vals, start_exec_params)?;
self.essence.modules.write().insert(name.into(), module_instance.clone()); self.modules.insert(name.to_string(), module_id);
module_instance.run_start_function()?;
Ok(module_instance)
}
/// Insert instantiated module. Ok(module_id)
pub fn insert_loaded_module(&self, name: &str, module_instance: Arc<ModuleInstanceInterface>) -> Result<Arc<ModuleInstanceInterface>, Error> {
// replace existing module with the same name with new one
self.essence.modules.write().insert(name.into(), Arc::clone(&module_instance));
Ok(module_instance)
} }
/// Get one of the modules by name /// Get one of the modules by name
pub fn module(&self, name: &str) -> Option<Arc<ModuleInstanceInterface>> { pub fn module(&self, name: &str) -> Option<ModuleId> {
self.essence.module(name) self.modules.get(name).cloned()
}
}
impl ProgramInstanceEssence {
/// Create new program essence.
pub fn new() -> Self {
ProgramInstanceEssence {
modules: RwLock::new(HashMap::new()),
}
}
/// Get module reference.
pub fn module(&self, name: &str) -> Option<Arc<ModuleInstanceInterface>> {
self.modules.read().get(name).cloned()
} }
} }

View File

@ -983,7 +983,12 @@ impl<'store> Interpreter<'store> {
} }
impl<'a> FunctionContext<'a> { impl<'a> FunctionContext<'a> {
pub fn new(module: ModuleId, function: FuncId, externals: &'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionSignature, args: Vec<VariableInstance>) -> Self { pub fn new(store: &Store, function: FuncId, externals: &'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionSignature, args: Vec<VariableInstance>) -> Self {
let func_instance = function.resolve(store);
let module = match *func_instance {
FuncInstance::Defined { module, .. } => module,
FuncInstance::Host { .. } => panic!("Host functions can't be called as internally defined functions; Thus FunctionContext can be created only with internally defined functions; qed"),
};
FunctionContext { FunctionContext {
is_initialized: false, is_initialized: false,
function: function, function: function,

View File

@ -4,7 +4,7 @@
use std::sync::Arc; use std::sync::Arc;
use std::collections::HashMap; use std::collections::HashMap;
use elements::{FunctionType, GlobalEntry, GlobalType, InitExpr, MemoryType, Module, use elements::{FunctionType, GlobalEntry, GlobalType, InitExpr, MemoryType, Module,
Opcode, Opcodes, Local, TableType, Type}; Opcode, Opcodes, Local, TableType, Type, Internal};
use interpreter::{Error, RuntimeValue, MemoryInstance, TableInstance, ExecutionParams, CallerContext, FunctionSignature}; use interpreter::{Error, RuntimeValue, MemoryInstance, TableInstance, ExecutionParams, CallerContext, FunctionSignature};
use interpreter::runner::{FunctionContext, prepare_function_args, Interpreter}; use interpreter::runner::{FunctionContext, prepare_function_args, Interpreter};
use validation::validate_module; use validation::validate_module;
@ -67,6 +67,14 @@ impl ModuleId {
.get(idx as usize) .get(idx as usize)
.expect("Due to validation type should exists") .expect("Due to validation type should exists")
} }
pub fn resolve_export(&self, store: &Store, name: &str) -> Option<ExternVal> {
let instance = store.resolve_module(*self);
instance
.exports
.get(name)
.cloned()
}
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
@ -102,6 +110,7 @@ impl MemoryId {
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct GlobalId(u32); pub struct GlobalId(u32);
#[derive(Copy, Clone, Debug)]
pub enum ExternVal { pub enum ExternVal {
Func(FuncId), Func(FuncId),
Table(TableId), Table(TableId),
@ -167,7 +176,7 @@ struct ModuleInstance {
tables: Vec<TableId>, tables: Vec<TableId>,
memories: Vec<MemoryId>, memories: Vec<MemoryId>,
globals: Vec<GlobalId>, globals: Vec<GlobalId>,
exports: Vec<ExportInstance>, exports: HashMap<String, ExternVal>,
} }
impl ModuleInstance { impl ModuleInstance {
@ -191,7 +200,7 @@ pub struct Store {
} }
impl Store { impl Store {
fn new() -> Store { pub fn new() -> Store {
Store::default() Store::default()
} }
@ -328,15 +337,38 @@ impl Store {
instance.globals.push(global_id); instance.globals.push(global_id);
} }
for export in module.export_section().map(|es| es.entries()).unwrap_or(&[]) {
let field = export.field();
let extern_val: ExternVal = match *export.internal() {
Internal::Function(idx) => {
let func_id = instance.funcs.get(idx as usize).expect("Due to validation func should exists");
ExternVal::Func(*func_id)
},
Internal::Global(idx) => {
let global_id = instance.globals.get(idx as usize).expect("Due to validation global should exists");
ExternVal::Global(*global_id)
}
Internal::Memory(idx) => {
let memory_id = instance.memories.get(idx as usize).expect("Due to validation memory should exists");
ExternVal::Memory(*memory_id)
}
Internal::Table(idx) => {
let table_id = instance.tables.get(idx as usize).expect("Due to validation table should exists");
ExternVal::Table(*table_id)
}
};
instance.exports.insert(field.into(), extern_val);
}
Ok(()) Ok(())
} }
fn instantiate_module( pub fn instantiate_module(
&mut self, &mut self,
module: &Module, module: &Module,
extern_vals: &[ExternVal], extern_vals: &[ExternVal],
start_exec_params: ExecutionParams, start_exec_params: ExecutionParams,
) -> Result<(), Error> { ) -> Result<ModuleId, Error> {
let mut instance = ModuleInstance::new(); let mut instance = ModuleInstance::new();
// Reserve the index of the module, but not yet push the module. // Reserve the index of the module, but not yet push the module.
let module_id = ModuleId((self.modules.len()) as u32); let module_id = ModuleId((self.modules.len()) as u32);
@ -404,7 +436,7 @@ impl Store {
self.invoke(start_func, start_exec_params)?; self.invoke(start_func, start_exec_params)?;
} }
Ok(()) Ok(module_id)
} }
fn invoke(&mut self, func: FuncId, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> { fn invoke(&mut self, func: FuncId, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
@ -414,7 +446,7 @@ impl Store {
let func_type = func.resolve(self).func_type().resolve(self); let func_type = func.resolve(self).func_type().resolve(self);
let func_signature = FunctionSignature::Module(func_type); let func_signature = FunctionSignature::Module(func_type);
let args = prepare_function_args(&func_signature, outer.value_stack)?; let args = prepare_function_args(&func_signature, outer.value_stack)?;
let inner = FunctionContext::new(func, outer.externals, outer.value_stack_limit, outer.frame_stack_limit, &func_signature, args); let inner = FunctionContext::new(self, func, outer.externals, outer.value_stack_limit, outer.frame_stack_limit, &func_signature, args);
let interpreter = Interpreter::new(self); let interpreter = Interpreter::new(self);
interpreter.run_function(inner) interpreter.run_function(inner)
} }