diff --git a/src/interpreter/host.rs b/src/interpreter/host.rs index 868aaff..cd711ad 100644 --- a/src/interpreter/host.rs +++ b/src/interpreter/host.rs @@ -1,7 +1,8 @@ use std::any::Any; +use std::sync::Arc; use std::marker::PhantomData; use std::collections::HashMap; -use elements::{FunctionType, ValueType}; +use elements::{FunctionType, ValueType, GlobalType, MemoryType, TableType}; use interpreter::store::{Store, ExternVal}; use interpreter::value::RuntimeValue; 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, Error> + 'static, Ret: AsReturn + 'static, P1: FromArg + 'static, @@ -34,12 +35,25 @@ impl<'a, St: 'static> HostModuleBuilder<'a, St> { let func_type = Func1::::derive_func_type(); let type_id = self.store.alloc_func_type(func_type); - let anyfunc = Box::new(f.into()) as Box; + let anyfunc = Arc::new(f.into()) as Arc; 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); } } diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index f5ecfbf..22a6570 100644 --- a/src/interpreter/module.rs +++ b/src/interpreter/module.rs @@ -19,13 +19,9 @@ const DEFAULT_VALUE_STACK_LIMIT: usize = 16384; const DEFAULT_FRAME_STACK_LIMIT: usize = 1024; /// Execution context. -#[derive(Clone)] -pub struct ExecutionParams { - /// Arguments. - pub args: Vec, - +pub struct ExecutionParams<'a, St: 'static> { /// State that can be used by host functions, - pub state: St, + pub state: &'a mut St, } /// Export type. @@ -79,32 +75,13 @@ pub struct InternalFunction<'a> { pub labels: &'a HashMap, } -impl ExecutionParams { +impl<'a, St> ExecutionParams<'a, St> { /// Add argument. pub fn add_argument(mut self, arg: RuntimeValue) -> Self { - self.args.push(arg); self } } -impl Default for ExecutionParams { - fn default() -> Self { - ExecutionParams { - args: Vec::default(), - state: St::default(), - } - } -} - -impl<'a, St: Default> From> for ExecutionParams { - fn from(args: Vec) -> ExecutionParams { - ExecutionParams { - args: args, - state: St::default(), - } - } -} - impl<'a> CallerContext<'a> { /// Top most args pub fn topmost(args: &'a mut StackWithLimit) -> Self { diff --git a/src/interpreter/program.rs b/src/interpreter/program.rs index 153c757..bcb4066 100644 --- a/src/interpreter/program.rs +++ b/src/interpreter/program.rs @@ -26,7 +26,7 @@ impl ProgramInstance { &mut self, name: &str, module: Module, - start_exec_params: ExecutionParams, + state: &mut St, ) -> Result { let mut extern_vals = Vec::new(); for import_entry in module.import_section().map(|s| s.entries()).unwrap_or(&[]) { @@ -37,7 +37,7 @@ impl ProgramInstance { 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); Ok(module_id) diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index fe477ec..3640fdd 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -8,12 +8,11 @@ use std::collections::{HashMap, VecDeque}; use elements::{Opcode, BlockType, Local}; use interpreter::Error; use interpreter::store::{Store, FuncId, ModuleId, FuncInstance}; -use interpreter::module::{CallerContext, FunctionSignature}; +use interpreter::module::{CallerContext, FunctionSignature, ExecutionParams}; use interpreter::value::{ RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto, ArithmeticOps, Integer, Float, LittleEndianConvert, TransmuteInto, }; -use interpreter::variable::VariableInstance; use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX, BlockFrame, BlockFrameType}; 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 function_ref = function_context.function; let function_return = { - let func_instance = function_ref.resolve(self.store).clone(); - - match func_instance { - FuncInstance::Defined { body, .. } => { - let function_body = body; + let func_body = function_ref.resolve(self.store).body(); + match func_body { + Some(function_body) => { if !function_context.is_initialized() { let return_type = function_context.return_type; 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)? }, - FuncInstance::Host { host_func, .. } => { + None => { 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) }, } @@ -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) -> Self { let func_instance = function.resolve(store); 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"), }; FunctionContext { @@ -995,7 +992,7 @@ impl<'a> FunctionContext { let (function_locals, module, function_return_type) = { let func_instance = function.resolve(store); 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"), }; let function_type = func_instance.func_type().resolve(store); diff --git a/src/interpreter/store.rs b/src/interpreter/store.rs index f06a54f..216c0c3 100644 --- a/src/interpreter/store.rs +++ b/src/interpreter/store.rs @@ -120,27 +120,33 @@ pub enum ExternVal { Global(GlobalId), } -#[derive(Clone, Debug)] pub enum FuncInstance { - Defined { + Internal { func_type: TypeId, module: ModuleId, body: Arc, }, Host { func_type: TypeId, - host_func: HostFuncId, + host_func: Arc, }, } impl FuncInstance { pub fn func_type(&self) -> TypeId { match *self { - FuncInstance::Defined { func_type, .. } | FuncInstance::Host { func_type, .. } => { + FuncInstance::Internal { func_type, .. } | FuncInstance::Host { func_type, .. } => { func_type } } } + + pub fn body(&self) -> Option> { + match *self { + FuncInstance::Internal { ref body, .. } => Some(Arc::clone(body)), + FuncInstance::Host { .. } => None, + } + } } #[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. modules: Vec, types: Vec, - host_funcs: Vec>, } impl Store { @@ -220,8 +225,8 @@ impl Store { TypeId(type_id as u32) } - fn alloc_func(&mut self, module: ModuleId, func_type: TypeId, body: FuncBody) -> FuncId { - let func = FuncInstance::Defined { + pub fn alloc_func(&mut self, module: ModuleId, func_type: TypeId, body: FuncBody) -> FuncId { + let func = FuncInstance::Internal { func_type, module, body: Arc::new(body), @@ -231,34 +236,31 @@ impl Store { FuncId(func_id as u32) } - pub fn alloc_host_func(&mut self, func_type: TypeId, anyfunc: Box) -> FuncId { - self.host_funcs.push(anyfunc); - let host_func_id = self.host_funcs.len() - 1; - + pub fn alloc_host_func(&mut self, func_type: TypeId, host_func: Arc) -> FuncId { let func = FuncInstance::Host { func_type, - host_func: HostFuncId(host_func_id as u32), + host_func, }; self.funcs.push(func); let func_id = self.funcs.len() - 1; FuncId(func_id as u32) } - fn alloc_table(&mut self, table_type: &TableType) -> Result { + pub fn alloc_table(&mut self, table_type: &TableType) -> Result { let table = TableInstance::new(table_type)?; self.tables.push(table); let table_id = self.tables.len() - 1; Ok(TableId(table_id as u32)) } - fn alloc_memory(&mut self, mem_type: &MemoryType) -> Result { + pub fn alloc_memory(&mut self, mem_type: &MemoryType) -> Result { let mem = MemoryInstance::new(&mem_type)?; self.memories.push(mem); let mem_id = self.memories.len() - 1; 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()); self.globals.push(global); let global_id = self.globals.len() - 1; @@ -376,7 +378,7 @@ impl Store { &mut self, module: &Module, extern_vals: &[ExternVal], - start_exec_params: ExecutionParams, + state: &mut St, ) -> Result { let mut instance = ModuleInstance::new(); // Reserve the index of the module, but not yet push the module. @@ -442,30 +444,40 @@ impl Store { .get(start_fn_idx as usize) .expect("Due to validation start function should exists") }; - self.invoke(start_func, start_exec_params)?; + self.invoke(start_func, vec![], state)?; } Ok(module_id) } - fn invoke(&mut self, func: FuncId, params: ExecutionParams) -> Result, Error> { - let ExecutionParams { args, mut state } = params; - let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT); - let outer = CallerContext::topmost(&mut args); - 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(&mut self, func: FuncId, args: Vec, state: &mut St) -> Result, Error> { + enum InvokeKind { + Internal(FunctionContext), + Host(Arc), + } - pub fn invoke_host(&mut self, state: &mut St, host_func: HostFuncId, args: Vec) -> Result, Error> { - let host_func_instance = self.host_funcs.get(host_func.0 as usize).expect("ID should be always valid"); - host_func_instance.call_as_any(state as &mut Any, &args); - panic!() + let result = match *func.resolve(self) { + FuncInstance::Internal { func_type, .. } => { + let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT); + 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> {