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 {
/// 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())?;
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.

View File

@ -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::<Result<Vec<_>, _>>()?,
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::<Result<Vec<_>, _>>()?,
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<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, 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<Option<InternalFunction<'a>>, Error> {

View File

@ -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<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,
}
}
}
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<FuncInstance>,
tables: Vec<TableInstance>,
memories: Vec<MemInstance>,
memories: Vec<MemoryInstance>,
globals: Vec<GlobalInstance>,
// 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<TableId, Error> {
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<MemoryId, Error> {
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"),
}
}

View File

@ -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<Vec<TableElement>>,
buffer: RwLock<Vec<Option<FuncId>>>,
}
/// 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<Arc<Self>, Error> {
pub fn new(table_type: &TableType) -> Result<Self, Error> {
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<RuntimeValue, Error> {
pub fn get(&self, offset: u32) -> Result<FuncId, Error> {
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(())
}
}