Introduce ValueStack

Also, hide FunctionContext and remove some stale code
This commit is contained in:
Sergey Pepyakin 2018-01-31 18:02:36 +03:00
parent e132b0113d
commit 6147ad0a2e
3 changed files with 108 additions and 73 deletions

View File

@ -28,13 +28,6 @@ pub struct StackWithLimit<T> where T: Clone {
}
impl<T> StackWithLimit<T> where T: Clone {
pub fn with_data<D: IntoIterator<Item=T>>(data: D, limit: usize) -> Self {
StackWithLimit {
values: data.into_iter().collect(),
limit: limit
}
}
pub fn with_limit(limit: usize) -> Self {
StackWithLimit {
values: VecDeque::new(),

View File

@ -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<Option<RuntimeValue>, 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()),
}
}
}

View File

@ -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<RuntimeValue>,
/// Values stack.
pub value_stack: StackWithLimit<RuntimeValue>,
/// Blocks frames stack.
pub frame_stack: StackWithLimit<BlockFrame>,
/// 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<Option<RuntimeValue>, Error> {
pub fn start_execution(&mut self, func: &FuncRef, args: &[RuntimeValue]) -> Result<Option<RuntimeValue>, 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<Option<RuntimeValue>, 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<RuntimeValue>,
/// Values stack.
pub value_stack: ValueStack,
/// Blocks frames stack.
pub frame_stack: StackWithLimit<BlockFrame>,
/// 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<RuntimeValue>) -> 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<RuntimeValue> {
pub fn value_stack(&self) -> &ValueStack {
&self.value_stack
}
pub fn value_stack_mut(&mut self) -> &mut StackWithLimit<RuntimeValue> {
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<u32, Trap> {
}
}
pub fn prepare_function_args(signature: &Signature, caller_stack: &mut StackWithLimit<RuntimeValue>) -> Result<Vec<RuntimeValue>, 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<Vec<RuntimeValue>, Error> {
let mut args = signature.params().iter().cloned().rev().map(|_| {
caller_stack.pop()
}).collect::<Result<Vec<RuntimeValue>, _>>()?;
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::<Result<Vec<_>, _>>()?;
args.reverse();
Ok(args)
Ok(())
}
impl StackWithLimit<RuntimeValue> {
struct ValueStack {
stack_with_limit: StackWithLimit<RuntimeValue>,
}
impl ValueStack {
fn with_limit(limit: usize) -> ValueStack {
ValueStack {
stack_with_limit: StackWithLimit::with_limit(limit),
}
}
fn pop_as<T>(&mut self) -> Result<T, Error>
where
RuntimeValue: TryInto<T, Error>,
{
let value = self.pop()?;
let value = self.stack_with_limit.pop()?;
TryInto::try_into(value)
}
@ -1220,9 +1261,33 @@ impl StackWithLimit<RuntimeValue> {
}
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<RuntimeValue, Error> {
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()))
}
}