mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-18 09:21:49 +00:00
Initial sketch
This commit is contained in:
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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(¶ms.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),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user