diff --git a/src/common/stack.rs b/src/common/stack.rs index b59e77a..d4d1bf3 100644 --- a/src/common/stack.rs +++ b/src/common/stack.rs @@ -28,13 +28,6 @@ pub struct StackWithLimit where T: Clone { } impl StackWithLimit where T: Clone { - pub fn with_data>(data: D, limit: usize) -> Self { - StackWithLimit { - values: data.into_iter().collect(), - limit: limit - } - } - pub fn with_limit(limit: usize) -> Self { StackWithLimit { values: VecDeque::new(), diff --git a/src/func.rs b/src/func.rs index bd1649a..f04be05 100644 --- a/src/func.rs +++ b/src/func.rs @@ -4,11 +4,9 @@ use std::collections::HashMap; use parity_wasm::elements::{Local, Opcodes}; use {Error, Signature}; use host::Externals; -use runner::{prepare_function_args, FunctionContext, Interpreter}; +use runner::{check_function_args, Interpreter}; use value::RuntimeValue; use module::ModuleInstance; -use common::stack::StackWithLimit; -use common::{DEFAULT_FRAME_STACK_LIMIT, DEFAULT_VALUE_STACK_LIMIT}; /// Reference to a function (See [`FuncInstance`] for details). /// @@ -135,36 +133,15 @@ impl FuncInstance { args: &[RuntimeValue], externals: &mut E, ) -> Result, Error> { - enum InvokeKind<'a> { - Internal(FunctionContext), - Host(usize, &'a [RuntimeValue]), - } - - let result = match *func.as_internal() { + match *func.as_internal() { FuncInstanceInternal::Internal { ref signature, .. } => { - let mut stack = - StackWithLimit::with_data(args.into_iter().cloned(), DEFAULT_VALUE_STACK_LIMIT); - let args = prepare_function_args(signature, &mut stack)?; - let context = FunctionContext::new( - func.clone(), - DEFAULT_VALUE_STACK_LIMIT, - DEFAULT_FRAME_STACK_LIMIT, - signature, - args, - ); - InvokeKind::Internal(context) + check_function_args(signature, &args)?; + let mut interpreter = Interpreter::new(externals); + interpreter.start_execution(func, args) } FuncInstanceInternal::Host { ref host_func_index, .. } => { - InvokeKind::Host(*host_func_index, &*args) + externals.invoke_index(*host_func_index, args.into()) } - }; - - match result { - InvokeKind::Internal(ctx) => { - let mut interpreter = Interpreter::new(externals); - interpreter.run_function(ctx) - } - InvokeKind::Host(host_func, args) => externals.invoke_index(host_func, args.into()), } } } diff --git a/src/runner.rs b/src/runner.rs index a715254..df66c26 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -15,31 +15,13 @@ use value::{ use host::Externals; use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX, BlockFrame, BlockFrameType}; use common::stack::StackWithLimit; +use common::{DEFAULT_FRAME_STACK_LIMIT, DEFAULT_VALUE_STACK_LIMIT}; /// Function interpreter. pub struct Interpreter<'a, E: Externals + 'a> { externals: &'a mut E, } -/// Function execution context. -pub struct FunctionContext { - /// Is context initialized. - pub is_initialized: bool, - /// Internal function reference. - pub function: FuncRef, - pub module: ModuleRef, - /// Function return type. - pub return_type: BlockType, - /// Local variables. - pub locals: Vec, - /// Values stack. - pub value_stack: StackWithLimit, - /// Blocks frames stack. - pub frame_stack: StackWithLimit, - /// Current instruction position. - pub position: usize, -} - /// Interpreter action to execute after executing instruction. pub enum InstructionOutcome { /// Continue with next instruction. @@ -69,7 +51,18 @@ impl<'a, E: Externals> Interpreter<'a, E> { } } - pub fn run_function(&mut self, function_context: FunctionContext) -> Result, Error> { + pub fn start_execution(&mut self, func: &FuncRef, args: &[RuntimeValue]) -> Result, Error> { + let context = FunctionContext::new( + func.clone(), + DEFAULT_VALUE_STACK_LIMIT, + DEFAULT_FRAME_STACK_LIMIT, + func.signature(), + args.into_iter().cloned().collect(), + ); + self.run_function(context) + } + + fn run_function(&mut self, function_context: FunctionContext) -> Result, Error> { let mut function_stack = VecDeque::new(); function_stack.push_back(function_context); @@ -1038,6 +1031,25 @@ impl<'a, E: Externals> Interpreter<'a, E> { } } +/// Function execution context. +struct FunctionContext { + /// Is context initialized. + pub is_initialized: bool, + /// Internal function reference. + pub function: FuncRef, + pub module: ModuleRef, + /// Function return type. + pub return_type: BlockType, + /// Local variables. + pub locals: Vec, + /// Values stack. + pub value_stack: ValueStack, + /// Blocks frames stack. + pub frame_stack: StackWithLimit, + /// Current instruction position. + pub position: usize, +} + impl FunctionContext { pub fn new(function: FuncRef, value_stack_limit: usize, frame_stack_limit: usize, signature: &Signature, args: Vec) -> Self { let module = match *function.as_internal() { @@ -1049,7 +1061,7 @@ impl FunctionContext { function: function, module: ModuleRef(module), return_type: signature.return_type().map(|vt| BlockType::Value(vt.into_elements())).unwrap_or(BlockType::NoResult), - value_stack: StackWithLimit::with_limit(value_stack_limit), + value_stack: ValueStack::with_limit(value_stack_limit), frame_stack: StackWithLimit::with_limit(frame_stack_limit), locals: args, position: 0, @@ -1073,7 +1085,7 @@ impl FunctionContext { function: function, module: ModuleRef(module), return_type: function_return_type, - value_stack: StackWithLimit::with_limit(self.value_stack.limit() - self.value_stack.len()), + value_stack: ValueStack::with_limit(self.value_stack.limit() - self.value_stack.len()), frame_stack: StackWithLimit::with_limit(self.frame_stack.limit() - self.frame_stack.len()), locals: function_locals, position: 0, @@ -1110,11 +1122,11 @@ impl FunctionContext { .expect("Due to validation local should exists") } - pub fn value_stack(&self) -> &StackWithLimit { + pub fn value_stack(&self) -> &ValueStack { &self.value_stack } - pub fn value_stack_mut(&mut self) -> &mut StackWithLimit { + pub fn value_stack_mut(&mut self) -> &mut ValueStack { &mut self.value_stack } @@ -1164,7 +1176,7 @@ impl FunctionContext { BlockType::Value(_) if frame.frame_type != BlockFrameType::Loop || !is_branch => Some(self.value_stack.pop()?), _ => None, }; - self.value_stack.resize(frame.value_stack_len, RuntimeValue::I32(0)); + self.value_stack.resize(frame.value_stack_len); self.position = if is_branch { frame.branch_position } else { frame.end_position }; if let Some(frame_value) = frame_value { self.value_stack.push(frame_value)?; @@ -1187,26 +1199,55 @@ fn effective_address(address: u32, offset: u32) -> Result { } } -pub fn prepare_function_args(signature: &Signature, caller_stack: &mut StackWithLimit) -> Result, Error> { - let mut args = signature.params().iter().cloned().rev().map(|expected_type| { - let param_value = caller_stack.pop()?; +fn prepare_function_args(signature: &Signature, caller_stack: &mut ValueStack) -> Result, Error> { + let mut args = signature.params().iter().cloned().rev().map(|_| { + caller_stack.pop() + }).collect::, _>>()?; + args.reverse(); + check_function_args(signature, &args)?; + Ok(args) +} + +pub fn check_function_args(signature: &Signature, args: &[RuntimeValue]) -> Result<(), Error> { + if signature.params().len() != args.len() { + return Err( + Error::Function( + format!( + "not enough arguments, given {} but expected: {}", + args.len(), + signature.params().len(), + ) + ) + ); + } + + signature.params().iter().cloned().zip(args).map(|(expected_type, param_value)| { let actual_type = param_value.value_type(); if actual_type != expected_type { return Err(Error::Function(format!("invalid parameter type {:?} when expected {:?}", actual_type, expected_type))); } - - Ok(param_value) + Ok(()) }).collect::, _>>()?; - args.reverse(); - Ok(args) + + Ok(()) } -impl StackWithLimit { +struct ValueStack { + stack_with_limit: StackWithLimit, +} + +impl ValueStack { + fn with_limit(limit: usize) -> ValueStack { + ValueStack { + stack_with_limit: StackWithLimit::with_limit(limit), + } + } + fn pop_as(&mut self) -> Result where RuntimeValue: TryInto, { - let value = self.pop()?; + let value = self.stack_with_limit.pop()?; TryInto::try_into(value) } @@ -1220,9 +1261,33 @@ impl StackWithLimit { } fn pop_triple(&mut self) -> Result<(RuntimeValue, RuntimeValue, RuntimeValue), Error> { - let right = self.pop()?; - let mid = self.pop()?; - let left = self.pop()?; + let right = self.stack_with_limit.pop()?; + let mid = self.stack_with_limit.pop()?; + let left = self.stack_with_limit.pop()?; Ok((left, mid, right)) } + + fn pop(&mut self) -> Result { + self.stack_with_limit.pop().map_err(|e| Error::Stack(e.to_string())) + } + + fn push(&mut self, value: RuntimeValue) -> Result<(), Error> { + self.stack_with_limit.push(value).map_err(|e| Error::Stack(e.to_string())) + } + + fn resize(&mut self, new_len: usize) { + self.stack_with_limit.resize(new_len, RuntimeValue::I32(0)); + } + + fn len(&self) -> usize { + self.stack_with_limit.len() + } + + fn limit(&self) -> usize { + self.stack_with_limit.limit() + } + + fn top(&self) -> Result<&RuntimeValue, Error> { + self.stack_with_limit.top().map_err(|e| Error::Stack(e.to_string())) + } }