Added full support for custom RuntimeErrors. Fixed warnings

This commit is contained in:
Syrus Akbary
2021-07-14 02:01:38 -07:00
parent b9b678c514
commit ecbd026e7c
12 changed files with 201 additions and 278 deletions

View File

@@ -1,5 +1,6 @@
use crate::instance::Instance; use crate::instance::Instance;
use crate::wasm_bindgen_polyfill::Global; use crate::wasm_bindgen_polyfill::Global;
use crate::HostEnvInitError;
use crate::WasmerEnv; use crate::WasmerEnv;
use js_sys::Function; use js_sys::Function;
use js_sys::WebAssembly::{Memory, Table}; use js_sys::WebAssembly::{Memory, Table};
@@ -65,11 +66,12 @@ impl VMFunction {
environment: environment.map(|env| Arc::new(RefCell::new(env))), environment: environment.map(|env| Arc::new(RefCell::new(env))),
} }
} }
pub(crate) fn init_envs(&self, instance: &Instance) { pub(crate) fn init_envs(&self, instance: &Instance) -> Result<(), HostEnvInitError> {
if let Some(env) = &self.environment { if let Some(env) = &self.environment {
let mut borrowed_env = env.borrow_mut(); let mut borrowed_env = env.borrow_mut();
borrowed_env.init_with_instance(instance); borrowed_env.init_with_instance(instance)?;
} }
Ok(())
} }
} }

View File

@@ -577,7 +577,7 @@ impl Function {
let given = Args::wasm_types(); let given = Args::wasm_types();
if expected != given { if expected != given {
return Err(RuntimeError::from_str(&format!( return Err(RuntimeError::new(format!(
"given types (`{:?}`) for the function arguments don't match the actual types (`{:?}`)", "given types (`{:?}`) for the function arguments don't match the actual types (`{:?}`)",
given, given,
expected, expected,
@@ -591,7 +591,7 @@ impl Function {
if expected != given { if expected != given {
// todo: error result types don't match // todo: error result types don't match
return Err(RuntimeError::from_str(&format!( return Err(RuntimeError::new(format!(
"given types (`{:?}`) for the function results don't match the actual types (`{:?}`)", "given types (`{:?}`) for the function results don't match the actual types (`{:?}`)",
given, given,
expected, expected,

View File

@@ -73,12 +73,12 @@ impl Global {
}; };
// This is the value type as string, even though is incorrectly called "value" // This is the value type as string, even though is incorrectly called "value"
// in the JS API. // in the JS API.
js_sys::Reflect::set(&descriptor, &"value".into(), &type_str.into()); js_sys::Reflect::set(&descriptor, &"value".into(), &type_str.into())?;
js_sys::Reflect::set( js_sys::Reflect::set(
&descriptor, &descriptor,
&"mutable".into(), &"mutable".into(),
&mutability.is_mutable().into(), &mutability.is_mutable().into(),
); )?;
let js_global = JSGlobal::new(&descriptor, &value).unwrap(); let js_global = JSGlobal::new(&descriptor, &value).unwrap();
let global = VMGlobal::new(js_global, global_ty); let global = VMGlobal::new(js_global, global_ty);
@@ -188,10 +188,10 @@ impl Global {
/// ``` /// ```
pub fn set(&self, val: Val) -> Result<(), RuntimeError> { pub fn set(&self, val: Val) -> Result<(), RuntimeError> {
if self.vm_global.ty.mutability == Mutability::Const { if self.vm_global.ty.mutability == Mutability::Const {
return Err(RuntimeError::from_str("The global is immutable")); return Err(RuntimeError::new("The global is immutable".to_owned()));
} }
if val.ty() != self.vm_global.ty.ty { if val.ty() != self.vm_global.ty.ty {
return Err(RuntimeError::from_str("The types don't match")); return Err(RuntimeError::new("The types don't match".to_owned()));
} }
let new_value = match val { let new_value = match val {
Val::I32(i) => JsValue::from_f64(i as _), Val::I32(i) => JsValue::from_f64(i as _),

View File

@@ -82,13 +82,14 @@ impl Memory {
/// ``` /// ```
pub fn new(store: &Store, ty: MemoryType) -> Result<Self, MemoryError> { pub fn new(store: &Store, ty: MemoryType) -> Result<Self, MemoryError> {
let descriptor = js_sys::Object::new(); let descriptor = js_sys::Object::new();
js_sys::Reflect::set(&descriptor, &"initial".into(), &ty.minimum.0.into()); js_sys::Reflect::set(&descriptor, &"initial".into(), &ty.minimum.0.into()).unwrap();
if let Some(max) = ty.maximum { if let Some(max) = ty.maximum {
js_sys::Reflect::set(&descriptor, &"maximum".into(), &max.0.into()); js_sys::Reflect::set(&descriptor, &"maximum".into(), &max.0.into()).unwrap();
} }
js_sys::Reflect::set(&descriptor, &"shared".into(), &ty.shared.into()); js_sys::Reflect::set(&descriptor, &"shared".into(), &ty.shared.into()).unwrap();
let js_memory = js_sys::WebAssembly::Memory::new(&descriptor).unwrap(); let js_memory = js_sys::WebAssembly::Memory::new(&descriptor)
.map_err(|_e| MemoryError::Generic("Error while creating the memory".to_owned()))?;
let memory = VMMemory::new(js_memory, ty); let memory = VMMemory::new(js_memory, ty);
Ok(Self { Ok(Self {

View File

@@ -45,13 +45,13 @@ impl Table {
/// [`BaseTunables`][crate::tunables::BaseTunables]. /// [`BaseTunables`][crate::tunables::BaseTunables].
pub fn new(store: &Store, ty: TableType, init: Val) -> Result<Self, RuntimeError> { pub fn new(store: &Store, ty: TableType, init: Val) -> Result<Self, RuntimeError> {
let descriptor = js_sys::Object::new(); let descriptor = js_sys::Object::new();
js_sys::Reflect::set(&descriptor, &"initial".into(), &ty.minimum.into()); js_sys::Reflect::set(&descriptor, &"initial".into(), &ty.minimum.into())?;
if let Some(max) = ty.maximum { if let Some(max) = ty.maximum {
js_sys::Reflect::set(&descriptor, &"maximum".into(), &max.into()); js_sys::Reflect::set(&descriptor, &"maximum".into(), &max.into())?;
} }
js_sys::Reflect::set(&descriptor, &"element".into(), &"anyfunc".into()); js_sys::Reflect::set(&descriptor, &"element".into(), &"anyfunc".into())?;
let js_table = js_sys::WebAssembly::Table::new(&descriptor).unwrap(); let js_table = js_sys::WebAssembly::Table::new(&descriptor)?;
let table = VMTable::new(js_table, ty); let table = VMTable::new(js_table, ty);
let num_elements = table.table.length(); let num_elements = table.table.length();

View File

@@ -118,7 +118,7 @@ impl Instance {
exports, exports,
}; };
for func in functions { for func in functions {
func.init_envs(&self_instance); func.init_envs(&self_instance).unwrap();
} }
Ok(self_instance) Ok(self_instance)
} }

View File

@@ -102,6 +102,7 @@ mod native;
mod ptr; mod ptr;
mod resolver; mod resolver;
mod store; mod store;
mod trap;
mod types; mod types;
mod utils; mod utils;
mod wasm_bindgen_polyfill; mod wasm_bindgen_polyfill;
@@ -124,7 +125,7 @@ pub use crate::module::{Module, ModuleTypeHints};
pub use crate::native::NativeFunc; pub use crate::native::NativeFunc;
pub use crate::ptr::{Array, Item, WasmPtr}; pub use crate::ptr::{Array, Item, WasmPtr};
pub use crate::resolver::{ChainableNamedResolver, NamedResolver, NamedResolverChain, Resolver}; pub use crate::resolver::{ChainableNamedResolver, NamedResolver, NamedResolverChain, Resolver};
pub use wasm_bindgen::JsValue as RuntimeError; pub use crate::trap::RuntimeError;
pub use crate::store::{Store, StoreObject}; pub use crate::store::{Store, StoreObject};
pub use crate::types::{ pub use crate::types::{

View File

@@ -7,6 +7,7 @@ use crate::types::{ExportType, ImportType};
use crate::error::CompileError; use crate::error::CompileError;
#[cfg(feature = "wat")] #[cfg(feature = "wat")]
use crate::error::WasmError; use crate::error::WasmError;
use crate::RuntimeError;
use js_sys::{Reflect, Uint8Array, WebAssembly}; use js_sys::{Reflect, Uint8Array, WebAssembly};
use std::fmt; use std::fmt;
use std::io; use std::io;
@@ -208,39 +209,31 @@ impl Module {
pub(crate) fn instantiate( pub(crate) fn instantiate(
&self, &self,
resolver: &dyn Resolver, resolver: &dyn Resolver,
) -> Result<(WebAssembly::Instance, Vec<VMFunction>), ()> { ) -> Result<(WebAssembly::Instance, Vec<VMFunction>), RuntimeError> {
let imports = js_sys::Object::new(); let imports = js_sys::Object::new();
let mut functions: Vec<VMFunction> = vec![]; let mut functions: Vec<VMFunction> = vec![];
for (i, import_type) in self.imports().enumerate() { for (i, import_type) in self.imports().enumerate() {
let resolved_import = let resolved_import =
resolver.resolve(i as u32, import_type.module(), import_type.name()); resolver.resolve(i as u32, import_type.module(), import_type.name());
if let Some(import) = resolved_import { if let Some(import) = resolved_import {
match js_sys::Reflect::get(&imports, &import_type.module().into()) { let val = js_sys::Reflect::get(&imports, &import_type.module().into())?;
Ok(val) => { if !val.is_undefined() {
if !val.is_undefined() { // If the namespace is already set
// If the namespace is already set js_sys::Reflect::set(&val, &import_type.name().into(), import.as_jsvalue())?;
js_sys::Reflect::set( } else {
&val, // If the namespace doesn't exist
&import_type.name().into(), let import_namespace = js_sys::Object::new();
import.as_jsvalue(), js_sys::Reflect::set(
); &import_namespace,
} else { &import_type.name().into(),
// If the namespace doesn't exist import.as_jsvalue(),
let import_namespace = js_sys::Object::new(); )?;
js_sys::Reflect::set( js_sys::Reflect::set(
&import_namespace, &imports,
&import_type.name().into(), &import_type.module().into(),
import.as_jsvalue(), &import_namespace.into(),
); )?;
js_sys::Reflect::set( }
&imports,
&import_type.module().into(),
&import_namespace.into(),
);
}
}
Err(_) => return Err(()),
};
if let Export::Function(func) = import { if let Export::Function(func) = import {
functions.push(func); functions.push(func);
} }

View File

@@ -252,7 +252,7 @@ mod test {
let memory = Memory::new(&store, memory_descriptor).unwrap(); let memory = Memory::new(&store, memory_descriptor).unwrap();
let start_wasm_ptr: WasmPtr<u64> = WasmPtr::new(2); let start_wasm_ptr: WasmPtr<u64> = WasmPtr::new(2);
let mut val = start_wasm_ptr.deref(&memory).unwrap(); let val = start_wasm_ptr.deref(&memory).unwrap();
assert_eq!(val.memory.to_vec(), vec![0; 8]); assert_eq!(val.memory.to_vec(), vec![0; 8]);
val.set(1200); val.set(1200);

View File

@@ -1,15 +1,22 @@
use super::frame_info::{FrameInfo, GlobalFrameInfo, FRAME_INFO}; // use super::frame_info::{FrameInfo, GlobalFrameInfo, FRAME_INFO};
use backtrace::Backtrace;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
use std::sync::Arc; use std::sync::Arc;
use wasm_bindgen::Exception; use wasm_bindgen::prelude::*;
use wasm_bindgen::JsValue;
/// A struct representing an aborted instruction execution, with a message /// A struct representing an aborted instruction execution, with a message
/// indicating the cause. /// indicating the cause.
#[wasm_bindgen]
#[derive(Clone)] #[derive(Clone)]
pub struct RuntimeError { pub struct RuntimeError {
inner: Arc<RuntimeErrorInner>, inner: Arc<RuntimeErrorSource>,
}
impl PartialEq for RuntimeError {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.inner, &other.inner)
}
} }
/// The source of the `RuntimeError`. /// The source of the `RuntimeError`.
@@ -17,6 +24,7 @@ pub struct RuntimeError {
enum RuntimeErrorSource { enum RuntimeErrorSource {
Generic(String), Generic(String),
User(Box<dyn Error + Send + Sync>), User(Box<dyn Error + Send + Sync>),
Js(JsValue),
} }
impl fmt::Display for RuntimeErrorSource { impl fmt::Display for RuntimeErrorSource {
@@ -24,20 +32,14 @@ impl fmt::Display for RuntimeErrorSource {
match self { match self {
Self::Generic(s) => write!(f, "{}", s), Self::Generic(s) => write!(f, "{}", s),
Self::User(s) => write!(f, "{}", s), Self::User(s) => write!(f, "{}", s),
Self::OOM => write!(f, "Wasmer VM out of memory"), Self::Js(s) => write!(f, "{}", s.as_string().unwrap_or("".to_string())),
Self::Trap(s) => write!(f, "{}", s.message()),
} }
} }
} }
struct RuntimeErrorInner { // fn _assert_trap_is_sync_and_send(t: &Trap) -> (&dyn Sync, &dyn Send) {
/// The source error (this can be a custom user `Error` or a [`TrapCode`]) // (t, t)
source: RuntimeErrorSource, // }
}
fn _assert_trap_is_sync_and_send(t: &Trap) -> (&dyn Sync, &dyn Send) {
(t, t)
}
impl RuntimeError { impl RuntimeError {
/// Creates a new generic `RuntimeError` with the given `message`. /// Creates a new generic `RuntimeError` with the given `message`.
@@ -48,82 +50,30 @@ impl RuntimeError {
/// assert_eq!("unexpected error", trap.message()); /// assert_eq!("unexpected error", trap.message());
/// ``` /// ```
pub fn new<I: Into<String>>(message: I) -> Self { pub fn new<I: Into<String>>(message: I) -> Self {
let info = FRAME_INFO.read().unwrap(); RuntimeError {
let msg = message.into(); inner: Arc::new(RuntimeErrorSource::Generic(message.into())),
Self::new_with_trace( }
&info,
None,
RuntimeErrorSource::Generic(msg),
Backtrace::new_unresolved(),
)
} }
/// Raises a custom user Error /// Raises a custom user Error
pub fn raise(error: Box<dyn Error + Send + Sync>) -> ! { pub fn raise(error: Box<dyn Error + Send + Sync>) -> ! {
wasm_bindgen::throw_val() let error = RuntimeError {
} inner: Arc::new(RuntimeErrorSource::User(error)),
};
fn new_with_trace( let js_error: JsValue = error.into();
info: &GlobalFrameInfo, wasm_bindgen::throw_val(js_error)
trap_pc: Option<usize>,
source: RuntimeErrorSource,
native_trace: Backtrace,
) -> Self {
let frames: Vec<usize> = native_trace
.frames()
.iter()
.filter_map(|frame| {
let pc = frame.ip() as usize;
if pc == 0 {
None
} else {
// Note that we need to be careful about the pc we pass in here to
// lookup frame information. This program counter is used to
// translate back to an original source location in the origin wasm
// module. If this pc is the exact pc that the trap happened at,
// then we look up that pc precisely. Otherwise backtrace
// information typically points at the pc *after* the call
// instruction (because otherwise it's likely a call instruction on
// the stack). In that case we want to lookup information for the
// previous instruction (the call instruction) so we subtract one as
// the lookup.
let pc_to_lookup = if Some(pc) == trap_pc { pc } else { pc - 1 };
Some(pc_to_lookup)
}
})
.collect();
// Let's construct the trace
let wasm_trace = frames
.into_iter()
.filter_map(|pc| info.lookup_frame_info(pc))
.collect::<Vec<_>>();
Self {
inner: Arc::new(RuntimeErrorInner {
source,
wasm_trace,
native_trace,
}),
}
} }
/// Returns a reference the `message` stored in `Trap`. /// Returns a reference the `message` stored in `Trap`.
pub fn message(&self) -> String { pub fn message(&self) -> String {
format!("{}", self.inner.source) format!("{}", self.inner)
}
/// Returns a list of function frames in WebAssembly code that led to this
/// trap happening.
pub fn trace(&self) -> &[FrameInfo] {
&self.inner.wasm_trace
} }
/// Attempts to downcast the `RuntimeError` to a concrete type. /// Attempts to downcast the `RuntimeError` to a concrete type.
pub fn downcast<T: Error + 'static>(self) -> Result<T, Self> { pub fn downcast<T: Error + 'static>(self) -> Result<T, Self> {
match self.inner.source { match Arc::try_unwrap(self.inner) {
// We only try to downcast user errors // We only try to downcast user errors
RuntimeErrorSource::User(err)) if err.is::<T>() => Ok(*err.downcast::<T>().unwrap()), Ok(RuntimeErrorSource::User(err)) if err.is::<T>() => Ok(*err.downcast::<T>().unwrap()),
Ok(inner) => Err(Self { Ok(inner) => Err(Self {
inner: Arc::new(inner), inner: Arc::new(inner),
}), }),
@@ -131,18 +81,9 @@ impl RuntimeError {
} }
} }
/// Returns trap code, if it's a Trap
pub fn to_trap(self) -> Option<TrapCode> {
if let RuntimeErrorSource::Trap(trap_code) = self.inner.source {
Some(trap_code)
} else {
None
}
}
/// Returns true if the `RuntimeError` is the same as T /// Returns true if the `RuntimeError` is the same as T
pub fn is<T: Error + 'static>(&self) -> bool { pub fn is<T: Error + 'static>(&self) -> bool {
match &self.inner.source { match self.inner.as_ref() {
RuntimeErrorSource::User(err) => err.is::<T>(), RuntimeErrorSource::User(err) => err.is::<T>(),
_ => false, _ => false,
} }
@@ -152,9 +93,7 @@ impl RuntimeError {
impl fmt::Debug for RuntimeError { impl fmt::Debug for RuntimeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RuntimeError") f.debug_struct("RuntimeError")
.field("source", &self.inner.source) .field("source", &self.inner)
.field("wasm_trace", &self.inner.wasm_trace)
.field("native_trace", &self.inner.native_trace)
.finish() .finish()
} }
} }
@@ -162,46 +101,29 @@ impl fmt::Debug for RuntimeError {
impl fmt::Display for RuntimeError { impl fmt::Display for RuntimeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "RuntimeError: {}", self.message())?; write!(f, "RuntimeError: {}", self.message())?;
let trace = self.trace();
if trace.is_empty() {
return Ok(());
}
for frame in self.trace().iter() {
let name = frame.module_name();
let func_index = frame.func_index();
writeln!(f)?;
write!(f, " at ")?;
match frame.function_name() {
Some(name) => match rustc_demangle::try_demangle(name) {
Ok(name) => write!(f, "{}", name)?,
Err(_) => write!(f, "{}", name)?,
},
None => write!(f, "<unnamed>")?,
}
write!(
f,
" ({}[{}]:0x{:x})",
name,
func_index,
frame.module_offset()
)?;
}
Ok(()) Ok(())
} }
} }
impl std::error::Error for RuntimeError { impl std::error::Error for RuntimeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self.inner.source { match self.inner.as_ref() {
RuntimeErrorSource::User(err) => Some(&**err), RuntimeErrorSource::User(err) => Some(&**err),
RuntimeErrorSource::Trap(err) => Some(err),
_ => None, _ => None,
} }
} }
} }
impl From<Trap> for RuntimeError { impl From<JsValue> for RuntimeError {
fn from(trap: Trap) -> Self { fn from(original: JsValue) -> Self {
Self::from_trap(trap) RuntimeError {
inner: Arc::new(RuntimeErrorSource::Js(original)),
}
} }
} }
// impl Into<JsValue> for RuntimeError {
// fn into(self) -> JsValue {
// }
// }

View File

@@ -14,10 +14,12 @@ fn test_exported_memory() {
"#, "#,
) )
.unwrap(); .unwrap();
module.set_type_hints(ModuleTypeHints { module
imports: vec![], .set_type_hints(ModuleTypeHints {
exports: vec![ExternType::Memory(MemoryType::new(Pages(1), None, false))], imports: vec![],
}); exports: vec![ExternType::Memory(MemoryType::new(Pages(1), None, false))],
})
.unwrap();
let import_object = imports! {}; let import_object = imports! {};
let instance = Instance::new(&module, &import_object).unwrap(); let instance = Instance::new(&module, &import_object).unwrap();
@@ -47,13 +49,15 @@ fn test_exported_function() {
"#, "#,
) )
.unwrap(); .unwrap();
module.set_type_hints(ModuleTypeHints { module
imports: vec![], .set_type_hints(ModuleTypeHints {
exports: vec![ExternType::Function(FunctionType::new( imports: vec![],
vec![], exports: vec![ExternType::Function(FunctionType::new(
vec![Type::I32], vec![],
))], vec![Type::I32],
}); ))],
})
.unwrap();
let import_object = imports! {}; let import_object = imports! {};
let instance = Instance::new(&module, &import_object).unwrap(); let instance = Instance::new(&module, &import_object).unwrap();
@@ -83,16 +87,18 @@ fn test_imported_function_dynamic() {
"#, "#,
) )
.unwrap(); .unwrap();
module.set_type_hints(ModuleTypeHints { module
imports: vec![ExternType::Function(FunctionType::new( .set_type_hints(ModuleTypeHints {
vec![Type::I32], imports: vec![ExternType::Function(FunctionType::new(
vec![Type::I32], vec![Type::I32],
))], vec![Type::I32],
exports: vec![ExternType::Function(FunctionType::new( ))],
vec![Type::I32], exports: vec![ExternType::Function(FunctionType::new(
vec![Type::I32], vec![Type::I32],
))], vec![Type::I32],
}); ))],
})
.unwrap();
let imported_signature = FunctionType::new(vec![Type::I32], vec![Type::I32]); let imported_signature = FunctionType::new(vec![Type::I32], vec![Type::I32]);
let imported = Function::new(&store, &imported_signature, |args| { let imported = Function::new(&store, &imported_signature, |args| {
@@ -102,15 +108,6 @@ fn test_imported_function_dynamic() {
Ok(vec![Value::I32(result)]) Ok(vec![Value::I32(result)])
}); });
let imported_multivalue_signature =
FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32, Type::I32]);
let imported_multivalue = Function::new(&store, &imported_multivalue_signature, |args| {
println!("Calling `imported`...");
// let result = args[0].unwrap_i32() * ;
// println!("Result of `imported`: {:?}", result);
Ok(vec![args[1].clone(), args[0].clone()])
});
let import_object = imports! { let import_object = imports! {
"env" => { "env" => {
"imported" => imported, "imported" => imported,
@@ -199,22 +196,18 @@ fn test_imported_function_dynamic_with_env() {
"#, "#,
) )
.unwrap(); .unwrap();
module.set_type_hints(ModuleTypeHints { module
imports: vec![ .set_type_hints(ModuleTypeHints {
ExternType::Function(FunctionType::new(vec![Type::I32], vec![Type::I32])), imports: vec![ExternType::Function(FunctionType::new(
ExternType::Function(FunctionType::new( vec![Type::I32],
vec![Type::I32, Type::I32], vec![Type::I32],
vec![Type::I32, Type::I32], ))],
)), exports: vec![ExternType::Function(FunctionType::new(
], vec![Type::I32],
exports: vec![ vec![Type::I32],
ExternType::Function(FunctionType::new(vec![Type::I32], vec![Type::I32])), ))],
ExternType::Function(FunctionType::new( })
vec![Type::I32, Type::I32], .unwrap();
vec![Type::I32, Type::I32],
)),
],
});
#[derive(WasmerEnv, Clone)] #[derive(WasmerEnv, Clone)]
struct Env { struct Env {
@@ -262,16 +255,18 @@ fn test_imported_function_native() {
"#, "#,
) )
.unwrap(); .unwrap();
module.set_type_hints(ModuleTypeHints { module
imports: vec![ExternType::Function(FunctionType::new( .set_type_hints(ModuleTypeHints {
vec![Type::I32], imports: vec![ExternType::Function(FunctionType::new(
vec![Type::I32], vec![Type::I32],
))], vec![Type::I32],
exports: vec![ExternType::Function(FunctionType::new( ))],
vec![Type::I32], exports: vec![ExternType::Function(FunctionType::new(
vec![Type::I32], vec![Type::I32],
))], vec![Type::I32],
}); ))],
})
.unwrap();
fn imported_fn(arg: u32) -> u32 { fn imported_fn(arg: u32) -> u32 {
return arg + 1; return arg + 1;
@@ -307,16 +302,18 @@ fn test_imported_function_native_with_env() {
"#, "#,
) )
.unwrap(); .unwrap();
module.set_type_hints(ModuleTypeHints { module
imports: vec![ExternType::Function(FunctionType::new( .set_type_hints(ModuleTypeHints {
vec![Type::I32], imports: vec![ExternType::Function(FunctionType::new(
vec![Type::I32], vec![Type::I32],
))], vec![Type::I32],
exports: vec![ExternType::Function(FunctionType::new( ))],
vec![Type::I32], exports: vec![ExternType::Function(FunctionType::new(
vec![Type::I32], vec![Type::I32],
))], vec![Type::I32],
}); ))],
})
.unwrap();
#[derive(WasmerEnv, Clone)] #[derive(WasmerEnv, Clone)]
struct Env { struct Env {
@@ -358,16 +355,18 @@ fn test_imported_function_native_with_wasmer_env() {
"#, "#,
) )
.unwrap(); .unwrap();
module.set_type_hints(ModuleTypeHints { module
imports: vec![ExternType::Function(FunctionType::new( .set_type_hints(ModuleTypeHints {
vec![Type::I32], imports: vec![ExternType::Function(FunctionType::new(
vec![Type::I32], vec![Type::I32],
))], vec![Type::I32],
exports: vec![ ))],
ExternType::Function(FunctionType::new(vec![Type::I32], vec![Type::I32])), exports: vec![
ExternType::Memory(MemoryType::new(Pages(1), None, false)), ExternType::Function(FunctionType::new(vec![Type::I32], vec![Type::I32])),
], ExternType::Memory(MemoryType::new(Pages(1), None, false)),
}); ],
})
.unwrap();
#[derive(WasmerEnv, Clone)] #[derive(WasmerEnv, Clone)]
struct Env { struct Env {
@@ -409,11 +408,11 @@ fn test_imported_function_native_with_wasmer_env() {
let exported = instance.exports.get_function("exported").unwrap(); let exported = instance.exports.get_function("exported").unwrap();
/// It with the provided memory // It works with the provided memory
let expected = vec![Val::I32(24)].into_boxed_slice(); let expected = vec![Val::I32(24)].into_boxed_slice();
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected)); assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
/// It works if we update the memory // It works if we update the memory
memory.uint8view().set_index(0, 3); memory.uint8view().set_index(0, 3);
let expected = vec![Val::I32(36)].into_boxed_slice(); let expected = vec![Val::I32(36)].into_boxed_slice();
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected)); assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
@@ -435,16 +434,18 @@ fn test_imported_function_with_wasmer_env() {
"#, "#,
) )
.unwrap(); .unwrap();
module.set_type_hints(ModuleTypeHints { module
imports: vec![ExternType::Function(FunctionType::new( .set_type_hints(ModuleTypeHints {
vec![Type::I32], imports: vec![ExternType::Function(FunctionType::new(
vec![Type::I32], vec![Type::I32],
))], vec![Type::I32],
exports: vec![ ))],
ExternType::Function(FunctionType::new(vec![Type::I32], vec![Type::I32])), exports: vec![
ExternType::Memory(MemoryType::new(Pages(1), None, false)), ExternType::Function(FunctionType::new(vec![Type::I32], vec![Type::I32])),
], ExternType::Memory(MemoryType::new(Pages(1), None, false)),
}); ],
})
.unwrap();
#[derive(WasmerEnv, Clone)] #[derive(WasmerEnv, Clone)]
struct Env { struct Env {
@@ -489,11 +490,11 @@ fn test_imported_function_with_wasmer_env() {
let exported = instance.exports.get_function("exported").unwrap(); let exported = instance.exports.get_function("exported").unwrap();
/// It with the provided memory // It works with the provided memory
let expected = vec![Val::I32(24)].into_boxed_slice(); let expected = vec![Val::I32(24)].into_boxed_slice();
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected)); assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
/// It works if we update the memory // It works if we update the memory
memory.uint8view().set_index(0, 3); memory.uint8view().set_index(0, 3);
let expected = vec![Val::I32(36)].into_boxed_slice(); let expected = vec![Val::I32(36)].into_boxed_slice();
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected)); assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
@@ -515,17 +516,19 @@ fn test_imported_exported_global() {
"#, "#,
) )
.unwrap(); .unwrap();
module.set_type_hints(ModuleTypeHints { module
imports: vec![ExternType::Global(GlobalType::new( .set_type_hints(ModuleTypeHints {
ValType::I32, imports: vec![ExternType::Global(GlobalType::new(
Mutability::Var, ValType::I32,
))], Mutability::Var,
exports: vec![ ))],
ExternType::Function(FunctionType::new(vec![], vec![Type::I32])), exports: vec![
ExternType::Function(FunctionType::new(vec![], vec![])), ExternType::Function(FunctionType::new(vec![], vec![Type::I32])),
], ExternType::Function(FunctionType::new(vec![], vec![])),
}); ],
let mut global = Global::new_mut(&store, Value::I32(0)); })
.unwrap();
let global = Global::new_mut(&store, Value::I32(0));
let import_object = imports! { let import_object = imports! {
"" => { "" => {
"global" => global.clone() "global" => global.clone()
@@ -539,14 +542,14 @@ fn test_imported_exported_global() {
Ok(vec![Val::I32(0)].into_boxed_slice()) Ok(vec![Val::I32(0)].into_boxed_slice())
); );
global.set(Value::I32(42)); global.set(Value::I32(42)).unwrap();
assert_eq!( assert_eq!(
get_global.call(&[]), get_global.call(&[]),
Ok(vec![Val::I32(42)].into_boxed_slice()) Ok(vec![Val::I32(42)].into_boxed_slice())
); );
let inc_global = instance.exports.get_function("incGlobal").unwrap(); let inc_global = instance.exports.get_function("incGlobal").unwrap();
inc_global.call(&[]); inc_global.call(&[]).unwrap();
assert_eq!( assert_eq!(
get_global.call(&[]), get_global.call(&[]),
Ok(vec![Val::I32(43)].into_boxed_slice()) Ok(vec![Val::I32(43)].into_boxed_slice())

View File

@@ -1,4 +1,3 @@
use anyhow::Result;
use wasm_bindgen_test::*; use wasm_bindgen_test::*;
use wasmer_js::*; use wasmer_js::*;
@@ -105,15 +104,17 @@ fn exports() {
(global (export "global") i32 (i32.const 0)) (global (export "global") i32 (i32.const 0))
)"#; )"#;
let mut module = Module::new(&store, wat).unwrap(); let mut module = Module::new(&store, wat).unwrap();
module.set_type_hints(ModuleTypeHints { module
exports: vec![ .set_type_hints(ModuleTypeHints {
ExternType::Function(FunctionType::new(vec![], vec![])), exports: vec![
ExternType::Memory(MemoryType::new(Pages(2), None, false)), ExternType::Function(FunctionType::new(vec![], vec![])),
ExternType::Table(TableType::new(Type::FuncRef, 2, None)), ExternType::Memory(MemoryType::new(Pages(2), None, false)),
ExternType::Global(GlobalType::new(Type::I32, Mutability::Const)), ExternType::Table(TableType::new(Type::FuncRef, 2, None)),
], ExternType::Global(GlobalType::new(Type::I32, Mutability::Const)),
imports: vec![], ],
}); imports: vec![],
})
.unwrap();
assert_eq!( assert_eq!(
module.exports().collect::<Vec<_>>(), module.exports().collect::<Vec<_>>(),
vec![ vec![