Move instantiate into ModuleInstance

This commit is contained in:
Sergey Pepyakin
2017-12-13 15:00:54 +01:00
parent 68d7005554
commit bdc9490197
5 changed files with 311 additions and 345 deletions

View File

@ -3,7 +3,7 @@ use std::rc::Rc;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::collections::HashMap; use std::collections::HashMap;
use elements::{FunctionType, ValueType, GlobalType, MemoryType, TableType}; use elements::{FunctionType, ValueType, GlobalType, MemoryType, TableType};
use interpreter::store::{Store, ExternVal, ModuleInstance, GlobalInstance, FuncInstance}; use interpreter::store::{ExternVal, ModuleInstance, GlobalInstance, FuncInstance};
use interpreter::memory::MemoryInstance; use interpreter::memory::MemoryInstance;
use interpreter::table::TableInstance; use interpreter::table::TableInstance;
use interpreter::value::RuntimeValue; use interpreter::value::RuntimeValue;
@ -48,7 +48,7 @@ impl<St: 'static> HostModuleBuilder<St> {
} }
pub fn with_func0< pub fn with_func0<
Cl: Fn(&mut Store, &mut St) -> Result<Option<Ret>, Error> + 'static, Cl: Fn(&mut St) -> Result<Option<Ret>, Error> + 'static,
Ret: AsReturnVal + 'static, Ret: AsReturnVal + 'static,
F: Into<Func0<Cl, St, Ret>>, F: Into<Func0<Cl, St, Ret>>,
N: Into<String>, N: Into<String>,
@ -68,7 +68,7 @@ impl<St: 'static> HostModuleBuilder<St> {
} }
pub fn with_func1< pub fn with_func1<
Cl: Fn(&mut Store, &mut St, P1) -> Result<Option<Ret>, Error> + 'static, Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error> + 'static,
Ret: AsReturnVal + 'static, Ret: AsReturnVal + 'static,
P1: FromArg + 'static, P1: FromArg + 'static,
F: Into<Func1<Cl, St, Ret, P1>>, F: Into<Func1<Cl, St, Ret, P1>>,
@ -89,7 +89,7 @@ impl<St: 'static> HostModuleBuilder<St> {
} }
pub fn with_func2< pub fn with_func2<
Cl: Fn(&mut Store, &mut St, P1, P2) -> Result<Option<Ret>, Error> + 'static, Cl: Fn(&mut St, P1, P2) -> Result<Option<Ret>, Error> + 'static,
Ret: AsReturnVal + 'static, Ret: AsReturnVal + 'static,
P1: FromArg + 'static, P1: FromArg + 'static,
P2: FromArg + 'static, P2: FromArg + 'static,
@ -189,7 +189,6 @@ impl HostModule {
pub trait AnyFunc { pub trait AnyFunc {
fn call_as_any( fn call_as_any(
&self, &self,
store: &mut Store,
state: &mut Any, state: &mut Any,
args: &[RuntimeValue], args: &[RuntimeValue],
) -> Result<Option<RuntimeValue>, Error>; ) -> Result<Option<RuntimeValue>, Error>;
@ -238,7 +237,7 @@ impl AsReturnVal for () {
} }
} }
pub struct Func0<Cl: Fn(&mut Store, &mut St) -> Result<Option<Ret>, Error>, St, Ret: AsReturnVal> { pub struct Func0<Cl: Fn(&mut St) -> Result<Option<Ret>, Error>, St, Ret: AsReturnVal> {
closure: Cl, closure: Cl,
_marker: PhantomData<(St, Ret)>, _marker: PhantomData<(St, Ret)>,
} }
@ -246,21 +245,20 @@ pub struct Func0<Cl: Fn(&mut Store, &mut St) -> Result<Option<Ret>, Error>, St,
impl< impl<
St: 'static, St: 'static,
Ret: AsReturnVal, Ret: AsReturnVal,
Cl: Fn(&mut Store, &mut St) -> Result<Option<Ret>, Error>, Cl: Fn(&mut St) -> Result<Option<Ret>, Error>,
> AnyFunc for Func0<Cl, St, Ret> { > AnyFunc for Func0<Cl, St, Ret> {
fn call_as_any( fn call_as_any(
&self, &self,
store: &mut Store,
state: &mut Any, state: &mut Any,
_args: &[RuntimeValue], _args: &[RuntimeValue],
) -> Result<Option<RuntimeValue>, Error> { ) -> Result<Option<RuntimeValue>, Error> {
let state = state.downcast_mut::<St>().unwrap(); let state = state.downcast_mut::<St>().unwrap();
let result = (self.closure)(store, state); let result = (self.closure)(state);
result.map(|r| r.and_then(|r| r.as_return_val())) result.map(|r| r.and_then(|r| r.as_return_val()))
} }
} }
impl<St: 'static, Ret: AsReturnVal, Cl: Fn(&mut Store, &mut St) -> Result<Option<Ret>, Error>> From<Cl> impl<St: 'static, Ret: AsReturnVal, Cl: Fn(&mut St) -> Result<Option<Ret>, Error>> From<Cl>
for Func0<Cl, St, Ret> { for Func0<Cl, St, Ret> {
fn from(cl: Cl) -> Self { fn from(cl: Cl) -> Self {
Func0 { Func0 {
@ -273,14 +271,14 @@ impl<St: 'static, Ret: AsReturnVal, Cl: Fn(&mut Store, &mut St) -> Result<Option
impl< impl<
St: 'static, St: 'static,
Ret: AsReturnVal, Ret: AsReturnVal,
Cl: Fn(&mut Store, &mut St) -> Result<Option<Ret>, Error>, Cl: Fn(&mut St) -> Result<Option<Ret>, Error>,
> Func0<Cl, St, Ret> { > Func0<Cl, St, Ret> {
fn derive_func_type() -> FunctionType { fn derive_func_type() -> FunctionType {
FunctionType::new(vec![], Ret::value_type()) FunctionType::new(vec![], Ret::value_type())
} }
} }
pub struct Func1<Cl: Fn(&mut Store, &mut St, P1) -> Result<Option<Ret>, Error>, St, Ret: AsReturnVal, P1: FromArg> { pub struct Func1<Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error>, St, Ret: AsReturnVal, P1: FromArg> {
closure: Cl, closure: Cl,
_marker: PhantomData<(St, Ret, P1)>, _marker: PhantomData<(St, Ret, P1)>,
} }
@ -289,22 +287,21 @@ impl<
St: 'static, St: 'static,
Ret: AsReturnVal, Ret: AsReturnVal,
P1: FromArg, P1: FromArg,
Cl: Fn(&mut Store, &mut St, P1) -> Result<Option<Ret>, Error>, Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error>,
> AnyFunc for Func1<Cl, St, Ret, P1> { > AnyFunc for Func1<Cl, St, Ret, P1> {
fn call_as_any( fn call_as_any(
&self, &self,
store: &mut Store,
state: &mut Any, state: &mut Any,
args: &[RuntimeValue], args: &[RuntimeValue],
) -> Result<Option<RuntimeValue>, Error> { ) -> Result<Option<RuntimeValue>, Error> {
let state = state.downcast_mut::<St>().unwrap(); let state = state.downcast_mut::<St>().unwrap();
let p1 = P1::from_arg(&args[0]); let p1 = P1::from_arg(&args[0]);
let result = (self.closure)(store, state, p1); let result = (self.closure)(state, p1);
result.map(|r| r.and_then(|r| r.as_return_val())) result.map(|r| r.and_then(|r| r.as_return_val()))
} }
} }
impl<St: 'static, Ret: AsReturnVal, P1: FromArg, Cl: Fn(&mut Store, &mut St, P1) -> Result<Option<Ret>, Error>> From<Cl> impl<St: 'static, Ret: AsReturnVal, P1: FromArg, Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error>> From<Cl>
for Func1<Cl, St, Ret, P1> { for Func1<Cl, St, Ret, P1> {
fn from(cl: Cl) -> Self { fn from(cl: Cl) -> Self {
Func1 { Func1 {
@ -318,14 +315,14 @@ impl<
St: 'static, St: 'static,
Ret: AsReturnVal, Ret: AsReturnVal,
P1: FromArg, P1: FromArg,
Cl: Fn(&mut Store, &mut St, P1) -> Result<Option<Ret>, Error>, Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error>,
> Func1<Cl, St, Ret, P1> { > Func1<Cl, St, Ret, P1> {
fn derive_func_type() -> FunctionType { fn derive_func_type() -> FunctionType {
FunctionType::new(vec![P1::value_type()], Ret::value_type()) FunctionType::new(vec![P1::value_type()], Ret::value_type())
} }
} }
pub struct Func2<Cl: Fn(&mut Store, &mut St, P1, P2) -> Result<Option<Ret>, Error>, St, Ret: AsReturnVal, P1: FromArg, P2: FromArg> { pub struct Func2<Cl: Fn(&mut St, P1, P2) -> Result<Option<Ret>, Error>, St, Ret: AsReturnVal, P1: FromArg, P2: FromArg> {
closure: Cl, closure: Cl,
_marker: PhantomData<(St, Ret, P1, P2)>, _marker: PhantomData<(St, Ret, P1, P2)>,
} }
@ -335,23 +332,22 @@ impl<
Ret: AsReturnVal, Ret: AsReturnVal,
P1: FromArg, P1: FromArg,
P2: FromArg, P2: FromArg,
Cl: Fn(&mut Store, &mut St, P1, P2) -> Result<Option<Ret>, Error>, Cl: Fn(&mut St, P1, P2) -> Result<Option<Ret>, Error>,
> AnyFunc for Func2<Cl, St, Ret, P1, P2> { > AnyFunc for Func2<Cl, St, Ret, P1, P2> {
fn call_as_any( fn call_as_any(
&self, &self,
store: &mut Store,
state: &mut Any, state: &mut Any,
args: &[RuntimeValue], args: &[RuntimeValue],
) -> Result<Option<RuntimeValue>, Error> { ) -> Result<Option<RuntimeValue>, Error> {
let state = state.downcast_mut::<St>().unwrap(); let state = state.downcast_mut::<St>().unwrap();
let p1 = P1::from_arg(&args[0]); let p1 = P1::from_arg(&args[0]);
let p2 = P2::from_arg(&args[1]); let p2 = P2::from_arg(&args[1]);
let result = (self.closure)(store, state, p1, p2); let result = (self.closure)(state, p1, p2);
result.map(|r| r.and_then(|r| r.as_return_val())) result.map(|r| r.and_then(|r| r.as_return_val()))
} }
} }
impl<St: 'static, Ret: AsReturnVal, P1: FromArg, P2: FromArg, Cl: Fn(&mut Store, &mut St, P1, P2) -> Result<Option<Ret>, Error>> From<Cl> impl<St: 'static, Ret: AsReturnVal, P1: FromArg, P2: FromArg, Cl: Fn(&mut St, P1, P2) -> Result<Option<Ret>, Error>> From<Cl>
for Func2<Cl, St, Ret, P1, P2> { for Func2<Cl, St, Ret, P1, P2> {
fn from(cl: Cl) -> Self { fn from(cl: Cl) -> Self {
Func2 { Func2 {
@ -366,7 +362,7 @@ impl<
Ret: AsReturnVal, Ret: AsReturnVal,
P1: FromArg, P1: FromArg,
P2: FromArg, P2: FromArg,
Cl: Fn(&mut Store, &mut St, P1, P2) -> Result<Option<Ret>, Error>, Cl: Fn(&mut St, P1, P2) -> Result<Option<Ret>, Error>,
> Func2<Cl, St, Ret, P1, P2> { > Func2<Cl, St, Ret, P1, P2> {
fn derive_func_type() -> FunctionType { fn derive_func_type() -> FunctionType {
FunctionType::new(vec![P1::value_type(), P2::value_type()], Ret::value_type()) FunctionType::new(vec![P1::value_type(), P2::value_type()], Ret::value_type())

View File

@ -2,13 +2,12 @@ use std::rc::Rc;
use std::collections::HashMap; use std::collections::HashMap;
use elements::Module; use elements::Module;
use interpreter::Error; use interpreter::Error;
use interpreter::store::{Store, ExternVal, FuncInstance, ModuleInstance}; use interpreter::store::{ExternVal, FuncInstance, ModuleInstance};
use interpreter::host::HostModule; use interpreter::host::HostModule;
use interpreter::value::RuntimeValue; use interpreter::value::RuntimeValue;
/// Program instance. Program is a set of instantiated modules. /// Program instance. Program is a set of instantiated modules.
pub struct ProgramInstance { pub struct ProgramInstance {
store: Store,
modules: HashMap<String, Rc<ModuleInstance>>, modules: HashMap<String, Rc<ModuleInstance>>,
} }
@ -16,7 +15,6 @@ impl ProgramInstance {
/// Create new program instance. /// Create new program instance.
pub fn new() -> Self { pub fn new() -> Self {
ProgramInstance { ProgramInstance {
store: Store::new(),
modules: HashMap::new(), modules: HashMap::new(),
} }
} }
@ -43,7 +41,7 @@ impl ProgramInstance {
extern_vals.push(extern_val); extern_vals.push(extern_val);
} }
let module_instance = self.store.instantiate_module(&module, &extern_vals, state)?; let module_instance = ModuleInstance::instantiate(&module, &extern_vals, state)?;
self.modules.insert(name.to_owned(), Rc::clone(&module_instance)); self.modules.insert(name.to_owned(), Rc::clone(&module_instance));
Ok(module_instance) Ok(module_instance)
@ -90,11 +88,11 @@ impl ProgramInstance {
"Export {} is not a function, but {:?}", "Export {} is not a function, but {:?}",
func_name, func_name,
unexpected unexpected
))) )));
} }
}; };
self.store.invoke(func_instance, args, state) FuncInstance::invoke(Rc::clone(&func_instance), args, state)
} }
pub fn invoke_index<St: 'static>( pub fn invoke_index<St: 'static>(
@ -115,15 +113,11 @@ impl ProgramInstance {
pub fn invoke_func<St: 'static>( pub fn invoke_func<St: 'static>(
&mut self, &mut self,
func: Rc<FuncInstance>, func_instance: Rc<FuncInstance>,
args: Vec<RuntimeValue>, args: Vec<RuntimeValue>,
state: &mut St, state: &mut St,
) -> Result<Option<RuntimeValue>, Error> { ) -> Result<Option<RuntimeValue>, Error> {
self.store.invoke(func, args, state) FuncInstance::invoke(Rc::clone(&func_instance), args, state)
}
pub fn store(&self) -> &Store {
&self.store
} }
pub fn module(&self, name: &str) -> Option<Rc<ModuleInstance>> { pub fn module(&self, name: &str) -> Option<Rc<ModuleInstance>> {

View File

@ -7,7 +7,7 @@ use std::iter::repeat;
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
use elements::{Opcode, BlockType, Local, FunctionType}; use elements::{Opcode, BlockType, Local, FunctionType};
use interpreter::Error; use interpreter::Error;
use interpreter::store::{Store, FuncInstance, ModuleInstance}; use interpreter::store::{FuncInstance, ModuleInstance};
use interpreter::value::{ use interpreter::value::{
RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto, RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto,
ArithmeticOps, Integer, Float, LittleEndianConvert, TransmuteInto, ArithmeticOps, Integer, Float, LittleEndianConvert, TransmuteInto,
@ -17,7 +17,6 @@ use common::stack::StackWithLimit;
/// Function interpreter. /// Function interpreter.
pub struct Interpreter<'a, St: 'static> { pub struct Interpreter<'a, St: 'static> {
store: &'a mut Store,
state: &'a mut St, state: &'a mut St,
} }
@ -64,9 +63,8 @@ enum RunResult {
} }
impl<'a, St: 'static> Interpreter<'a, St> { impl<'a, St: 'static> Interpreter<'a, St> {
pub fn new(store: &'a mut Store, state: &'a mut St) -> Interpreter<'a, St> { pub fn new(state: &'a mut St) -> Interpreter<'a, St> {
Interpreter { Interpreter {
store,
state state
} }
} }
@ -78,24 +76,14 @@ impl<'a, St: 'static> Interpreter<'a, St> {
loop { loop {
let mut function_context = function_stack.pop_back().expect("on loop entry - not empty; on loop continue - checking for emptiness; qed"); let mut function_context = function_stack.pop_back().expect("on loop entry - not empty; on loop continue - checking for emptiness; qed");
let function_ref = Rc::clone(&function_context.function); let function_ref = Rc::clone(&function_context.function);
let function_return = { let function_body = function_ref.body().expect("Host functions checked in function_return below; Internal functions always have a body; qed");
match function_ref.body() {
Some(function_body) => {
if !function_context.is_initialized() { if !function_context.is_initialized() {
let return_type = function_context.return_type; let return_type = function_context.return_type;
function_context.initialize(&function_body.locals); function_context.initialize(&function_body.locals);
function_context.push_frame(&function_body.labels, BlockFrameType::Function, return_type)?; function_context.push_frame(&function_body.labels, BlockFrameType::Function, return_type)?;
} }
self.do_run_function(&mut function_context, function_body.opcodes.elements(), &function_body.labels)? let function_return = self.do_run_function(&mut function_context, function_body.opcodes.elements(), &function_body.labels)?;
},
None => {
let args: Vec<_> = function_context.locals.drain(..).collect();
let result = self.store.invoke(function_ref, args, self.state)?;
RunResult::Return(result)
},
}
};
match function_return { match function_return {
RunResult::Return(return_value) => { RunResult::Return(return_value) => {
@ -116,7 +104,7 @@ impl<'a, St: 'static> Interpreter<'a, St> {
}, },
FuncInstance::Host { ref func_type, .. } => { FuncInstance::Host { ref func_type, .. } => {
let args = prepare_function_args(func_type, &mut function_context.value_stack)?; let args = prepare_function_args(func_type, &mut function_context.value_stack)?;
let return_val = self.store.invoke(Rc::clone(&nested_func), args, self.state)?; let return_val = FuncInstance::invoke(Rc::clone(&nested_func), args, self.state)?;
if let Some(return_val) = return_val { if let Some(return_val) = return_val {
function_context.value_stack_mut().push(return_val)?; function_context.value_stack_mut().push(return_val)?;
} }

View File

@ -98,6 +98,45 @@ impl FuncInstance {
} }
} }
impl FuncInstance {
pub fn invoke<St: 'static>(
func: Rc<FuncInstance>,
args: Vec<RuntimeValue>,
state: &mut St,
) -> Result<Option<RuntimeValue>, Error> {
enum InvokeKind {
Internal(FunctionContext),
Host(Rc<AnyFunc>, Vec<RuntimeValue>),
}
let result = match *func {
FuncInstance::Internal { ref func_type, .. } => {
let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT);
let args = prepare_function_args(func_type, &mut args)?;
let context = FunctionContext::new(
Rc::clone(&func),
DEFAULT_VALUE_STACK_LIMIT,
DEFAULT_FRAME_STACK_LIMIT,
func_type,
args,
);
InvokeKind::Internal(context)
}
FuncInstance::Host { ref host_func, .. } => InvokeKind::Host(Rc::clone(host_func), args),
};
match result {
InvokeKind::Internal(ctx) => {
let mut interpreter = Interpreter::new(state);
interpreter.run_function(ctx)
}
InvokeKind::Host(host_func, args) => {
host_func.call_as_any(state as &mut Any, &args)
}
}
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct FuncBody { pub struct FuncBody {
pub locals: Vec<Local>, pub locals: Vec<Local>,
@ -159,6 +198,211 @@ impl ModuleInstance {
} }
} }
fn alloc_module_internal(
module: &Module,
extern_vals: &[ExternVal],
instance: &Rc<ModuleInstance>,
) -> Result<(), Error> {
let mut aux_data = validate_module(module)?;
for &Type::Function(ref ty) in module
.type_section()
.map(|ts| ts.types())
.unwrap_or(&[])
{
let type_id = alloc_func_type(ty.clone());
instance.push_type(type_id);
}
{
let imports = module.import_section().map(|is| is.entries()).unwrap_or(&[]);
if imports.len() != extern_vals.len() {
return Err(Error::Initialization(format!("extern_vals length is not equal to import section entries")));
}
for (import, extern_val) in Iterator::zip(imports.into_iter(), extern_vals.into_iter())
{
match (import.external(), extern_val) {
(&External::Function(fn_type_idx), &ExternVal::Func(ref func)) => {
let expected_fn_type = instance.type_by_index(fn_type_idx).expect("Due to validation function type should exists");
let actual_fn_type = func.func_type();
if expected_fn_type != actual_fn_type {
return Err(Error::Initialization(format!(
"Expected function with type {:?}, but actual type is {:?} for entry {}",
expected_fn_type,
actual_fn_type,
import.field(),
)));
}
instance.push_func(Rc::clone(func))
}
(&External::Table(ref tt), &ExternVal::Table(ref table)) => {
match_limits(table.limits(), tt.limits())?;
instance.push_table(Rc::clone(table));
}
(&External::Memory(ref mt), &ExternVal::Memory(ref memory)) => {
match_limits(memory.limits(), mt.limits())?;
instance.push_memory(Rc::clone(memory));
}
(&External::Global(ref gl), &ExternVal::Global(ref global)) => {
// TODO: check globals
instance.push_global(Rc::clone(global))
}
(expected_import, actual_extern_val) => {
return Err(Error::Initialization(format!(
"Expected {:?} type, but provided {:?} extern_val",
expected_import,
actual_extern_val
)));
}
}
}
}
{
let funcs = module
.function_section()
.map(|fs| fs.entries())
.unwrap_or(&[]);
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"
);
for (index, (ty, body)) in
Iterator::zip(funcs.into_iter(), bodies.into_iter()).enumerate()
{
let func_type = instance.type_by_index(ty.type_ref()).expect("Due to validation type should exists");
let labels = aux_data.labels.remove(&index).expect(
"At func validation time labels are collected; Collected labels are added by index; qed",
);
let func_body = FuncBody {
locals: body.locals().to_vec(),
opcodes: body.code().clone(),
labels: labels,
};
let func_instance = alloc_func(instance, func_type, func_body);
instance.push_func(func_instance);
}
}
for table_type in module.table_section().map(|ts| ts.entries()).unwrap_or(&[]) {
let table = alloc_table(table_type)?;
instance.push_table(table);
}
for memory_type in module
.memory_section()
.map(|ms| ms.entries())
.unwrap_or(&[])
{
let memory = alloc_memory(memory_type)?;
instance.push_memory(memory);
}
for global_entry in module
.global_section()
.map(|gs| gs.entries())
.unwrap_or(&[])
{
let init_val = eval_init_expr(global_entry.init_expr(), &*instance);
let global = alloc_global(global_entry.global_type().clone(), init_val);
instance.push_global(global);
}
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 = instance
.func_by_index(idx)
.expect("Due to validation func should exists");
ExternVal::Func(func)
}
Internal::Global(idx) => {
let global = instance
.global_by_index(idx)
.expect("Due to validation global should exists");
ExternVal::Global(global)
}
Internal::Memory(idx) => {
let memory = instance
.memory_by_index(idx)
.expect("Due to validation memory should exists");
ExternVal::Memory(memory)
}
Internal::Table(idx) => {
let table = instance
.table_by_index(idx)
.expect("Due to validation table should exists");
ExternVal::Table(table)
}
};
instance.insert_export(field, extern_val);
}
Ok(())
}
pub fn instantiate<St: 'static>(
module: &Module,
extern_vals: &[ExternVal],
state: &mut St,
) -> Result<Rc<ModuleInstance>, Error> {
let mut instance = Rc::new(ModuleInstance::new());
ModuleInstance::alloc_module_internal(module, extern_vals, &instance)?;
for element_segment in module
.elements_section()
.map(|es| es.entries())
.unwrap_or(&[])
{
let offset_val = match eval_init_expr(element_segment.offset(), &instance) {
RuntimeValue::I32(v) => v as u32,
_ => panic!("Due to validation elem segment offset should evaluate to i32"),
};
let table_inst = instance
.table_by_index(DEFAULT_TABLE_INDEX)
.expect("Due to validation default table should exists");
for (j, func_idx) in element_segment.members().into_iter().enumerate() {
let func = instance
.func_by_index(*func_idx)
.expect("Due to validation funcs from element segments should exists");
table_inst.set(offset_val + j as u32, func);
}
}
for data_segment in module.data_section().map(|ds| ds.entries()).unwrap_or(&[]) {
let offset_val = match eval_init_expr(data_segment.offset(), &instance) {
RuntimeValue::I32(v) => v as u32,
_ => panic!("Due to validation data segment offset should evaluate to i32"),
};
let memory_inst = instance
.memory_by_index(DEFAULT_MEMORY_INDEX)
.expect("Due to validation default memory should exists");
memory_inst.set(offset_val, data_segment.value())?;
}
// And run module's start function, if any
if let Some(start_fn_idx) = module.start_section() {
let start_func = instance
.func_by_index(start_fn_idx)
.expect("Due to validation start function should exists");
FuncInstance::invoke(start_func, vec![], state)?;
}
Ok(instance)
}
pub fn memory_by_index(&self, idx: u32) -> Option<Rc<MemoryInstance>> { pub fn memory_by_index(&self, idx: u32) -> Option<Rc<MemoryInstance>> {
self self
.memories .memories
@ -235,19 +479,12 @@ impl ModuleInstance {
} }
} }
#[derive(Default, Debug)]
pub struct Store;
impl Store { fn alloc_func_type(func_type: FunctionType) -> Rc<FunctionType> {
pub fn new() -> Store {
Store::default()
}
pub fn alloc_func_type(&mut self, func_type: FunctionType) -> Rc<FunctionType> {
Rc::new(func_type) Rc::new(func_type)
} }
pub fn alloc_func(&mut self, module: &Rc<ModuleInstance>, func_type: Rc<FunctionType>, body: FuncBody) -> Rc<FuncInstance> { fn alloc_func(module: &Rc<ModuleInstance>, func_type: Rc<FunctionType>, body: FuncBody) -> Rc<FuncInstance> {
let func = FuncInstance::Internal { let func = FuncInstance::Internal {
func_type, func_type,
module: Rc::clone(module), module: Rc::clone(module),
@ -256,7 +493,7 @@ impl Store {
Rc::new(func) Rc::new(func)
} }
pub fn alloc_host_func(&mut self, func_type: Rc<FunctionType>, host_func: Rc<AnyFunc>) -> Rc<FuncInstance> { fn alloc_host_func(func_type: Rc<FunctionType>, host_func: Rc<AnyFunc>) -> Rc<FuncInstance> {
let func = FuncInstance::Host { let func = FuncInstance::Host {
func_type, func_type,
host_func, host_func,
@ -264,269 +501,21 @@ impl Store {
Rc::new(func) Rc::new(func)
} }
pub fn alloc_table(&mut self, table_type: &TableType) -> Result<Rc<TableInstance>, Error> { fn alloc_table(table_type: &TableType) -> Result<Rc<TableInstance>, Error> {
let table = TableInstance::new(table_type)?; let table = TableInstance::new(table_type)?;
Ok(Rc::new(table)) Ok(Rc::new(table))
} }
pub fn alloc_memory(&mut self, mem_type: &MemoryType) -> Result<Rc<MemoryInstance>, Error> { fn alloc_memory(mem_type: &MemoryType) -> Result<Rc<MemoryInstance>, Error> {
let memory = MemoryInstance::new(&mem_type)?; let memory = MemoryInstance::new(&mem_type)?;
Ok(Rc::new(memory)) Ok(Rc::new(memory))
} }
pub fn alloc_global(&mut self, global_type: GlobalType, val: RuntimeValue) -> Rc<GlobalInstance> { fn alloc_global(global_type: GlobalType, val: RuntimeValue) -> Rc<GlobalInstance> {
let global = GlobalInstance::new(val, global_type.is_mutable()); let global = GlobalInstance::new(val, global_type.is_mutable());
Rc::new(global) Rc::new(global)
} }
fn alloc_module_internal(
&mut self,
module: &Module,
extern_vals: &[ExternVal],
instance: &Rc<ModuleInstance>,
) -> Result<(), Error> {
let mut aux_data = validate_module(module)?;
for &Type::Function(ref ty) in module
.type_section()
.map(|ts| ts.types())
.unwrap_or(&[])
{
let type_id = self.alloc_func_type(ty.clone());
instance.push_type(type_id);
}
{
let imports = module.import_section().map(|is| is.entries()).unwrap_or(&[]);
if imports.len() != extern_vals.len() {
return Err(Error::Initialization(format!("extern_vals length is not equal to import section entries")));
}
for (import, extern_val) in Iterator::zip(imports.into_iter(), extern_vals.into_iter())
{
match (import.external(), extern_val) {
(&External::Function(fn_type_idx), &ExternVal::Func(ref func)) => {
let expected_fn_type = instance.type_by_index(fn_type_idx).expect("Due to validation function type should exists");
let actual_fn_type = func.func_type();
if expected_fn_type != actual_fn_type {
return Err(Error::Initialization(format!(
"Expected function with type {:?}, but actual type is {:?} for entry {}",
expected_fn_type,
actual_fn_type,
import.field(),
)));
}
instance.push_func(Rc::clone(func))
}
(&External::Table(ref tt), &ExternVal::Table(ref table)) => {
match_limits(table.limits(), tt.limits())?;
instance.push_table(Rc::clone(table));
}
(&External::Memory(ref mt), &ExternVal::Memory(ref memory)) => {
match_limits(memory.limits(), mt.limits())?;
instance.push_memory(Rc::clone(memory));
}
(&External::Global(ref gl), &ExternVal::Global(ref global)) => {
// TODO: check globals
instance.push_global(Rc::clone(global))
}
(expected_import, actual_extern_val) => {
return Err(Error::Initialization(format!(
"Expected {:?} type, but provided {:?} extern_val",
expected_import,
actual_extern_val
)));
}
}
}
}
{
let funcs = module
.function_section()
.map(|fs| fs.entries())
.unwrap_or(&[]);
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"
);
for (index, (ty, body)) in
Iterator::zip(funcs.into_iter(), bodies.into_iter()).enumerate()
{
let func_type = instance.type_by_index(ty.type_ref()).expect("Due to validation type should exists");
let labels = aux_data.labels.remove(&index).expect(
"At func validation time labels are collected; Collected labels are added by index; qed",
);
let func_body = FuncBody {
locals: body.locals().to_vec(),
opcodes: body.code().clone(),
labels: labels,
};
let func_instance = self.alloc_func(instance, func_type, func_body);
instance.push_func(func_instance);
}
}
for table_type in module.table_section().map(|ts| ts.entries()).unwrap_or(&[]) {
let table = self.alloc_table(table_type)?;
instance.push_table(table);
}
for memory_type in module
.memory_section()
.map(|ms| ms.entries())
.unwrap_or(&[])
{
let memory = self.alloc_memory(memory_type)?;
instance.push_memory(memory);
}
for global_entry in module
.global_section()
.map(|gs| gs.entries())
.unwrap_or(&[])
{
let init_val = eval_init_expr(global_entry.init_expr(), &*instance);
let global = self.alloc_global(global_entry.global_type().clone(), init_val);
instance.push_global(global);
}
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 = instance
.func_by_index(idx)
.expect("Due to validation func should exists");
ExternVal::Func(func)
}
Internal::Global(idx) => {
let global = instance
.global_by_index(idx)
.expect("Due to validation global should exists");
ExternVal::Global(global)
}
Internal::Memory(idx) => {
let memory = instance
.memory_by_index(idx)
.expect("Due to validation memory should exists");
ExternVal::Memory(memory)
}
Internal::Table(idx) => {
let table = instance
.table_by_index(idx)
.expect("Due to validation table should exists");
ExternVal::Table(table)
}
};
instance.insert_export(field, extern_val);
}
Ok(())
}
pub fn instantiate_module<St: 'static>(
&mut self,
module: &Module,
extern_vals: &[ExternVal],
state: &mut St,
) -> Result<Rc<ModuleInstance>, Error> {
let mut instance = Rc::new(ModuleInstance::new());
self.alloc_module_internal(module, extern_vals, &instance)?;
for element_segment in module
.elements_section()
.map(|es| es.entries())
.unwrap_or(&[])
{
let offset_val = match eval_init_expr(element_segment.offset(), &instance) {
RuntimeValue::I32(v) => v as u32,
_ => panic!("Due to validation elem segment offset should evaluate to i32"),
};
let table_inst = instance
.table_by_index(DEFAULT_TABLE_INDEX)
.expect("Due to validation default table should exists");
for (j, func_idx) in element_segment.members().into_iter().enumerate() {
let func = instance
.func_by_index(*func_idx)
.expect("Due to validation funcs from element segments should exists");
table_inst.set(offset_val + j as u32, func);
}
}
for data_segment in module.data_section().map(|ds| ds.entries()).unwrap_or(&[]) {
let offset_val = match eval_init_expr(data_segment.offset(), &instance) {
RuntimeValue::I32(v) => v as u32,
_ => panic!("Due to validation data segment offset should evaluate to i32"),
};
let memory_inst = instance
.memory_by_index(DEFAULT_MEMORY_INDEX)
.expect("Due to validation default memory should exists");
memory_inst.set(offset_val, data_segment.value())?;
}
// And run module's start function, if any
if let Some(start_fn_idx) = module.start_section() {
let start_func = {
instance
.func_by_index(start_fn_idx)
.expect("Due to validation start function should exists")
};
self.invoke(start_func, vec![], state)?;
}
Ok(instance)
}
pub fn invoke<St: 'static>(
&mut self,
func: Rc<FuncInstance>,
args: Vec<RuntimeValue>,
state: &mut St,
) -> Result<Option<RuntimeValue>, Error> {
enum InvokeKind {
Internal(FunctionContext),
Host(Rc<AnyFunc>, Vec<RuntimeValue>),
}
let result = match *func {
FuncInstance::Internal { ref func_type, .. } => {
let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT);
let args = prepare_function_args(func_type, &mut args)?;
let context = FunctionContext::new(
Rc::clone(&func),
DEFAULT_VALUE_STACK_LIMIT,
DEFAULT_FRAME_STACK_LIMIT,
func_type,
args,
);
InvokeKind::Internal(context)
}
FuncInstance::Host { ref host_func, .. } => InvokeKind::Host(Rc::clone(host_func), args),
};
match result {
InvokeKind::Internal(ctx) => {
let mut interpreter = Interpreter::new(self, state);
interpreter.run_function(ctx)
}
InvokeKind::Host(host_func, args) => {
host_func.call_as_any(self, state as &mut Any, &args)
}
}
}
}
fn eval_init_expr(init_expr: &InitExpr, module: &ModuleInstance) -> RuntimeValue { fn eval_init_expr(init_expr: &InitExpr, module: &ModuleInstance) -> RuntimeValue {
let code = init_expr.code(); let code = init_expr.code();
debug_assert!( debug_assert!(

View File

@ -7,7 +7,6 @@ use elements::{ExportEntry, Internal, ImportEntry, External, GlobalEntry, Global
use interpreter::{Error, UserError, ProgramInstance}; use interpreter::{Error, UserError, ProgramInstance};
use interpreter::value::RuntimeValue; use interpreter::value::RuntimeValue;
use interpreter::host::{HostModuleBuilder, HostModule}; use interpreter::host::{HostModuleBuilder, HostModule};
use interpreter::store::Store;
use interpreter::memory::MemoryInstance; use interpreter::memory::MemoryInstance;
use super::utils::program_with_default_env; use super::utils::program_with_default_env;
@ -122,7 +121,7 @@ struct FunctionExecutor {
fn build_env_module() -> HostModule { fn build_env_module() -> HostModule {
let mut builder = HostModuleBuilder::<FunctionExecutor>::new(); let mut builder = HostModuleBuilder::<FunctionExecutor>::new();
builder.with_func2("add", |_store: &mut Store, state: &mut FunctionExecutor, arg: i32, unused: i32| { builder.with_func2("add", |state: &mut FunctionExecutor, arg: i32, unused: i32| {
let memory_value = state.memory.get(0, 1).unwrap()[0]; let memory_value = state.memory.get(0, 1).unwrap()[0];
let fn_argument_unused = unused as u8; let fn_argument_unused = unused as u8;
let fn_argument = arg as u8; let fn_argument = arg as u8;
@ -133,7 +132,7 @@ fn build_env_module() -> HostModule {
state.values.push(sum as i32); state.values.push(sum as i32);
Ok(Some(sum as i32)) Ok(Some(sum as i32))
}); });
builder.with_func2("sub", |_store: &mut Store, state: &mut FunctionExecutor, arg: i32, unused: i32| { builder.with_func2("sub", |state: &mut FunctionExecutor, arg: i32, unused: i32| {
let memory_value = state.memory.get(0, 1).unwrap()[0]; let memory_value = state.memory.get(0, 1).unwrap()[0];
let fn_argument_unused = unused as u8; let fn_argument_unused = unused as u8;
let fn_argument = arg as u8; let fn_argument = arg as u8;
@ -144,7 +143,7 @@ fn build_env_module() -> HostModule {
state.values.push(diff as i32); state.values.push(diff as i32);
Ok(Some(diff as i32)) Ok(Some(diff as i32))
}); });
builder.with_func2("err", |_: &mut Store, _: &mut FunctionExecutor, _unused1: i32, _unused2: i32| -> Result<Option<i32>, Error> { builder.with_func2("err", |_: &mut FunctionExecutor, _unused1: i32, _unused2: i32| -> Result<Option<i32>, Error> {
Err(Error::User(Box::new(UserErrorWithCode { error_code: 777 }))) Err(Error::User(Box::new(UserErrorWithCode { error_code: 777 })))
}); });
builder.with_memory("memory", MemoryType::new(256, None)); builder.with_memory("memory", MemoryType::new(256, None));