diff --git a/Makefile b/Makefile index 8355918c5..7ad96636e 100644 --- a/Makefile +++ b/Makefile @@ -486,6 +486,9 @@ test-packages: test-js: test-js-api test-js-wasi +test-js-core: + cd lib/api && wasm-pack test --node -- --no-default-features --features js,core,wasm-types-polyfill,wat + test-js-api: cd lib/api && wasm-pack test --node -- --no-default-features --features js-default,wat diff --git a/lib/api/src/js/error.rs b/lib/api/src/js/error.rs index f334b4a1c..0bd656af7 100644 --- a/lib/api/src/js/error.rs +++ b/lib/api/src/js/error.rs @@ -2,6 +2,8 @@ use crate::js::lib::std::string::String; use crate::js::trap::RuntimeError; #[cfg(feature = "std")] use std::borrow::Cow; +#[cfg(feature = "core")] +use crate::alloc::borrow::Cow; #[cfg(feature = "std")] use thiserror::Error; @@ -115,7 +117,7 @@ impl From for WasmError { pub enum SerializeError { /// An IO error #[cfg_attr(feature = "std", error(transparent))] - Io(#[from] std::io::Error), + Io(#[cfg_attr(feature = "std", from)] std::io::Error), /// A generic serialization error #[cfg_attr(feature = "std", error("{0}"))] Generic(String), @@ -124,11 +126,12 @@ pub enum SerializeError { /// The Deserialize error can occur when loading a /// compiled Module from a binary. /// Copied from wasmer_compiler::DeSerializeError -#[derive(Error, Debug)] +#[derive(Debug)] +#[cfg_attr(feature = "std", derive(Error))] pub enum DeserializeError { /// An IO error #[cfg_attr(feature = "std", error(transparent))] - Io(#[from] std::io::Error), + Io(#[cfg_attr(feature = "std", from)] std::io::Error), /// A generic deserialization error #[cfg_attr(feature = "std", error("{0}"))] Generic(String), diff --git a/lib/api/src/js/mod.rs b/lib/api/src/js/mod.rs index a642e14b5..99aa2c22b 100644 --- a/lib/api/src/js/mod.rs +++ b/lib/api/src/js/mod.rs @@ -7,12 +7,12 @@ compile_error!( compile_error!("Both the `std` and `core` features are disabled. Please enable one of them."); #[cfg(feature = "core")] -extern crate alloc; +pub(crate) extern crate alloc; mod lib { #[cfg(feature = "core")] pub mod std { - pub use alloc::{borrow, boxed, str, string, sync, vec}; + pub use crate::alloc::{borrow, boxed, str, string, sync, vec}; pub use core::fmt; pub use hashbrown as collections; } @@ -23,7 +23,7 @@ mod lib { } } -mod error; +pub(crate) mod error; mod export; mod exports; mod externals; diff --git a/lib/api/src/js/trap.rs b/lib/api/src/js/trap.rs index 0d5ca5318..1273851a3 100644 --- a/lib/api/src/js/trap.rs +++ b/lib/api/src/js/trap.rs @@ -6,6 +6,10 @@ use wasm_bindgen::convert::FromWasmAbi; use wasm_bindgen::prelude::*; use wasm_bindgen::JsValue; +pub trait CoreError: fmt::Debug + fmt::Display + core::any::Any { } + +impl CoreError for T { } + /// A struct representing an aborted instruction execution, with a message /// indicating the cause. #[wasm_bindgen] @@ -30,7 +34,10 @@ impl PartialEq for RuntimeError { #[derive(Debug)] enum RuntimeErrorSource { Generic(String), + #[cfg(feature = "std")] User(Box), + #[cfg(feature = "core")] + User(Box), Js(JsValue), } @@ -74,6 +81,7 @@ impl RuntimeError { /// /// This error object can be passed through Wasm frames and later retrieved /// using the `downcast` method. + #[cfg(feature = "std")] pub fn user(error: Box) -> Self { match error.downcast::() { // The error is already a RuntimeError, we return it directly @@ -84,6 +92,17 @@ impl RuntimeError { } } + #[cfg(feature = "core")] + pub fn user(error: Box) -> Self { + match error.downcast::() { + // The error is already a RuntimeError, we return it directly + Ok(runtime_error) => *runtime_error, + Err(error) => RuntimeError { + inner: Arc::new(RuntimeErrorSource::User(error)), + }, + } + } + /// Returns a reference the `message` stored in `Trap`. pub fn message(&self) -> String { format!("{}", self.inner) diff --git a/lib/compiler/src/engine/trap/error.rs b/lib/compiler/src/engine/trap/error.rs index 76ae212fb..60e033985 100644 --- a/lib/compiler/src/engine/trap/error.rs +++ b/lib/compiler/src/engine/trap/error.rs @@ -12,12 +12,19 @@ pub struct RuntimeError { inner: Arc, } +pub trait CoreError: fmt::Debug + fmt::Display + core::any::Any { } + +impl CoreError for T { } + /// The source of the `RuntimeError`. #[derive(Debug)] enum RuntimeErrorSource { Generic(String), OutOfMemory, + #[cfg(feature = "std")] User(Box), + #[cfg(feature = "core")] + User(Box), Trap(TrapCode), } @@ -110,6 +117,7 @@ impl RuntimeError { /// /// This error object can be passed through Wasm frames and later retrieved /// using the `downcast` method. + #[cfg(feature = "std")] pub fn user(error: Box) -> Self { match error.downcast::() { // The error is already a RuntimeError, we return it directly @@ -126,6 +134,27 @@ impl RuntimeError { } } + /// Creates a custom user Error. + /// + /// This error object can be passed through Wasm frames and later retrieved + /// using the `downcast` method. + #[cfg(feature = "core")] + pub fn user(error: Box) -> Self { + match error.downcast::() { + // The error is already a RuntimeError, we return it directly + Ok(runtime_error) => *runtime_error, + Err(error) => { + let info = FRAME_INFO.read().unwrap(); + Self::new_with_trace( + &info, + None, + RuntimeErrorSource::User(error), + Backtrace::new_unresolved(), + ) + } + } + } + fn new_with_trace( info: &GlobalFrameInfo, trap_pc: Option,