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 parking_lot::RwLock;
use elements::Module;
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.
pub struct ProgramInstance {
/// Shared data reference.
essence: Arc<ProgramInstanceEssence>,
}
/// Program instance essence.
pub struct ProgramInstanceEssence {
/// Loaded modules.
modules: RwLock<HashMap<String, Arc<ModuleInstanceInterface>>>,
store: Store,
modules: HashMap<String, ModuleId>,
}
impl ProgramInstance {
/// Create new program instance.
pub fn new() -> Self {
ProgramInstance {
essence: Arc::new(ProgramInstanceEssence::new()),
store: Store::new(),
modules: HashMap::new(),
}
}
/// 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> {
let mut module_instance = ModuleInstance::new(Arc::downgrade(&self.essence), name.into(), module)?;
module_instance.instantiate(externals)?;
pub fn add_module<'a>(
&mut self,
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);
self.essence.modules.write().insert(name.into(), module_instance.clone());
module_instance.run_start_function()?;
Ok(module_instance)
}
let module_id = self.store.instantiate_module(&module, &extern_vals, start_exec_params)?;
self.modules.insert(name.to_string(), module_id);
/// Insert instantiated module.
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)
Ok(module_id)
}
/// Get one of the modules by name
pub fn module(&self, name: &str) -> Option<Arc<ModuleInstanceInterface>> {
self.essence.module(name)
}
}
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()
pub fn module(&self, name: &str) -> Option<ModuleId> {
self.modules.get(name).cloned()
}
}

View File

@ -983,7 +983,12 @@ impl<'store> Interpreter<'store> {
}
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 {
is_initialized: false,
function: function,

View File

@ -4,7 +4,7 @@
use std::sync::Arc;
use std::collections::HashMap;
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::runner::{FunctionContext, prepare_function_args, Interpreter};
use validation::validate_module;
@ -67,6 +67,14 @@ impl ModuleId {
.get(idx as usize)
.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)]
@ -102,6 +110,7 @@ impl MemoryId {
#[derive(Copy, Clone, Debug)]
pub struct GlobalId(u32);
#[derive(Copy, Clone, Debug)]
pub enum ExternVal {
Func(FuncId),
Table(TableId),
@ -167,7 +176,7 @@ struct ModuleInstance {
tables: Vec<TableId>,
memories: Vec<MemoryId>,
globals: Vec<GlobalId>,
exports: Vec<ExportInstance>,
exports: HashMap<String, ExternVal>,
}
impl ModuleInstance {
@ -191,7 +200,7 @@ pub struct Store {
}
impl Store {
fn new() -> Store {
pub fn new() -> Store {
Store::default()
}
@ -328,15 +337,38 @@ impl Store {
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(())
}
fn instantiate_module(
pub fn instantiate_module(
&mut self,
module: &Module,
extern_vals: &[ExternVal],
start_exec_params: ExecutionParams,
) -> Result<(), Error> {
) -> Result<ModuleId, Error> {
let mut instance = ModuleInstance::new();
// Reserve the index of the module, but not yet push the module.
let module_id = ModuleId((self.modules.len()) as u32);
@ -404,7 +436,7 @@ impl Store {
self.invoke(start_func, start_exec_params)?;
}
Ok(())
Ok(module_id)
}
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_signature = FunctionSignature::Module(func_type);
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);
interpreter.run_function(inner)
}