Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial port of make test-js-core (port wasmer API to core) #3165

Merged
merged 8 commits into from
Sep 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/test-js.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,6 @@ jobs:

- name: Compile Wasmer to WebAssembly and test with a JavaScript host
run: make test-js

- name: Compile Wasmer to WebAssembly and test with a JavaScript host (no-std)
run: make test-js-core
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
fschutt marked this conversation as resolved.
Show resolved Hide resolved

test-js-api:
cd lib/api && wasm-pack test --node -- --no-default-features --features js-default,wat

Expand Down
20 changes: 12 additions & 8 deletions lib/api/src/js/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#[cfg(feature = "core")]
use crate::alloc::borrow::Cow;
use crate::js::lib::std::string::String;
use crate::js::trap::RuntimeError;
#[cfg(feature = "std")]
Expand Down Expand Up @@ -116,7 +118,7 @@ impl From<wasm_bindgen::JsValue> 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),
Expand All @@ -125,11 +127,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),
Expand All @@ -151,19 +154,20 @@ pub enum DeserializeError {
/// This is based on the [link error][link-error] API.
///
/// [link-error]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/LinkError
#[derive(Error, Debug)]
#[error("Link error: {0}")]
#[derive(Debug)]
#[cfg_attr(feature = "std", derive(Error))]
#[cfg_attr(feature = "std", error("Link error: {0}"))]
pub enum LinkError {
/// An error occurred when checking the import types.
#[error("Error while importing {0:?}.{1:?}: {2}")]
#[cfg_attr(feature = "std", error("Error while importing {0:?}.{1:?}: {2}"))]
Import(String, String, ImportError),

#[cfg(not(target_arch = "wasm32"))]
/// A trap ocurred during linking.
#[error("RuntimeError occurred during linking: {0}")]
#[cfg_attr(feature = "std", error("RuntimeError occurred during linking: {0}"))]
Trap(#[source] RuntimeError),
/// Insufficient resources available for linking.
#[error("Insufficient resources: {0}")]
#[cfg_attr(feature = "std", error("Insufficient resources: {0}"))]
Resource(String),
}

Expand Down
8 changes: 8 additions & 0 deletions lib/api/src/js/externals/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1148,6 +1148,10 @@ mod inner {
match result {
Ok(Ok(result)) => return result.into_c_struct(&mut store),
#[allow(deprecated)]
#[cfg(feature = "std")]
Ok(Err(trap)) => RuntimeError::raise(Box::new(trap)),
#[cfg(feature = "core")]
#[allow(deprecated)]
Ok(Err(trap)) => RuntimeError::raise(Box::new(trap)),
Err(_panic) => unimplemented!(),
}
Expand Down Expand Up @@ -1191,6 +1195,10 @@ mod inner {

match result {
Ok(Ok(result)) => return result.into_c_struct(&mut store),
#[cfg(feature = "std")]
#[allow(deprecated)]
Ok(Err(trap)) => RuntimeError::raise(Box::new(trap)),
#[cfg(feature = "core")]
#[allow(deprecated)]
Ok(Err(trap)) => RuntimeError::raise(Box::new(trap)),
Err(_panic) => unimplemented!(),
Expand Down
6 changes: 3 additions & 3 deletions lib/api/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -23,7 +23,7 @@ mod lib {
}
}

mod error;
pub(crate) mod error;
mod export;
mod exports;
mod externals;
Expand Down
117 changes: 117 additions & 0 deletions lib/api/src/js/trap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,89 @@ use wasm_bindgen::convert::FromWasmAbi;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsValue;

pub trait CoreError: fmt::Debug + fmt::Display {
fn source(&self) -> Option<&(dyn CoreError + 'static)> {
None
}

fn type_id(&self) -> core::any::TypeId
where
Self: 'static,
{
core::any::TypeId::of::<Self>()
}

fn description(&self) -> &str {
"description() is deprecated; use Display"
}
fn cause(&self) -> Option<&dyn CoreError> {
self.source()
}
}

impl<T: fmt::Debug + fmt::Display> CoreError for T {}

impl dyn CoreError + 'static {
/// Returns `true` if the inner type is the same as `T`.
pub fn core_is_equal<T: CoreError + 'static>(&self) -> bool {
let t = core::any::TypeId::of::<T>();
let concrete = self.type_id();
t == concrete
}
}

impl dyn CoreError + Send + Sync + 'static {
/// Returns `true` if the inner type is the same as `T`.
pub fn core_is_equal<T: CoreError + 'static>(&self) -> bool {
let t = core::any::TypeId::of::<T>();
let concrete = self.type_id();
t == concrete
}
}

impl dyn CoreError + Send {
#[inline]
/// Attempts to downcast the box to a concrete type.
pub fn downcast_core<T: CoreError + 'static>(
self: Box<Self>,
) -> Result<Box<T>, Box<dyn CoreError + Send>> {
let err: Box<dyn CoreError> = self;
<dyn CoreError>::downcast_core(err).map_err(|s| unsafe {
// Reapply the `Send` marker.
core::mem::transmute::<Box<dyn CoreError>, Box<dyn CoreError + Send>>(s)
})
}
}

impl dyn CoreError + Send + Sync {
#[inline]
/// Attempts to downcast the box to a concrete type.
pub fn downcast_core<T: CoreError + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
let err: Box<dyn CoreError> = self;
<dyn CoreError>::downcast_core(err).map_err(|s| unsafe {
// Reapply the `Send + Sync` marker.
core::mem::transmute::<Box<dyn CoreError>, Box<dyn CoreError + Send + Sync>>(s)
})
}
}

impl dyn CoreError {
#[inline]
/// Attempts to downcast the box to a concrete type.
pub fn downcast_core<T: CoreError + 'static>(
self: Box<Self>,
) -> Result<Box<T>, Box<dyn CoreError>> {
if self.core_is_equal::<T>() {
unsafe {
let raw: *mut dyn CoreError = Box::into_raw(self);
Ok(Box::from_raw(raw as *mut T))
}
} else {
Err(self)
}
}
}

/// A struct representing an aborted instruction execution, with a message
/// indicating the cause.
#[wasm_bindgen]
Expand All @@ -30,7 +113,10 @@ impl PartialEq for RuntimeError {
#[derive(Debug)]
enum RuntimeErrorSource {
Generic(String),
#[cfg(feature = "std")]
User(Box<dyn Error + Send + Sync>),
#[cfg(feature = "core")]
User(Box<dyn CoreError + Send + Sync>),
Js(JsValue),
}

Expand Down Expand Up @@ -64,16 +150,27 @@ impl RuntimeError {

/// Raises a custom user Error
#[deprecated(since = "2.1.1", note = "return a Result from host functions instead")]
#[cfg(feature = "std")]
pub(crate) fn raise(error: Box<dyn Error + Send + Sync>) -> ! {
let error = Self::user(error);
let js_error: JsValue = error.into();
wasm_bindgen::throw_val(js_error)
}

/// Raises a custom user Error
#[deprecated(since = "2.1.1", note = "return a Result from host functions instead")]
#[cfg(feature = "core")]
pub(crate) fn raise(error: Box<dyn CoreError + Send + Sync>) -> ! {
let error = Self::user(error);
let js_error: JsValue = error.into();
wasm_bindgen::throw_val(js_error)
}

/// Creates a custom user Error.
///
/// This error object can be passed through Wasm frames and later retrieved
/// using the `downcast` method.
#[cfg(feature = "std")]
pub fn user(error: Box<dyn Error + Send + Sync>) -> Self {
match error.downcast::<Self>() {
// The error is already a RuntimeError, we return it directly
Expand All @@ -84,6 +181,17 @@ impl RuntimeError {
}
}

#[cfg(feature = "core")]
pub fn user(error: Box<dyn CoreError + Send + Sync>) -> Self {
match error.downcast_core::<Self>() {
// 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)
Expand All @@ -93,7 +201,12 @@ impl RuntimeError {
pub fn downcast<T: Error + 'static>(self) -> Result<T, Self> {
match Arc::try_unwrap(self.inner) {
// We only try to downcast user errors
#[cfg(feature = "std")]
Ok(RuntimeErrorSource::User(err)) if err.is::<T>() => Ok(*err.downcast::<T>().unwrap()),
#[cfg(feature = "core")]
Ok(RuntimeErrorSource::User(err)) if (*err).core_is_equal::<T>() => {
Ok(*err.downcast_core::<T>().unwrap())
}
Ok(inner) => Err(Self {
inner: Arc::new(inner),
}),
Expand All @@ -104,7 +217,10 @@ impl RuntimeError {
/// Returns true if the `RuntimeError` is the same as T
pub fn is<T: Error + 'static>(&self) -> bool {
match self.inner.as_ref() {
#[cfg(feature = "std")]
RuntimeErrorSource::User(err) => err.is::<T>(),
#[cfg(feature = "core")]
RuntimeErrorSource::User(err) => (*err).core_is_equal::<T>(),
_ => false,
}
}
Expand All @@ -125,6 +241,7 @@ impl fmt::Display for RuntimeError {
}
}

#[cfg(feature = "std")]
impl std::error::Error for RuntimeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self.inner.as_ref() {
Expand Down
29 changes: 29 additions & 0 deletions lib/compiler/src/engine/trap/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,19 @@ pub struct RuntimeError {
inner: Arc<RuntimeErrorInner>,
}

pub trait CoreError: fmt::Debug + fmt::Display + core::any::Any {}

impl<T: fmt::Debug + fmt::Display + core::any::Any> CoreError for T {}

/// The source of the `RuntimeError`.
#[derive(Debug)]
enum RuntimeErrorSource {
Generic(String),
OutOfMemory,
#[cfg(feature = "std")]
User(Box<dyn Error + Send + Sync>),
#[cfg(feature = "core")]
User(Box<dyn CoreError + Send + Sync>),
Trap(TrapCode),
}

Expand Down Expand Up @@ -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<dyn Error + Send + Sync>) -> Self {
match error.downcast::<Self>() {
// The error is already a RuntimeError, we return it directly
Expand All @@ -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<dyn CoreError + Send + Sync>) -> Self {
match error.downcast::<Self>() {
// 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<usize>,
Expand Down