Refactor host

This commit is contained in:
Sergey Pepyakin
2017-12-18 15:18:53 +03:00
parent 848389ed88
commit 0e89639fe6
5 changed files with 83 additions and 77 deletions

View File

@ -4,8 +4,9 @@ use std::env;
use std::fmt; use std::fmt;
use std::rc::Rc; use std::rc::Rc;
use parity_wasm::elements::Module; use parity_wasm::elements::Module;
use parity_wasm::interpreter::{Error as InterpreterError, HostModule, HostModuleBuilder, use parity_wasm::interpreter::{
ModuleInstance, UserError}; Error as InterpreterError, HostModule, HostModuleBuilder,
ModuleInstance, UserError};
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -157,16 +158,16 @@ fn env_host_module<'a>() -> HostModule<Runtime<'a>> {
let mut builder = HostModuleBuilder::<Runtime>::new(); let mut builder = HostModuleBuilder::<Runtime>::new();
builder.with_func1( builder.with_func1(
"set", "set",
|state: &Runtime, idx: i32| -> Result<Option<()>, InterpreterError> { |state: &Runtime, idx: i32| -> Result<(), InterpreterError> {
state.game.set(idx, state.player)?; state.game.set(idx, state.player)?;
Ok(None) Ok(())
}, },
); );
builder.with_func1( builder.with_func1(
"get", "get",
|state: &Runtime, idx: i32| -> Result<Option<i32>, InterpreterError> { |state: &Runtime, idx: i32| -> Result<i32, InterpreterError> {
let val: i32 = tictactoe::Player::into_i32(state.game.get(idx).unwrap()); let val: i32 = tictactoe::Player::into_i32(state.game.get(idx).unwrap());
Ok(Some(val)) Ok(val)
}, },
); );
builder.build() builder.build()

View File

@ -7,7 +7,7 @@ use interpreter::func::FuncInstance;
use interpreter::global::GlobalInstance; use interpreter::global::GlobalInstance;
use interpreter::memory::MemoryInstance; use interpreter::memory::MemoryInstance;
use interpreter::table::TableInstance; use interpreter::table::TableInstance;
use interpreter::value::RuntimeValue; use interpreter::value::{RuntimeValue, TryInto};
use interpreter::Error; use interpreter::Error;
use interpreter::ImportResolver; use interpreter::ImportResolver;
@ -25,8 +25,8 @@ impl<St> HostModuleBuilder<St> {
} }
pub fn with_func0< pub fn with_func0<
Cl: Fn(&St) -> Result<Option<Ret>, Error> + 'static, Cl: Fn(&St) -> Result<Ret, Error> + 'static,
Ret: AsReturnVal + 'static, Ret: IntoReturnVal + 'static,
N: Into<String>, N: Into<String>,
>( >(
&mut self, &mut self,
@ -35,8 +35,8 @@ impl<St> HostModuleBuilder<St> {
) { ) {
let func_type = FunctionType::new(vec![], Ret::value_type()); let func_type = FunctionType::new(vec![], Ret::value_type());
let host_func = Rc::new(move |state: &St, _args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> { let host_func = Rc::new(move |state: &St, _args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> {
let result = f(state); let result = f(state)?.into_return_val();
result.map(|r| r.and_then(|r| r.as_return_val())) Ok(result)
}); });
let func = FuncInstance::alloc_host(Rc::new(func_type), host_func); let func = FuncInstance::alloc_host(Rc::new(func_type), host_func);
@ -44,8 +44,8 @@ impl<St> HostModuleBuilder<St> {
} }
pub fn with_func1< pub fn with_func1<
Cl: Fn(&St, P1) -> Result<Option<Ret>, Error> + 'static, Cl: Fn(&St, P1) -> Result<Ret, Error> + 'static,
Ret: AsReturnVal + 'static, Ret: IntoReturnVal + 'static,
P1: FromArg + 'static, P1: FromArg + 'static,
N: Into<String>, N: Into<String>,
>( >(
@ -56,8 +56,8 @@ impl<St> HostModuleBuilder<St> {
let func_type = FunctionType::new(vec![P1::value_type()], Ret::value_type()); let func_type = FunctionType::new(vec![P1::value_type()], Ret::value_type());
let host_func = Rc::new(move |state: &St, args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> { let host_func = Rc::new(move |state: &St, args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> {
let arg0 = P1::from_arg(&args[0]); let arg0 = P1::from_arg(&args[0]);
let result = f(state, arg0); let result = f(state, arg0)?.into_return_val();
result.map(|r| r.and_then(|r| r.as_return_val())) Ok(result)
}); });
let func = FuncInstance::alloc_host(Rc::new(func_type), host_func); let func = FuncInstance::alloc_host(Rc::new(func_type), host_func);
@ -65,8 +65,8 @@ impl<St> HostModuleBuilder<St> {
} }
pub fn with_func2< pub fn with_func2<
Cl: Fn(&St, P1, P2) -> Result<Option<Ret>, Error> + 'static, Cl: Fn(&St, P1, P2) -> Result<Ret, Error> + 'static,
Ret: AsReturnVal + 'static, Ret: IntoReturnVal + 'static,
P1: FromArg + 'static, P1: FromArg + 'static,
P2: FromArg + 'static, P2: FromArg + 'static,
N: Into<String>, N: Into<String>,
@ -79,8 +79,8 @@ impl<St> HostModuleBuilder<St> {
let host_func = Rc::new(move |state: &St, args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> { let host_func = Rc::new(move |state: &St, args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> {
let p1 = P1::from_arg(&args[0]); let p1 = P1::from_arg(&args[0]);
let p2 = P2::from_arg(&args[1]); let p2 = P2::from_arg(&args[1]);
let result = f(state, p1, p2); let result = f(state, p1, p2)?.into_return_val();
result.map(|r| r.and_then(|r| r.as_return_val())) Ok(result)
}); });
let func = FuncInstance::alloc_host(Rc::new(func_type), host_func); let func = FuncInstance::alloc_host(Rc::new(func_type), host_func);
@ -177,49 +177,66 @@ impl<St> ImportResolver<St> for HostModule<St> {
} }
} }
pub trait AnyFunc<St> { pub trait FromArg where Self: Sized {
fn call_as_any(
&self,
state: &St,
args: &[RuntimeValue],
) -> Result<Option<RuntimeValue>, Error>;
}
pub trait FromArg {
fn from_arg(arg: &RuntimeValue) -> Self; fn from_arg(arg: &RuntimeValue) -> Self;
fn value_type() -> ValueType; fn value_type() -> ValueType;
} }
impl FromArg for i32 { macro_rules! impl_from_arg {
fn from_arg(arg: &RuntimeValue) -> Self { ($ty: ident, $val_ty: ident) => {
match arg { impl FromArg for $ty {
&RuntimeValue::I32(v) => v, fn from_arg(arg: &RuntimeValue) -> Self {
unexpected => panic!("Expected I32, got {:?}", unexpected), arg
} .try_into()
} .expect(
concat!("Due to validation, arg expected to be ", stringify!($val_ty))
)
}
fn value_type() -> ValueType { fn value_type() -> ValueType {
ValueType::I32 use self::ValueType::*;
$val_ty
}
}
} }
} }
pub trait AsReturnVal { impl_from_arg!(i32, I32);
fn as_return_val(self) -> Option<RuntimeValue>; impl_from_arg!(u32, I32);
impl_from_arg!(i64, I64);
impl_from_arg!(u64, I64);
impl_from_arg!(f32, F32);
impl_from_arg!(f64, F64);
pub trait IntoReturnVal {
fn into_return_val(self) -> Option<RuntimeValue>;
fn value_type() -> Option<ValueType>; fn value_type() -> Option<ValueType>;
} }
impl AsReturnVal for i32 { macro_rules! impl_into_return_val {
fn as_return_val(self) -> Option<RuntimeValue> { ($ty: ident, $val_ty: ident) => {
Some(self.into()) impl IntoReturnVal for $ty {
} fn into_return_val(self) -> Option<RuntimeValue> {
Some(self.into())
}
fn value_type() -> Option<ValueType> { fn value_type() -> Option<ValueType> {
Some(ValueType::I32) use self::ValueType::*;
Some($val_ty)
}
}
} }
} }
impl AsReturnVal for () { impl_into_return_val!(i32, I32);
fn as_return_val(self) -> Option<RuntimeValue> { impl_into_return_val!(u32, I32);
impl_into_return_val!(i64, I64);
impl_into_return_val!(u64, I64);
impl_into_return_val!(f32, F32);
impl_into_return_val!(f64, F64);
impl IntoReturnVal for () {
fn into_return_val(self) -> Option<RuntimeValue> {
None None
} }
@ -227,27 +244,3 @@ impl AsReturnVal for () {
None None
} }
} }
impl<St, Ret: AsReturnVal> AnyFunc<St> for Fn(&St) -> Result<Option<Ret>, Error> {
fn call_as_any(
&self,
state: &St,
_args: &[RuntimeValue],
) -> Result<Option<RuntimeValue>, Error> {
let result = self(state);
result.map(|r| r.and_then(|r| r.as_return_val()))
}
}
impl<St, Ret: AsReturnVal, P1: FromArg, P2: FromArg> AnyFunc<St> for Fn(&St, P1, P2) -> Result<Option<Ret>, Error> {
fn call_as_any(
&self,
state: &St,
args: &[RuntimeValue],
) -> Result<Option<RuntimeValue>, Error> {
let p1 = P1::from_arg(&args[0]);
let p2 = P2::from_arg(&args[1]);
let result = self(state, p1, p2);
result.map(|r| r.and_then(|r| r.as_return_val()))
}
}

View File

@ -151,7 +151,7 @@ pub use self::memory::MemoryInstance;
pub use self::table::TableInstance; pub use self::table::TableInstance;
pub use self::program::ProgramInstance; pub use self::program::ProgramInstance;
pub use self::value::RuntimeValue; pub use self::value::RuntimeValue;
pub use self::host::{HostModule, HostModuleBuilder, HostFunc, AsReturnVal, FromArg}; pub use self::host::{HostModule, HostModuleBuilder, HostFunc, IntoReturnVal, FromArg};
pub use self::imports::{ImportResolver, Imports}; pub use self::imports::{ImportResolver, Imports};
pub use self::module::ModuleInstance; pub use self::module::ModuleInstance;
pub use self::global::GlobalInstance; pub use self::global::GlobalInstance;

View File

@ -133,7 +133,7 @@ fn build_env_module() -> HostModule<TestState> {
let sum = memory_value + fn_argument; let sum = memory_value + fn_argument;
state.memory.set(0, &vec![sum]).unwrap(); state.memory.set(0, &vec![sum]).unwrap();
state.values.borrow_mut().push(sum as i32); state.values.borrow_mut().push(sum as i32);
Ok(Some(sum as i32)) Ok(sum as i32)
}); });
builder.with_func2("sub", |state: &TestState, arg: i32, unused: i32| { builder.with_func2("sub", |state: &TestState, arg: i32, unused: i32| {
let memory_value = state.memory.get(0, 1).unwrap()[0]; let memory_value = state.memory.get(0, 1).unwrap()[0];
@ -144,9 +144,9 @@ fn build_env_module() -> HostModule<TestState> {
let diff = memory_value - fn_argument; let diff = memory_value - fn_argument;
state.memory.set(0, &vec![diff]).unwrap(); state.memory.set(0, &vec![diff]).unwrap();
state.values.borrow_mut().push(diff as i32); state.values.borrow_mut().push(diff as i32);
Ok(Some(diff as i32)) Ok(diff as i32)
}); });
builder.with_func2("err", |_: &TestState, _unused1: i32, _unused2: i32| -> Result<Option<i32>, Error> { builder.with_func2("err", |_: &TestState, _unused1: i32, _unused2: i32| -> Result<i32, Error> {
Err(Error::User(Box::new(UserErrorWithCode { error_code: 777 }))) Err(Error::User(Box::new(UserErrorWithCode { error_code: 777 })))
}); });
builder.insert_memory("memory", Rc::new(MemoryInstance::new(&MemoryType::new(256, None)).unwrap())); builder.insert_memory("memory", Rc::new(MemoryInstance::new(&MemoryType::new(256, None)).unwrap()));
@ -323,14 +323,14 @@ fn native_ref_state() {
let mut host_module_builder = HostModuleBuilder::<HostState>::new(); let mut host_module_builder = HostModuleBuilder::<HostState>::new();
host_module_builder.with_func1( host_module_builder.with_func1(
"inc", "inc",
|state: &HostState, val: i32| -> Result<Option<()>, Error> { |state: &HostState, val: i32| -> Result<(), Error> {
let mut ext_state = state.ext_state.borrow_mut(); let mut ext_state = state.ext_state.borrow_mut();
// TODO: fix this // TODO: fix this
fn inc(acc: &mut i32, val: i32) { fn inc(acc: &mut i32, val: i32) {
*acc += val; *acc += val;
} }
inc(&mut *ext_state, val); inc(&mut *ext_state, val);
Ok(None) Ok(())
}, },
); );
host_module_builder.build() host_module_builder.build()

View File

@ -153,6 +153,18 @@ impl From<i64> for RuntimeValue {
} }
} }
impl From<u32> for RuntimeValue {
fn from(val: u32) -> Self {
RuntimeValue::I32(val as i32)
}
}
impl From<u64> for RuntimeValue {
fn from(val: u64) -> Self {
RuntimeValue::I64(val as i64)
}
}
impl From<f32> for RuntimeValue { impl From<f32> for RuntimeValue {
fn from(val: f32) -> Self { fn from(val: f32) -> Self {
RuntimeValue::F32(val) RuntimeValue::F32(val)