mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-10 06:38:22 +00:00
Added full support for custom RuntimeErrors. Fixed warnings
This commit is contained in:
@@ -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(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
4
lib/js-api/src/externals/function.rs
vendored
4
lib/js-api/src/externals/function.rs
vendored
@@ -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,
|
||||||
|
|||||||
8
lib/js-api/src/externals/global.rs
vendored
8
lib/js-api/src/externals/global.rs
vendored
@@ -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 _),
|
||||||
|
|||||||
9
lib/js-api/src/externals/memory.rs
vendored
9
lib/js-api/src/externals/memory.rs
vendored
@@ -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 {
|
||||||
|
|||||||
8
lib/js-api/src/externals/table.rs
vendored
8
lib/js-api/src/externals/table.rs
vendored
@@ -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();
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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::{
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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![
|
||||||
|
|||||||
Reference in New Issue
Block a user