TableInstance is specialized for any func

This commit is contained in:
Sergey Pepyakin
2017-12-09 15:32:19 +01:00
parent 0a92032956
commit 987fffb6c3
4 changed files with 149 additions and 148 deletions

View File

@ -47,7 +47,7 @@ impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref<Target=Vec<u8>>
impl MemoryInstance { impl MemoryInstance {
/// Create new linear memory instance. /// Create new linear memory instance.
pub fn new(memory_type: &MemoryType) -> Result<Arc<Self>, Error> { pub fn new(memory_type: &MemoryType) -> Result<Self, Error> {
check_limits(memory_type.limits())?; check_limits(memory_type.limits())?;
let maximum_size = match memory_type.limits().maximum() { let maximum_size = match memory_type.limits().maximum() {
@ -65,7 +65,7 @@ impl MemoryInstance {
maximum_size: maximum_size, maximum_size: maximum_size,
}; };
Ok(Arc::new(memory)) Ok(memory)
} }
/// Return linear memory limits. /// Return linear memory limits.

View File

@ -191,7 +191,7 @@ impl ModuleInstance {
let memory = match module.memory_section() { let memory = match module.memory_section() {
Some(memory_section) => memory_section.entries() Some(memory_section) => memory_section.entries()
.iter() .iter()
.map(MemoryInstance::new) .map(|mt| MemoryInstance::new(mt).map(Arc::new))
.collect::<Result<Vec<_>, _>>()?, .collect::<Result<Vec<_>, _>>()?,
None => Vec::new(), None => Vec::new(),
}; };
@ -200,7 +200,7 @@ impl ModuleInstance {
let tables = match module.table_section() { let tables = match module.table_section() {
Some(table_section) => table_section.entries() Some(table_section) => table_section.entries()
.iter() .iter()
.map(|tt| TableInstance::new(tt)) .map(|tt| TableInstance::new(tt).map(Arc::new))
.collect::<Result<Vec<_>, _>>()?, .collect::<Result<Vec<_>, _>>()?,
None => Vec::new(), None => Vec::new(),
}; };
@ -417,19 +417,19 @@ impl ModuleInstance {
} }
// use element section to fill tables // use element section to fill tables
if let Some(element_section) = self.module.elements_section() { // if let Some(element_section) = self.module.elements_section() {
for (element_segment_index, element_segment) in element_section.entries().iter().enumerate() { // 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()?; // let offset: u32 = get_initializer(element_segment.offset(), &self.module, &self.imports, VariableType::I32)?.try_into()?;
for function_index in element_segment.members() { // for function_index in element_segment.members() {
self.require_function(ItemIndex::IndexSpace(*function_index))?; // self.require_function(ItemIndex::IndexSpace(*function_index))?;
} // }
self.table(ItemIndex::IndexSpace(element_segment.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))) // .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())) // .and_then(|m| m.set_raw(offset, self.name.clone(), element_segment.members()))
.map_err(|e| Error::Initialization(e.into()))?; // .map_err(|e| Error::Initialization(e.into()))?;
} // }
} // }
Ok(()) 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<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> { fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> {
let table = self.table(ItemIndex::IndexSpace(table_idx))?; panic!("TODO")
let (module, index) = match table.get(func_idx)? { // let table = self.table(ItemIndex::IndexSpace(table_idx))?;
RuntimeValue::AnyFunc(module, index) => (module.clone(), index), // let (module, index) = match table.get(func_idx)? {
_ => return Err(Error::Function(format!("trying to indirect call function {} via non-anyfunc table {:?}", func_idx, table_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 module = self.imports.module(externals, &module)?;
let required_function_type = self.function_type_by_index(type_idx)?; // let required_function_type = self.function_type_by_index(type_idx)?;
let actual_function_type = module.function_type(ItemIndex::IndexSpace(index))?; // let actual_function_type = module.function_type(ItemIndex::IndexSpace(index))?;
if required_function_type != actual_function_type { // if required_function_type != actual_function_type {
return Err(Error::Function(format!("expected indirect function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}", // return Err(Error::Function(format!("expected indirect function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}",
required_function_type.params(), required_function_type.return_type(), // required_function_type.params(), required_function_type.return_type(),
actual_function_type.params(), actual_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<Option<InternalFunction<'a>>, Error> { fn function_body<'a>(&'a self, internal_index: u32) -> Result<Option<InternalFunction<'a>>, Error> {

View File

@ -1,9 +1,11 @@
// TODO: remove this // TODO: remove this
#![allow(unused)] #![allow(unused)]
use elements::{Module, FunctionType, FuncBody, TableType, MemoryType, GlobalType, GlobalEntry, Type, Opcode}; use elements::{FuncBody, FunctionType, GlobalEntry, GlobalType, InitExpr, MemoryType, Module,
use interpreter::{RuntimeValue, Error}; Opcode, TableType, Type};
use interpreter::{Error, RuntimeValue, MemoryInstance, TableInstance};
use validation::validate_module; use validation::validate_module;
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct TypeId(u32); pub struct TypeId(u32);
@ -42,40 +44,10 @@ pub enum FuncInstance {
Host { Host {
func_type: TypeId, func_type: TypeId,
host_func: HostFuncId, host_func: HostFuncId,
} },
} }
impl FuncInstance { impl FuncInstance {}
}
pub struct MemInstance {
data: Vec<u8>,
max: Option<u32>,
}
impl MemInstance {
fn new(min: u32, max: Option<u32>) -> MemInstance {
MemInstance {
data: vec![0; min as usize],
max,
}
}
}
pub struct TableInstance {
elements: Vec<Option<FuncId>>,
max: Option<u32>,
}
impl TableInstance {
fn new(min: u32, max: Option<u32>) -> TableInstance {
TableInstance {
elements: vec![None; min as usize],
max,
}
}
}
pub struct GlobalInstance { pub struct GlobalInstance {
val: RuntimeValue, val: RuntimeValue,
@ -84,10 +56,7 @@ pub struct GlobalInstance {
impl GlobalInstance { impl GlobalInstance {
fn new(val: RuntimeValue, mutable: bool) -> GlobalInstance { fn new(val: RuntimeValue, mutable: bool) -> GlobalInstance {
GlobalInstance { GlobalInstance { val, mutable }
val,
mutable,
}
} }
} }
@ -117,7 +86,7 @@ pub struct Store {
// TODO: u32 capped vectors. // TODO: u32 capped vectors.
funcs: Vec<FuncInstance>, funcs: Vec<FuncInstance>,
tables: Vec<TableInstance>, tables: Vec<TableInstance>,
memories: Vec<MemInstance>, memories: Vec<MemoryInstance>,
globals: Vec<GlobalInstance>, globals: Vec<GlobalInstance>,
// These are not the part of specification of the Store. // These are not the part of specification of the Store.
@ -132,11 +101,15 @@ impl Store {
} }
fn resolve_module(&self, id: ModuleId) -> &ModuleInstance { 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 { 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 { fn alloc_func_type(&mut self, func_type: FunctionType) -> TypeId {
@ -149,7 +122,7 @@ impl Store {
let func = FuncInstance::Defined { let func = FuncInstance::Defined {
func_type, func_type,
module, module,
body body,
}; };
self.funcs.push(func); self.funcs.push(func);
let func_id = self.funcs.len() - 1; let func_id = self.funcs.len() - 1;
@ -158,18 +131,18 @@ impl Store {
// TODO: alloc_host_func // TODO: alloc_host_func
fn alloc_table(&mut self, table_type: TableType) -> TableId { fn alloc_table(&mut self, table_type: &TableType) -> Result<TableId, Error> {
let table = TableInstance::new(table_type.limits().initial(), table_type.limits().maximum()); let table = TableInstance::new(table_type)?;
self.tables.push(table); self.tables.push(table);
let table_id = self.tables.len() - 1; 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 { fn alloc_memory(&mut self, mem_type: &MemoryType) -> Result<MemoryId, Error> {
let mem = MemInstance::new(mem_type.limits().initial(), mem_type.limits().maximum()); let mem = MemoryInstance::new(&mem_type)?;
self.memories.push(mem); self.memories.push(mem);
let mem_id = self.memories.len() - 1; 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 { fn alloc_global(&mut self, global_type: GlobalType, val: RuntimeValue) -> GlobalId {
@ -181,11 +154,11 @@ impl Store {
fn alloc_module_internal( fn alloc_module_internal(
&mut self, &mut self,
module: Module, module: &Module,
extern_vals: &[ExternVal], extern_vals: &[ExternVal],
instance: &mut ModuleInstance, instance: &mut ModuleInstance,
module_id: ModuleId, module_id: ModuleId,
) { ) -> Result<(), Error> {
for extern_val in extern_vals { for extern_val in extern_vals {
match *extern_val { match *extern_val {
ExternVal::Func(func) => instance.funcs.push(func), ExternVal::Func(func) => instance.funcs.push(func),
@ -214,7 +187,7 @@ impl Store {
let bodies = module.code_section().map(|cs| cs.bodies()).unwrap_or(&[]); let bodies = module.code_section().map(|cs| cs.bodies()).unwrap_or(&[]);
debug_assert!( debug_assert!(
funcs.len() == bodies.len(), 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()) { 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(&[]) { 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); instance.tables.push(table_id);
} }
@ -234,7 +207,7 @@ impl Store {
.map(|ms| ms.entries()) .map(|ms| ms.entries())
.unwrap_or(&[]) .unwrap_or(&[])
{ {
let memory_id = self.alloc_memory(memory.clone()); let memory_id = self.alloc_memory(memory)?;
instance.memories.push(memory_id); instance.memories.push(memory_id);
} }
@ -243,38 +216,86 @@ impl Store {
.map(|gs| gs.entries()) .map(|gs| gs.entries())
.unwrap_or(&[]) .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); let global_id = self.alloc_global(global.global_type().clone(), init_val);
instance.globals.push(global_id); 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(); 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);
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.
self.modules.push(instance); for element_segment in module
module_id .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);
}
} }
fn instantiate_module(&mut self, module: Module, extern_vals: &[ExternVal]) -> Result<(), Error> { for data_segment in module.data_section().map(|ds| ds.entries()).unwrap_or(&[]) {
validate_module(&module)?; 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"),
};
// TODO: check extern_vals let memory_id = instance
let module_id = self.alloc_module(module, extern_vals); .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);
Ok(()) Ok(())
} }
} }
fn global_init_val(global: &GlobalEntry, module: &ModuleInstance, store: &Store) -> RuntimeValue { fn eval_init_expr(init_expr: &InitExpr, module: &ModuleInstance, store: &Store) -> RuntimeValue {
let code = global.init_expr().code(); let code = init_expr.code();
debug_assert!( debug_assert!(
code.len() == 2, code.len() == 2,
"due to validation `code`.len() should be 2" "Due to validation `code`.len() should be 2"
); );
match code[0] { match code[0] {
Opcode::I32Const(v) => v.into(), Opcode::I32Const(v) => v.into(),
@ -285,13 +306,13 @@ fn global_init_val(global: &GlobalEntry, module: &ModuleInstance, store: &Store)
let global_id = module let global_id = module
.globals .globals
.get(idx as usize) .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 let global_inst = store
.globals .globals
.get(global_id.0 as usize) .get(global_id.0 as usize)
.expect("ID should always be a valid index"); .expect("ID should always be a valid index");
global_inst.val.clone() global_inst.val.clone()
} }
_ => panic!("due to validation init should be a const expr"), _ => panic!("Due to validation init should be a const expr"),
} }
} }

View File

@ -1,20 +1,19 @@
use std::u32; use std::u32;
use std::sync::Arc;
use parking_lot::RwLock; use parking_lot::RwLock;
use elements::{TableType, ResizableLimits}; use elements::{TableType, ResizableLimits};
use interpreter::Error; use interpreter::Error;
use interpreter::module::check_limits; use interpreter::module::check_limits;
use interpreter::variable::{VariableInstance, VariableType}; use interpreter::variable::{VariableInstance, VariableType};
use interpreter::value::RuntimeValue; use interpreter::value::RuntimeValue;
use interpreter::store::FuncId;
/// Table instance. /// Table instance.
pub struct TableInstance { pub struct TableInstance {
/// Table limits. /// Table limits.
limits: ResizableLimits, limits: ResizableLimits,
/// Table variables type.
variable_type: VariableType,
/// Table memory buffer. /// Table memory buffer.
buffer: RwLock<Vec<TableElement>>, buffer: RwLock<Vec<Option<FuncId>>>,
} }
/// Table element. Cloneable wrapper around VariableInstance. /// Table element. Cloneable wrapper around VariableInstance.
@ -24,17 +23,14 @@ struct TableElement {
impl TableInstance { impl TableInstance {
/// New instance of the table /// New instance of the table
pub fn new(table_type: &TableType) -> Result<Arc<Self>, Error> { pub fn new(table_type: &TableType) -> Result<Self, Error> {
check_limits(table_type.limits())?; check_limits(table_type.limits())?;
Ok(TableInstance {
let variable_type = table_type.elem_type().into();
Ok(Arc::new(TableInstance {
limits: table_type.limits().clone(), limits: table_type.limits().clone(),
variable_type: variable_type,
buffer: RwLock::new( 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. /// Return table limits.
@ -44,51 +40,34 @@ impl TableInstance {
/// Get variable type for this table. /// Get variable type for this table.
pub fn variable_type(&self) -> VariableType { pub fn variable_type(&self) -> VariableType {
self.variable_type panic!("TODO")
} }
/// Get the specific value in the table /// Get the specific value in the table
pub fn get(&self, offset: u32) -> Result<RuntimeValue, Error> { pub fn get(&self, offset: u32) -> Result<FuncId, Error> {
let buffer = self.buffer.read(); let buffer = self.buffer.read();
let buffer_len = buffer.len(); let buffer_len = buffer.len();
buffer.get(offset as usize) let table_elem = buffer.get(offset as usize).ok_or(Error::Table(format!(
.map(|v| v.var.get()) "trying to read table item with index {} when there are only {} items",
.ok_or(Error::Table(format!("trying to read table item with index {} when there are only {} items", offset, buffer_len))) 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 /// Set the table element to the specified function.
pub fn set_raw(&self, mut offset: u32, module_name: String, value: &[u32]) -> Result<(), Error> { pub fn set(&self, offset: u32, value: FuncId) -> 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> {
let mut buffer = self.buffer.write(); let mut buffer = self.buffer.write();
let buffer_len = buffer.len(); let buffer_len = buffer.len();
buffer.get_mut(offset as usize) let table_elem = buffer.get_mut(offset as usize).ok_or(Error::Table(format!(
.ok_or(Error::Table(format!("trying to update table item with index {} when there are only {} items", offset, buffer_len))) "trying to update table item with index {} when there are only {} items",
.and_then(|v| v.var.set(value)) offset,
} buffer_len
} )))?;
*table_elem = Some(value);
impl TableElement { Ok(())
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"))
} }
} }