Invoke stuff and state.

This commit is contained in:
Sergey Pepyakin
2017-12-11 18:38:09 +01:00
parent 8588899f82
commit 0860436d33
5 changed files with 78 additions and 78 deletions

View File

@ -1,7 +1,8 @@
use std::any::Any; use std::any::Any;
use std::sync::Arc;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::collections::HashMap; use std::collections::HashMap;
use elements::{FunctionType, ValueType}; use elements::{FunctionType, ValueType, GlobalType, MemoryType, TableType};
use interpreter::store::{Store, ExternVal}; use interpreter::store::{Store, ExternVal};
use interpreter::value::RuntimeValue; use interpreter::value::RuntimeValue;
use interpreter::Error; use interpreter::Error;
@ -21,7 +22,7 @@ impl<'a, St: 'static> HostModuleBuilder<'a, St> {
} }
} }
pub fn push_func1< pub fn with_func1<
Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error> + 'static, Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error> + 'static,
Ret: AsReturn + 'static, Ret: AsReturn + 'static,
P1: FromArg + 'static, P1: FromArg + 'static,
@ -34,12 +35,25 @@ impl<'a, St: 'static> HostModuleBuilder<'a, St> {
let func_type = Func1::<Cl, St, Ret, P1>::derive_func_type(); let func_type = Func1::<Cl, St, Ret, P1>::derive_func_type();
let type_id = self.store.alloc_func_type(func_type); let type_id = self.store.alloc_func_type(func_type);
let anyfunc = Box::new(f.into()) as Box<AnyFunc>; let anyfunc = Arc::new(f.into()) as Arc<AnyFunc>;
let func_id = self.store.alloc_host_func(type_id, anyfunc); let func_id = self.store.alloc_host_func(type_id, anyfunc);
let extern_val = ExternVal::Func(func_id); self.exports.insert(name.to_owned(), ExternVal::Func(func_id));
}
self.exports.insert(name.to_owned(), extern_val); pub fn with_global(&mut self, name: &str, global_type: GlobalType, val: RuntimeValue) {
let global_id = self.store.alloc_global(global_type, val);
self.exports.insert(name.to_owned(), ExternVal::Global(global_id));
}
pub fn with_memory(&mut self, name: &str, memory_type: &MemoryType) -> Result<(), Error> {
let memory_id = self.store.alloc_memory(memory_type)?;
self.exports.insert(name.to_owned(), ExternVal::Memory(memory_id));
Ok(())
}
pub fn with_table(&mut self, name: &str, table_type: &TableType) {
let table_id = self.store.alloc_table(table_type);
} }
} }

View File

@ -19,13 +19,9 @@ const DEFAULT_VALUE_STACK_LIMIT: usize = 16384;
const DEFAULT_FRAME_STACK_LIMIT: usize = 1024; const DEFAULT_FRAME_STACK_LIMIT: usize = 1024;
/// Execution context. /// Execution context.
#[derive(Clone)] pub struct ExecutionParams<'a, St: 'static> {
pub struct ExecutionParams<St: 'static> {
/// Arguments.
pub args: Vec<RuntimeValue>,
/// State that can be used by host functions, /// State that can be used by host functions,
pub state: St, pub state: &'a mut St,
} }
/// Export type. /// Export type.
@ -79,32 +75,13 @@ pub struct InternalFunction<'a> {
pub labels: &'a HashMap<usize, usize>, pub labels: &'a HashMap<usize, usize>,
} }
impl<St> ExecutionParams<St> { impl<'a, St> ExecutionParams<'a, St> {
/// Add argument. /// Add argument.
pub fn add_argument(mut self, arg: RuntimeValue) -> Self { pub fn add_argument(mut self, arg: RuntimeValue) -> Self {
self.args.push(arg);
self self
} }
} }
impl<St: Default> Default for ExecutionParams<St> {
fn default() -> Self {
ExecutionParams {
args: Vec::default(),
state: St::default(),
}
}
}
impl<'a, St: Default> From<Vec<RuntimeValue>> for ExecutionParams<St> {
fn from(args: Vec<RuntimeValue>) -> ExecutionParams<St> {
ExecutionParams {
args: args,
state: St::default(),
}
}
}
impl<'a> CallerContext<'a> { impl<'a> CallerContext<'a> {
/// Top most args /// Top most args
pub fn topmost(args: &'a mut StackWithLimit<RuntimeValue>) -> Self { pub fn topmost(args: &'a mut StackWithLimit<RuntimeValue>) -> Self {

View File

@ -26,7 +26,7 @@ impl ProgramInstance {
&mut self, &mut self,
name: &str, name: &str,
module: Module, module: Module,
start_exec_params: ExecutionParams<St>, state: &mut St,
) -> Result<ModuleId, Error> { ) -> Result<ModuleId, Error> {
let mut extern_vals = Vec::new(); let mut extern_vals = Vec::new();
for import_entry in module.import_section().map(|s| s.entries()).unwrap_or(&[]) { for import_entry in module.import_section().map(|s| s.entries()).unwrap_or(&[]) {
@ -37,7 +37,7 @@ impl ProgramInstance {
extern_vals.push(extern_val); extern_vals.push(extern_val);
} }
let module_id = self.store.instantiate_module(&module, &extern_vals, start_exec_params)?; let module_id = self.store.instantiate_module(&module, &extern_vals, state)?;
self.modules.insert(name.to_string(), module_id); self.modules.insert(name.to_string(), module_id);
Ok(module_id) Ok(module_id)

View File

@ -8,12 +8,11 @@ use std::collections::{HashMap, VecDeque};
use elements::{Opcode, BlockType, Local}; use elements::{Opcode, BlockType, Local};
use interpreter::Error; use interpreter::Error;
use interpreter::store::{Store, FuncId, ModuleId, FuncInstance}; use interpreter::store::{Store, FuncId, ModuleId, FuncInstance};
use interpreter::module::{CallerContext, FunctionSignature}; use interpreter::module::{CallerContext, FunctionSignature, ExecutionParams};
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,
}; };
use interpreter::variable::VariableInstance;
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX, BlockFrame, BlockFrameType}; use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX, BlockFrame, BlockFrameType};
use common::stack::StackWithLimit; use common::stack::StackWithLimit;
@ -81,12 +80,10 @@ impl<'store, St: 'static> Interpreter<'store, St> {
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 = function_context.function; let function_ref = function_context.function;
let function_return = { let function_return = {
let func_instance = function_ref.resolve(self.store).clone(); let func_body = function_ref.resolve(self.store).body();
match func_instance {
FuncInstance::Defined { body, .. } => {
let function_body = body;
match func_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);
@ -95,9 +92,9 @@ impl<'store, St: 'static> Interpreter<'store, St> {
self.do_run_function(&mut function_context, function_body.opcodes.elements(), &function_body.labels)? self.do_run_function(&mut function_context, function_body.opcodes.elements(), &function_body.labels)?
}, },
FuncInstance::Host { host_func, .. } => { None => {
let args: Vec<_> = function_context.locals.drain(..).collect(); let args: Vec<_> = function_context.locals.drain(..).collect();
let result = self.store.invoke_host(self.state, host_func, args)?; let result = self.store.invoke(function_ref, args, self.state)?;
RunResult::Return(result) RunResult::Return(result)
}, },
} }
@ -976,7 +973,7 @@ impl<'a> FunctionContext {
pub fn new<'store>(store: &'store Store, function: FuncId, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionSignature, args: Vec<RuntimeValue>) -> Self { pub fn new<'store>(store: &'store Store, function: FuncId, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionSignature, args: Vec<RuntimeValue>) -> Self {
let func_instance = function.resolve(store); let func_instance = function.resolve(store);
let module = match *func_instance { let module = match *func_instance {
FuncInstance::Defined { module, .. } => module, FuncInstance::Internal { module, .. } => module,
FuncInstance::Host { .. } => panic!("Host functions can't be called as internally defined functions; Thus FunctionContext can be created only with internally defined functions; qed"), FuncInstance::Host { .. } => panic!("Host functions can't be called as internally defined functions; Thus FunctionContext can be created only with internally defined functions; qed"),
}; };
FunctionContext { FunctionContext {
@ -995,7 +992,7 @@ impl<'a> FunctionContext {
let (function_locals, module, function_return_type) = { let (function_locals, module, function_return_type) = {
let func_instance = function.resolve(store); let func_instance = function.resolve(store);
let module = match *func_instance { let module = match *func_instance {
FuncInstance::Defined { module, .. } => module, FuncInstance::Internal { module, .. } => module,
FuncInstance::Host { .. } => panic!("Host functions can't be called as internally defined functions; Thus FunctionContext can be created only with internally defined functions; qed"), FuncInstance::Host { .. } => panic!("Host functions can't be called as internally defined functions; Thus FunctionContext can be created only with internally defined functions; qed"),
}; };
let function_type = func_instance.func_type().resolve(store); let function_type = func_instance.func_type().resolve(store);

View File

@ -120,27 +120,33 @@ pub enum ExternVal {
Global(GlobalId), Global(GlobalId),
} }
#[derive(Clone, Debug)]
pub enum FuncInstance { pub enum FuncInstance {
Defined { Internal {
func_type: TypeId, func_type: TypeId,
module: ModuleId, module: ModuleId,
body: Arc<FuncBody>, body: Arc<FuncBody>,
}, },
Host { Host {
func_type: TypeId, func_type: TypeId,
host_func: HostFuncId, host_func: Arc<AnyFunc>,
}, },
} }
impl FuncInstance { impl FuncInstance {
pub fn func_type(&self) -> TypeId { pub fn func_type(&self) -> TypeId {
match *self { match *self {
FuncInstance::Defined { func_type, .. } | FuncInstance::Host { func_type, .. } => { FuncInstance::Internal { func_type, .. } | FuncInstance::Host { func_type, .. } => {
func_type func_type
} }
} }
} }
pub fn body(&self) -> Option<Arc<FuncBody>> {
match *self {
FuncInstance::Internal { ref body, .. } => Some(Arc::clone(body)),
FuncInstance::Host { .. } => None,
}
}
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -194,7 +200,6 @@ pub struct Store {
// However, they can be referenced in several places, so it is handy to have it here. // However, they can be referenced in several places, so it is handy to have it here.
modules: Vec<ModuleInstance>, modules: Vec<ModuleInstance>,
types: Vec<FunctionType>, types: Vec<FunctionType>,
host_funcs: Vec<Box<AnyFunc>>,
} }
impl Store { impl Store {
@ -220,8 +225,8 @@ impl Store {
TypeId(type_id as u32) TypeId(type_id as u32)
} }
fn alloc_func(&mut self, module: ModuleId, func_type: TypeId, body: FuncBody) -> FuncId { pub fn alloc_func(&mut self, module: ModuleId, func_type: TypeId, body: FuncBody) -> FuncId {
let func = FuncInstance::Defined { let func = FuncInstance::Internal {
func_type, func_type,
module, module,
body: Arc::new(body), body: Arc::new(body),
@ -231,34 +236,31 @@ impl Store {
FuncId(func_id as u32) FuncId(func_id as u32)
} }
pub fn alloc_host_func(&mut self, func_type: TypeId, anyfunc: Box<AnyFunc>) -> FuncId { pub fn alloc_host_func(&mut self, func_type: TypeId, host_func: Arc<AnyFunc>) -> FuncId {
self.host_funcs.push(anyfunc);
let host_func_id = self.host_funcs.len() - 1;
let func = FuncInstance::Host { let func = FuncInstance::Host {
func_type, func_type,
host_func: HostFuncId(host_func_id as u32), host_func,
}; };
self.funcs.push(func); self.funcs.push(func);
let func_id = self.funcs.len() - 1; let func_id = self.funcs.len() - 1;
FuncId(func_id as u32) FuncId(func_id as u32)
} }
fn alloc_table(&mut self, table_type: &TableType) -> Result<TableId, Error> { pub fn alloc_table(&mut self, table_type: &TableType) -> Result<TableId, Error> {
let table = TableInstance::new(table_type)?; 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;
Ok(TableId(table_id as u32)) Ok(TableId(table_id as u32))
} }
fn alloc_memory(&mut self, mem_type: &MemoryType) -> Result<MemoryId, Error> { pub fn alloc_memory(&mut self, mem_type: &MemoryType) -> Result<MemoryId, Error> {
let mem = MemoryInstance::new(&mem_type)?; 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;
Ok(MemoryId(mem_id as u32)) Ok(MemoryId(mem_id as u32))
} }
fn alloc_global(&mut self, global_type: GlobalType, val: RuntimeValue) -> GlobalId { pub fn alloc_global(&mut self, global_type: GlobalType, val: RuntimeValue) -> GlobalId {
let global = GlobalInstance::new(val, global_type.is_mutable()); let global = GlobalInstance::new(val, global_type.is_mutable());
self.globals.push(global); self.globals.push(global);
let global_id = self.globals.len() - 1; let global_id = self.globals.len() - 1;
@ -376,7 +378,7 @@ impl Store {
&mut self, &mut self,
module: &Module, module: &Module,
extern_vals: &[ExternVal], extern_vals: &[ExternVal],
start_exec_params: ExecutionParams<St>, state: &mut St,
) -> Result<ModuleId, Error> { ) -> Result<ModuleId, Error> {
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.
@ -442,30 +444,40 @@ impl Store {
.get(start_fn_idx as usize) .get(start_fn_idx as usize)
.expect("Due to validation start function should exists") .expect("Due to validation start function should exists")
}; };
self.invoke(start_func, start_exec_params)?; self.invoke(start_func, vec![], state)?;
} }
Ok(module_id) Ok(module_id)
} }
fn invoke<St>(&mut self, func: FuncId, params: ExecutionParams<St>) -> Result<Option<RuntimeValue>, Error> { pub fn invoke<St: 'static>(&mut self, func: FuncId, args: Vec<RuntimeValue>, state: &mut St) -> Result<Option<RuntimeValue>, Error> {
let ExecutionParams { args, mut state } = params; enum InvokeKind {
let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT); Internal(FunctionContext),
let outer = CallerContext::topmost(&mut args); Host(Arc<AnyFunc>),
let inner = { }
let func_type = func.resolve(self).func_type().resolve(self);
let func_signature = FunctionSignature::Module(func_type);
let args = prepare_function_args(&func_signature, outer.value_stack)?;
FunctionContext::new(self, func, outer.value_stack_limit, outer.frame_stack_limit, &func_signature, args)
};
let mut interpreter = Interpreter::new(self, &mut state);
interpreter.run_function(inner)
}
pub fn invoke_host<St: 'static>(&mut self, state: &mut St, host_func: HostFuncId, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> { let result = match *func.resolve(self) {
let host_func_instance = self.host_funcs.get(host_func.0 as usize).expect("ID should be always valid"); FuncInstance::Internal { func_type, .. } => {
host_func_instance.call_as_any(state as &mut Any, &args); let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT);
panic!() let outer = CallerContext::topmost(&mut args);
let func_signature = FunctionSignature::Module(func_type.resolve(self));
let args = prepare_function_args(&func_signature, outer.value_stack)?;
let context = FunctionContext::new(self, func, outer.value_stack_limit, outer.frame_stack_limit, &func_signature, args);
InvokeKind::Internal(context)
},
FuncInstance::Host { ref host_func, .. } => InvokeKind::Host(Arc::clone(host_func)),
};
match result {
InvokeKind::Internal(ctx) => {
let mut interpreter = Interpreter::new(self, state);
interpreter.run_function(ctx)
},
InvokeKind::Host(host_func) => {
// host_func.call_as_any();
panic!()
},
}
} }
pub fn write_global(&mut self, global: GlobalId, val: RuntimeValue) -> Result<(), Error> { pub fn write_global(&mut self, global: GlobalId, val: RuntimeValue) -> Result<(), Error> {