diff --git a/src/interpreter/memory.rs b/src/interpreter/memory.rs index 8fcb38f..adc94fc 100644 --- a/src/interpreter/memory.rs +++ b/src/interpreter/memory.rs @@ -47,7 +47,7 @@ impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref> impl MemoryInstance { /// Create new linear memory instance. - pub fn new(memory_type: &MemoryType) -> Result, Error> { + pub fn new(memory_type: &MemoryType) -> Result { check_limits(memory_type.limits())?; let maximum_size = match memory_type.limits().maximum() { @@ -65,7 +65,7 @@ impl MemoryInstance { maximum_size: maximum_size, }; - Ok(Arc::new(memory)) + Ok(memory) } /// Return linear memory limits. diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index f7be5ed..e747a0b 100644 --- a/src/interpreter/module.rs +++ b/src/interpreter/module.rs @@ -191,7 +191,7 @@ impl ModuleInstance { let memory = match module.memory_section() { Some(memory_section) => memory_section.entries() .iter() - .map(MemoryInstance::new) + .map(|mt| MemoryInstance::new(mt).map(Arc::new)) .collect::, _>>()?, None => Vec::new(), }; @@ -200,7 +200,7 @@ impl ModuleInstance { let tables = match module.table_section() { Some(table_section) => table_section.entries() .iter() - .map(|tt| TableInstance::new(tt)) + .map(|tt| TableInstance::new(tt).map(Arc::new)) .collect::, _>>()?, None => Vec::new(), }; @@ -417,19 +417,19 @@ impl ModuleInstance { } // use element section to fill tables - if let Some(element_section) = self.module.elements_section() { - for (element_segment_index, element_segment) in element_section.entries().iter().enumerate() { - let offset: u32 = get_initializer(element_segment.offset(), &self.module, &self.imports, VariableType::I32)?.try_into()?; - for function_index in element_segment.members() { - self.require_function(ItemIndex::IndexSpace(*function_index))?; - } + // if let Some(element_section) = self.module.elements_section() { + // for (element_segment_index, element_segment) in element_section.entries().iter().enumerate() { + // let offset: u32 = get_initializer(element_segment.offset(), &self.module, &self.imports, VariableType::I32)?.try_into()?; + // for function_index in element_segment.members() { + // self.require_function(ItemIndex::IndexSpace(*function_index))?; + // } - self.table(ItemIndex::IndexSpace(element_segment.index())) - .map_err(|e| Error::Initialization(format!("ElementSegment {} initializes non-existant Table {}: {:?}", element_segment_index, element_segment.index(), e))) - .and_then(|m| m.set_raw(offset, self.name.clone(), element_segment.members())) - .map_err(|e| Error::Initialization(e.into()))?; - } - } + // self.table(ItemIndex::IndexSpace(element_segment.index())) + // .map_err(|e| Error::Initialization(format!("ElementSegment {} initializes non-existant Table {}: {:?}", element_segment_index, element_segment.index(), e))) + // .and_then(|m| m.set_raw(offset, self.name.clone(), element_segment.members())) + // .map_err(|e| Error::Initialization(e.into()))?; + // } + // } Ok(()) } @@ -603,22 +603,23 @@ impl ModuleInstanceInterface for ModuleInstance { } fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap>>) -> Result, Error> { - let table = self.table(ItemIndex::IndexSpace(table_idx))?; - let (module, index) = match table.get(func_idx)? { - RuntimeValue::AnyFunc(module, index) => (module.clone(), index), - _ => return Err(Error::Function(format!("trying to indirect call function {} via non-anyfunc table {:?}", func_idx, table_idx))), - }; + panic!("TODO") + // let table = self.table(ItemIndex::IndexSpace(table_idx))?; + // let (module, index) = match table.get(func_idx)? { + // RuntimeValue::AnyFunc(module, index) => (module.clone(), index), + // _ => return Err(Error::Function(format!("trying to indirect call function {} via non-anyfunc table {:?}", func_idx, table_idx))), + // }; - let module = self.imports.module(externals, &module)?; - let required_function_type = self.function_type_by_index(type_idx)?; - let actual_function_type = module.function_type(ItemIndex::IndexSpace(index))?; - if required_function_type != actual_function_type { - return Err(Error::Function(format!("expected indirect function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}", - required_function_type.params(), required_function_type.return_type(), - actual_function_type.params(), actual_function_type.return_type()))); - } + // let module = self.imports.module(externals, &module)?; + // let required_function_type = self.function_type_by_index(type_idx)?; + // let actual_function_type = module.function_type(ItemIndex::IndexSpace(index))?; + // if required_function_type != actual_function_type { + // return Err(Error::Function(format!("expected indirect function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}", + // required_function_type.params(), required_function_type.return_type(), + // actual_function_type.params(), actual_function_type.return_type()))); + // } - module.function_reference(ItemIndex::IndexSpace(index), externals) + // module.function_reference(ItemIndex::IndexSpace(index), externals) } fn function_body<'a>(&'a self, internal_index: u32) -> Result>, Error> { diff --git a/src/interpreter/store.rs b/src/interpreter/store.rs index 36a0dbd..05ba00c 100644 --- a/src/interpreter/store.rs +++ b/src/interpreter/store.rs @@ -1,9 +1,11 @@ // TODO: remove this #![allow(unused)] -use elements::{Module, FunctionType, FuncBody, TableType, MemoryType, GlobalType, GlobalEntry, Type, Opcode}; -use interpreter::{RuntimeValue, Error}; +use elements::{FuncBody, FunctionType, GlobalEntry, GlobalType, InitExpr, MemoryType, Module, + Opcode, TableType, Type}; +use interpreter::{Error, RuntimeValue, MemoryInstance, TableInstance}; use validation::validate_module; +use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; #[derive(Copy, Clone, Debug)] pub struct TypeId(u32); @@ -42,40 +44,10 @@ pub enum FuncInstance { Host { func_type: TypeId, host_func: HostFuncId, - } + }, } -impl FuncInstance { - -} - -pub struct MemInstance { - data: Vec, - max: Option, -} - -impl MemInstance { - fn new(min: u32, max: Option) -> MemInstance { - MemInstance { - data: vec![0; min as usize], - max, - } - } -} - -pub struct TableInstance { - elements: Vec>, - max: Option, -} - -impl TableInstance { - fn new(min: u32, max: Option) -> TableInstance { - TableInstance { - elements: vec![None; min as usize], - max, - } - } -} +impl FuncInstance {} pub struct GlobalInstance { val: RuntimeValue, @@ -84,10 +56,7 @@ pub struct GlobalInstance { impl GlobalInstance { fn new(val: RuntimeValue, mutable: bool) -> GlobalInstance { - GlobalInstance { - val, - mutable, - } + GlobalInstance { val, mutable } } } @@ -117,7 +86,7 @@ pub struct Store { // TODO: u32 capped vectors. funcs: Vec, tables: Vec, - memories: Vec, + memories: Vec, globals: Vec, // These are not the part of specification of the Store. @@ -132,11 +101,15 @@ impl Store { } fn resolve_module(&self, id: ModuleId) -> &ModuleInstance { - self.modules.get(id.0 as usize).expect("ID should always be a valid index") + self.modules + .get(id.0 as usize) + .expect("ID should always be a valid index") } fn resolve_type(&self, id: TypeId) -> &FunctionType { - self.types.get(id.0 as usize).expect("ID should always be a valid index") + self.types + .get(id.0 as usize) + .expect("ID should always be a valid index") } fn alloc_func_type(&mut self, func_type: FunctionType) -> TypeId { @@ -149,7 +122,7 @@ impl Store { let func = FuncInstance::Defined { func_type, module, - body + body, }; self.funcs.push(func); let func_id = self.funcs.len() - 1; @@ -158,18 +131,18 @@ impl Store { // TODO: alloc_host_func - fn alloc_table(&mut self, table_type: TableType) -> TableId { - let table = TableInstance::new(table_type.limits().initial(), table_type.limits().maximum()); + fn alloc_table(&mut self, table_type: &TableType) -> Result { + let table = TableInstance::new(table_type)?; self.tables.push(table); let table_id = self.tables.len() - 1; - TableId(table_id as u32) + Ok(TableId(table_id as u32)) } - fn alloc_memory(&mut self, mem_type: MemoryType) -> MemoryId { - let mem = MemInstance::new(mem_type.limits().initial(), mem_type.limits().maximum()); + fn alloc_memory(&mut self, mem_type: &MemoryType) -> Result { + let mem = MemoryInstance::new(&mem_type)?; self.memories.push(mem); let mem_id = self.memories.len() - 1; - MemoryId(mem_id as u32) + Ok(MemoryId(mem_id as u32)) } fn alloc_global(&mut self, global_type: GlobalType, val: RuntimeValue) -> GlobalId { @@ -181,11 +154,11 @@ impl Store { fn alloc_module_internal( &mut self, - module: Module, + module: &Module, extern_vals: &[ExternVal], instance: &mut ModuleInstance, module_id: ModuleId, - ) { + ) -> Result<(), Error> { for extern_val in extern_vals { match *extern_val { ExternVal::Func(func) => instance.funcs.push(func), @@ -214,7 +187,7 @@ impl Store { let bodies = module.code_section().map(|cs| cs.bodies()).unwrap_or(&[]); debug_assert!( funcs.len() == bodies.len(), - "due to validation func and body counts must match" + "Due to validation func and body counts must match" ); for (ty, body) in Iterator::zip(funcs.into_iter(), bodies.into_iter()) { @@ -225,7 +198,7 @@ impl Store { } for table in module.table_section().map(|ts| ts.entries()).unwrap_or(&[]) { - let table_id = self.alloc_table(table.clone()); + let table_id = self.alloc_table(table)?; instance.tables.push(table_id); } @@ -234,7 +207,7 @@ impl Store { .map(|ms| ms.entries()) .unwrap_or(&[]) { - let memory_id = self.alloc_memory(memory.clone()); + let memory_id = self.alloc_memory(memory)?; instance.memories.push(memory_id); } @@ -243,38 +216,86 @@ impl Store { .map(|gs| gs.entries()) .unwrap_or(&[]) { - let init_val = global_init_val(global, instance, self); + let init_val = eval_init_expr(global.init_expr(), instance, self); let global_id = self.alloc_global(global.global_type().clone(), init_val); instance.globals.push(global_id); } + + Ok(()) } - fn alloc_module(&mut self, module: Module, extern_vals: &[ExternVal]) -> ModuleId { + fn instantiate_module( + &mut self, + module: &Module, + extern_vals: &[ExternVal], + ) -> Result<(), Error> { + // TODO: Add execution params + + validate_module(module)?; + + 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); + self.alloc_module_internal(module, extern_vals, &mut instance, module_id)?; - self.alloc_module_internal(module, extern_vals, &mut instance, module_id); + // TODO: assert module is valid with extern_vals. + + for element_segment in module + .elements_section() + .map(|es| es.entries()) + .unwrap_or(&[]) + { + let offset_val = match eval_init_expr(element_segment.offset(), &instance, self) { + RuntimeValue::I32(v) => v as u32, + _ => panic!("Due to validation elem segment offset should evaluate to i32"), + }; + + let table_id = instance + .tables + .get(DEFAULT_TABLE_INDEX as usize) + .expect("Due to validation default table should exists"); + let table_inst = self.tables + .get_mut(table_id.0 as usize) + .expect("ID should be always valid"); + + for (j, func_idx) in element_segment.members().into_iter().enumerate() { + let func_id = instance + .funcs + .get(*func_idx as usize) + .expect("Due to validation funcs from element segments should exists"); + + table_inst.set(offset_val + j as u32, *func_id); + } + } + + for data_segment in module.data_section().map(|ds| ds.entries()).unwrap_or(&[]) { + let offset_val = match eval_init_expr(data_segment.offset(), &instance, self) { + RuntimeValue::I32(v) => v as u32, + _ => panic!("Due to validation data segment offset should evaluate to i32"), + }; + + let memory_id = instance + .memories + .get(DEFAULT_MEMORY_INDEX as usize) + .expect("Due to validation default memory should exists"); + let memory_inst = self.memories + .get_mut(memory_id.0 as usize) + .expect("ID should be always valid"); + + memory_inst.set(offset_val, data_segment.value())?; + } self.modules.push(instance); - module_id - } - - fn instantiate_module(&mut self, module: Module, extern_vals: &[ExternVal]) -> Result<(), Error> { - validate_module(&module)?; - - // TODO: check extern_vals - let module_id = self.alloc_module(module, extern_vals); - Ok(()) } } -fn global_init_val(global: &GlobalEntry, module: &ModuleInstance, store: &Store) -> RuntimeValue { - let code = global.init_expr().code(); +fn eval_init_expr(init_expr: &InitExpr, module: &ModuleInstance, store: &Store) -> RuntimeValue { + let code = init_expr.code(); debug_assert!( code.len() == 2, - "due to validation `code`.len() should be 2" + "Due to validation `code`.len() should be 2" ); match code[0] { Opcode::I32Const(v) => v.into(), @@ -285,13 +306,13 @@ fn global_init_val(global: &GlobalEntry, module: &ModuleInstance, store: &Store) let global_id = module .globals .get(idx as usize) - .expect("due to validation global should exists in module"); + .expect("Due to validation global should exists in module"); let global_inst = store .globals .get(global_id.0 as usize) .expect("ID should always be a valid index"); global_inst.val.clone() } - _ => panic!("due to validation init should be a const expr"), + _ => panic!("Due to validation init should be a const expr"), } } diff --git a/src/interpreter/table.rs b/src/interpreter/table.rs index a5c2641..fa1d76a 100644 --- a/src/interpreter/table.rs +++ b/src/interpreter/table.rs @@ -1,20 +1,19 @@ use std::u32; -use std::sync::Arc; use parking_lot::RwLock; use elements::{TableType, ResizableLimits}; use interpreter::Error; use interpreter::module::check_limits; use interpreter::variable::{VariableInstance, VariableType}; use interpreter::value::RuntimeValue; +use interpreter::store::FuncId; /// Table instance. pub struct TableInstance { /// Table limits. limits: ResizableLimits, - /// Table variables type. - variable_type: VariableType, /// Table memory buffer. - buffer: RwLock>, + buffer: RwLock>>, + } /// Table element. Cloneable wrapper around VariableInstance. @@ -24,17 +23,14 @@ struct TableElement { impl TableInstance { /// New instance of the table - pub fn new(table_type: &TableType) -> Result, Error> { + pub fn new(table_type: &TableType) -> Result { check_limits(table_type.limits())?; - - let variable_type = table_type.elem_type().into(); - Ok(Arc::new(TableInstance { + Ok(TableInstance { limits: table_type.limits().clone(), - variable_type: variable_type, buffer: RwLock::new( - vec![TableElement::new(VariableInstance::new(true, variable_type, RuntimeValue::Null)?); table_type.limits().initial() as usize] + vec![None; table_type.limits().initial() as usize] ), - })) + }) } /// Return table limits. @@ -44,51 +40,34 @@ impl TableInstance { /// Get variable type for this table. pub fn variable_type(&self) -> VariableType { - self.variable_type + panic!("TODO") } /// Get the specific value in the table - pub fn get(&self, offset: u32) -> Result { + pub fn get(&self, offset: u32) -> Result { let buffer = self.buffer.read(); let buffer_len = buffer.len(); - buffer.get(offset as usize) - .map(|v| v.var.get()) - .ok_or(Error::Table(format!("trying to read table item with index {} when there are only {} items", offset, buffer_len))) + let table_elem = buffer.get(offset as usize).ok_or(Error::Table(format!( + "trying to read table item with index {} when there are only {} items", + offset, + buffer_len + )))?; + Ok(table_elem.ok_or(Error::Table(format!( + "trying to read uninitialized element on index {}", + offset + )))?) } - /// Set the table value from raw slice - pub fn set_raw(&self, mut offset: u32, module_name: String, value: &[u32]) -> Result<(), Error> { - for val in value { - match self.variable_type { - VariableType::AnyFunc => self.set(offset, RuntimeValue::AnyFunc(module_name.clone(), *val))?, - _ => return Err(Error::Table(format!("table of type {:?} is not supported", self.variable_type))), - } - offset += 1; - } - Ok(()) - } - - /// Set the table from runtime variable value - pub fn set(&self, offset: u32, value: RuntimeValue) -> Result<(), Error> { + /// Set the table element to the specified function. + pub fn set(&self, offset: u32, value: FuncId) -> Result<(), Error> { let mut buffer = self.buffer.write(); let buffer_len = buffer.len(); - buffer.get_mut(offset as usize) - .ok_or(Error::Table(format!("trying to update table item with index {} when there are only {} items", offset, buffer_len))) - .and_then(|v| v.var.set(value)) - } -} - -impl TableElement { - pub fn new(var: VariableInstance) -> Self { - TableElement { - var: var, - } - } -} - -impl Clone for TableElement { - fn clone(&self) -> Self { - TableElement::new(VariableInstance::new(self.var.is_mutable(), self.var.variable_type(), self.var.get()) - .expect("it only fails when variable_type() != passed variable value; both are read from already constructed var; qed")) + let table_elem = buffer.get_mut(offset as usize).ok_or(Error::Table(format!( + "trying to update table item with index {} when there are only {} items", + offset, + buffer_len + )))?; + *table_elem = Some(value); + Ok(()) } }