Initial sketch

This commit is contained in:
Sergey Pepyakin
2017-11-25 22:28:15 +03:00
parent 0b5939e4e7
commit 6a3b9af597
4 changed files with 93 additions and 19 deletions

View File

@ -1,11 +1,35 @@
//! WebAssembly interpreter module.
use std::any::TypeId;
/// Custom user error.
pub trait UserError: 'static + ::std::fmt::Display + ::std::fmt::Debug + Clone + PartialEq {
pub trait UserError: 'static + ::std::fmt::Display + ::std::fmt::Debug {
#[doc(hidden)]
fn __private_get_type_id__(&self) -> TypeId {
TypeId::of::<Self>()
}
}
impl UserError {
pub fn downcast_ref<T: UserError>(&self) -> Option<&T> {
if self.__private_get_type_id__() == TypeId::of::<T>() {
unsafe { Some(&*(self as *const UserError as *const T)) }
} else {
None
}
}
pub fn downcast_mut<T: UserError>(&mut self) -> Option<&mut T> {
if self.__private_get_type_id__() == TypeId::of::<T>() {
unsafe { Some(&mut *(self as *mut UserError as *mut T)) }
} else {
None
}
}
}
/// Internal interpreter error.
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug)]
pub enum Error<E> where E: UserError {
/// Program-level error.
Program(String),
@ -38,7 +62,8 @@ pub enum Error<E> where E: UserError {
/// Trap.
Trap(String),
/// Custom user error.
User(E),
User(Box<UserError>),
Other(E),
}
impl<E> Into<String> for Error<E> where E: UserError {
@ -60,6 +85,7 @@ impl<E> Into<String> for Error<E> where E: UserError {
Error::Native(s) => s,
Error::Trap(s) => format!("trap: {}", s),
Error::User(e) => format!("user: {}", e),
Error::Other(_) => panic!("TODO: Remove this arm "),
}
}
}
@ -83,6 +109,7 @@ impl<E> ::std::fmt::Display for Error<E> where E: UserError {
Error::Native(ref s) => write!(f, "Native: {}", s),
Error::Trap(ref s) => write!(f, "Trap: {}", s),
Error::User(ref e) => write!(f, "User: {}", e),
Error::Other(_) => panic!("TODO: Remove this arm "),
}
}
}
@ -99,7 +126,7 @@ impl ::std::fmt::Display for DummyUserError {
impl<U> From<U> for Error<U> where U: UserError + Sized {
fn from(e: U) -> Self {
Error::User(e)
Error::User(Box::new(e))
}
}

View File

@ -121,7 +121,6 @@ pub struct CallerContext<'a, E: 'a + UserError> {
}
/// Internal function reference.
#[derive(Clone)]
pub struct InternalFunctionReference<'a, E: UserError> {
/// Module reference.
pub module: Arc<ModuleInstanceInterface<E> + 'a>,
@ -129,6 +128,16 @@ pub struct InternalFunctionReference<'a, E: UserError> {
pub internal_index: u32,
}
// TODO: This impl should be removed once `E` not needed anymore.
impl<'a, E> Clone for InternalFunctionReference<'a, E> where E: UserError {
fn clone(&self) -> InternalFunctionReference<'a, E> {
InternalFunctionReference {
module: Arc::clone(&self.module),
internal_index: self.internal_index,
}
}
}
impl<'a, E> fmt::Debug for InternalFunctionReference<'a, E> where E: UserError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "InternalFunctionReference")

View File

@ -186,7 +186,7 @@ impl UserFunctionExecutor<UserErrorWithCode> for FunctionExecutor {
Ok(Some(RuntimeValue::I32(diff as i32)))
},
"err" => {
Err(Error::User(UserErrorWithCode { error_code: 777 }))
Err(Error::User(Box::new(UserErrorWithCode { error_code: 777 })))
},
_ => Err(Error::Trap("not implemented".into()).into()),
}
@ -401,10 +401,29 @@ fn native_custom_error() {
.build();
let module_instance = program.add_module("main", module, Some(&params.externals)).unwrap();
assert_eq!(module_instance.execute_index(0, params.clone().add_argument(RuntimeValue::I32(7)).add_argument(RuntimeValue::I32(0))),
Err(Error::User(UserErrorWithCode { error_code: 777 })));
assert_eq!(module_instance.execute_index(1, params.clone().add_argument(RuntimeValue::I32(7)).add_argument(RuntimeValue::I32(0))),
Err(Error::User(UserErrorWithCode { error_code: 777 })));
let user_error1 = match module_instance.execute_index(
0,
params
.clone()
.add_argument(RuntimeValue::I32(7))
.add_argument(RuntimeValue::I32(0)),
) {
Err(Error::User(user_error)) => user_error,
result => panic!("Unexpected result {:?}", result),
};
assert_eq!(user_error1.downcast_ref::<UserErrorWithCode>().unwrap(), &UserErrorWithCode { error_code: 777 });
let user_error2 = match module_instance.execute_index(
0,
params
.clone()
.add_argument(RuntimeValue::I32(7))
.add_argument(RuntimeValue::I32(0)),
) {
Err(Error::User(user_error)) => user_error,
result => panic!("Unexpected result {:?}", result),
};
assert_eq!(user_error2.downcast_ref::<UserErrorWithCode>().unwrap(), &UserErrorWithCode { error_code: 777 });
}
#[test]
@ -434,21 +453,21 @@ fn env_native_export_entry_type_check() {
assert!(native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionSignature::Module(&FunctionType::new(vec![ValueType::I32, ValueType::I32], Some(ValueType::I32))))).is_ok());
match native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionSignature::Module(&FunctionType::new(vec![], Some(ValueType::I32))))) {
Err(Error::Validation(_)) => { },
result => panic!("Unexpected result {:?}.", result),
result => panic!("Unexpected result {:?}", result),
}
match native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionSignature::Module(&FunctionType::new(vec![ValueType::I32, ValueType::I32], None)))) {
Err(Error::Validation(_)) => { },
result => panic!("Unexpected result {:?}.", result),
result => panic!("Unexpected result {:?}", result),
}
match native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionSignature::Module(&FunctionType::new(vec![ValueType::I32, ValueType::I32], Some(ValueType::I64))))) {
Err(Error::Validation(_)) => { },
result => panic!("Unexpected result {:?}.", result),
result => panic!("Unexpected result {:?}", result),
}
assert!(native_env_instance.export_entry("ext_global", &ExportEntryType::Global(VariableType::I32)).is_ok());
match native_env_instance.export_entry("ext_global", &ExportEntryType::Global(VariableType::F32)) {
Err(Error::Validation(_)) => { },
result => panic!("Unexpected result {:?}.", result),
result => panic!("Unexpected result {:?}", result),
}
}

View File

@ -35,7 +35,12 @@ fn unreachable() {
Opcode::Unreachable, // trap
Opcode::End]));
assert_eq!(run_function_i32(&module, 0).unwrap_err(), Error::Trap("programmatic".into()));
match run_function_i32(&module, 0) {
Err(Error::Trap(msg)) => {
assert_eq!(msg, "programmatic");
},
result => panic!("Unexpected result {:?}", result),
}
}
#[test]
@ -730,10 +735,24 @@ fn callindirect_2() {
let module = program.add_module("main", module, None).unwrap();
assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(0)].into()).unwrap().unwrap(), RuntimeValue::I32(14));
assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(1)].into()).unwrap().unwrap(), RuntimeValue::I32(6));
assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(2)].into()).unwrap_err(),
Error::Function("expected indirect function with signature ([I32, I32]) -> Some(I32) when got with ([I32]) -> Some(I32)".into()));
assert_eq!(module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(3)].into()).unwrap_err(),
Error::Table("trying to read table item with index 3 when there are only 3 items".into()));
match module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(2)].into()) {
Err(Error::Function(msg)) => {
assert_eq!(
&msg,
"expected indirect function with signature ([I32, I32]) -> Some(I32) when got with ([I32]) -> Some(I32)"
);
}
result => panic!("Unexpected result {:?}", result),
}
match module.execute_index(3, vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(3)].into()) {
Err(Error::Table(msg)) => {
assert_eq!(
&msg,
"trying to read table item with index 3 when there are only 3 items"
)
},
result => panic!("Unexpected result {:?}", result),
}
}
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/select.txt