Add functionality to resume execution in Interpreter level

This commit is contained in:
Wei Tang 2018-07-06 07:36:52 +08:00
parent fa556a2af1
commit dcf926fd15
1 changed files with 63 additions and 14 deletions

View File

@ -37,16 +37,9 @@ pub enum InstructionOutcome {
Return(isa::DropKeep), Return(isa::DropKeep),
} }
/// Function run result. #[derive(PartialEq, Eq)]
enum RunResult {
/// Function has returned.
Return,
/// Function is calling other function.
NestedCall(FuncRef),
}
/// Function execution state, related to pause and resume. /// Function execution state, related to pause and resume.
enum RunState { pub enum InterpreterState {
/// The interpreter has been created, but has not been executed. /// The interpreter has been created, but has not been executed.
Initialized, Initialized,
/// The interpreter has started execution, and cannot be called again if it exits normally, or no Host traps happened. /// The interpreter has started execution, and cannot be called again if it exits normally, or no Host traps happened.
@ -56,13 +49,30 @@ enum RunState {
Resumable(Option<ValueType>), Resumable(Option<ValueType>),
} }
impl InterpreterState {
pub fn is_resumable(&self) -> bool {
match self {
&InterpreterState::Resumable(_) => true,
_ => false,
}
}
}
/// Function run result.
enum RunResult {
/// Function has returned.
Return,
/// Function is calling other function.
NestedCall(FuncRef),
}
/// Function interpreter. /// Function interpreter.
pub struct Interpreter<'a, E: Externals + 'a> { pub struct Interpreter<'a, E: Externals + 'a> {
externals: &'a mut E, externals: &'a mut E,
value_stack: ValueStack, value_stack: ValueStack,
call_stack: Vec<FunctionContext>, call_stack: Vec<FunctionContext>,
return_type: Option<ValueType>, return_type: Option<ValueType>,
state: RunState, state: InterpreterState,
} }
impl<'a, E: Externals> Interpreter<'a, E> { impl<'a, E: Externals> Interpreter<'a, E> {
@ -89,12 +99,49 @@ impl<'a, E: Externals> Interpreter<'a, E> {
value_stack, value_stack,
call_stack, call_stack,
return_type, return_type,
state: RunState::Initialized, state: InterpreterState::Initialized,
}) })
} }
pub fn start_execution(&mut self) -> Result<Option<RuntimeValue>, Trap> { pub fn start_execution(&mut self) -> Result<Option<RuntimeValue>, Trap> {
self.state = RunState::Started; // Ensure that the VM has not been executed.
assert!(self.state == InterpreterState::Initialized);
self.state = InterpreterState::Started;
self.run_interpreter_loop()?;
let opt_return_value = self.return_type.map(|_vt| {
self.value_stack.pop()
});
// Ensure that stack is empty after the execution.
assert!(self.value_stack.len() == 0);
Ok(opt_return_value)
}
pub fn resume_execution(&mut self, return_val: Option<RuntimeValue>) -> Result<Option<RuntimeValue>, Trap> {
use std::mem::swap;
// Ensure that the VM is resumable.
assert!(self.state.is_resumable());
let mut resumable_state = InterpreterState::Started;
swap(&mut self.state, &mut resumable_state);
let expected_ty = match resumable_state {
InterpreterState::Resumable(ty) => ty,
_ => unreachable!("Resumable arm is checked above is_resumable; qed"),
};
let value_ty = return_val.as_ref().map(|val| val.value_type());
if value_ty != expected_ty {
return Err(TrapKind::UnexpectedSignature.into());
}
if let Some(return_val) = return_val {
self.value_stack.push(return_val).map_err(Trap::new)?;
}
self.run_interpreter_loop()?; self.run_interpreter_loop()?;
let opt_return_value = self.return_type.map(|_vt| { let opt_return_value = self.return_type.map(|_vt| {
@ -151,11 +198,14 @@ impl<'a, E: Externals> Interpreter<'a, E> {
}, },
FuncInstanceInternal::Host { ref signature, .. } => { FuncInstanceInternal::Host { ref signature, .. } => {
let args = prepare_function_args(signature, &mut self.value_stack); let args = prepare_function_args(signature, &mut self.value_stack);
// We push the function context first. If the VM is not resumable, it does no harm. If it is, we then save the context here.
self.call_stack.push(function_context);
let return_val = match FuncInstance::invoke(&nested_func, &args, self.externals) { let return_val = match FuncInstance::invoke(&nested_func, &args, self.externals) {
Ok(val) => val, Ok(val) => val,
Err(trap) => { Err(trap) => {
if trap.kind().is_host() { if trap.kind().is_host() {
self.state = RunState::Resumable(nested_func.signature().return_type()); self.state = InterpreterState::Resumable(nested_func.signature().return_type());
} }
return Err(trap); return Err(trap);
}, },
@ -171,7 +221,6 @@ impl<'a, E: Externals> Interpreter<'a, E> {
if let Some(return_val) = return_val { if let Some(return_val) = return_val {
self.value_stack.push(return_val).map_err(Trap::new)?; self.value_stack.push(return_val).map_err(Trap::new)?;
} }
self.call_stack.push(function_context);
} }
} }
}, },