diff --git a/src/interpreter/program.rs b/src/interpreter/program.rs index 9efedc7..267b685 100644 --- a/src/interpreter/program.rs +++ b/src/interpreter/program.rs @@ -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, -} - -/// Program instance essence. -pub struct ProgramInstanceEssence { - /// Loaded modules. - modules: RwLock>>, + store: Store, + modules: HashMap, } 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>>) -> Result, 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 { + 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) -> Result, 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> { - 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> { - self.modules.read().get(name).cloned() + pub fn module(&self, name: &str) -> Option { + self.modules.get(name).cloned() } } diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index 957ba43..586812a 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -983,7 +983,12 @@ impl<'store> Interpreter<'store> { } impl<'a> FunctionContext<'a> { - pub fn new(module: ModuleId, function: FuncId, externals: &'a HashMap>, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionSignature, args: Vec) -> Self { + pub fn new(store: &Store, function: FuncId, externals: &'a HashMap>, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionSignature, args: Vec) -> 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, diff --git a/src/interpreter/store.rs b/src/interpreter/store.rs index 0ec1731..051f264 100644 --- a/src/interpreter/store.rs +++ b/src/interpreter/store.rs @@ -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 { + 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, memories: Vec, globals: Vec, - exports: Vec, + exports: HashMap, } 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 { 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, 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) }