mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-18 09:21:49 +00:00
TableInstance is specialized for any func
This commit is contained in:
@ -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.
|
||||||
|
@ -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> {
|
||||||
|
@ -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"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user