mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-14 17:31:20 +00:00
Fix new RuntimeError implementation for the Singlepass backend
This commit is contained in:
@ -213,27 +213,6 @@ impl std::error::Error for RuntimeError {}
|
||||
|
||||
*/
|
||||
|
||||
/// An `InternalError` is an error that happened inside of Wasmer and is a
|
||||
/// catch-all for errors that would otherwise be returned as
|
||||
/// `RuntimeError(Box::new(<string>))`.
|
||||
///
|
||||
/// This type provides greater visibility into the kinds of things that may fail
|
||||
/// and improves the ability of users to handle them, though these errors may be
|
||||
/// extremely rare and impossible to handle.
|
||||
#[derive(Debug)]
|
||||
pub enum RuntimeError {
|
||||
/// When an invoke returns an error
|
||||
InvokeError(InvokeError),
|
||||
/// A metering triggered error value.
|
||||
///
|
||||
/// An error of this type indicates that it was returned by the metering system.
|
||||
Metering(Box<dyn Any + Send>),
|
||||
/// A user triggered error value.
|
||||
///
|
||||
/// An error returned from a host function.
|
||||
User(Box<dyn Any + Send>),
|
||||
}
|
||||
|
||||
/// TODO:
|
||||
#[derive(Debug)]
|
||||
pub enum InvokeError {
|
||||
@ -278,14 +257,39 @@ impl From<InvokeError> for RuntimeError {
|
||||
}
|
||||
}
|
||||
|
||||
//impl std::error::Error for InvokeError {}
|
||||
|
||||
/// An `InternalError` is an error that happened inside of Wasmer and is a
|
||||
/// catch-all for errors that would otherwise be returned as
|
||||
/// `RuntimeError(Box::new(<string>))`.
|
||||
///
|
||||
/// This type provides greater visibility into the kinds of things that may fail
|
||||
/// and improves the ability of users to handle them, though these errors may be
|
||||
/// extremely rare and impossible to handle.
|
||||
#[derive(Debug)]
|
||||
pub enum RuntimeError {
|
||||
/// When an invoke returns an error
|
||||
InvokeError(InvokeError),
|
||||
/// A metering triggered error value.
|
||||
///
|
||||
/// An error of this type indicates that it was returned by the metering system.
|
||||
Metering(Box<dyn Any + Send>),
|
||||
/// A frozen state of Wasm used to pause and resume execution. Not strictly an
|
||||
/// "error", but this happens while executing and therefore is a `RuntimeError`
|
||||
/// from the persective of the caller that expected the code to fully execute.
|
||||
InstanceImage(Box<dyn Any + Send>),
|
||||
/// A user triggered error value.
|
||||
///
|
||||
/// An error returned from a host function.
|
||||
User(Box<dyn Any + Send>),
|
||||
}
|
||||
|
||||
impl PartialEq for RuntimeError {
|
||||
fn eq(&self, _other: &RuntimeError) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
//impl std::error::Error for InvokeError {}
|
||||
|
||||
impl std::error::Error for RuntimeError {}
|
||||
|
||||
impl std::fmt::Display for RuntimeError {
|
||||
@ -294,6 +298,10 @@ impl std::fmt::Display for RuntimeError {
|
||||
// TODO: update invoke error formatting
|
||||
RuntimeError::InvokeError(_) => write!(f, "Error when calling invoke"),
|
||||
RuntimeError::Metering(_) => write!(f, "unknown metering error type"),
|
||||
RuntimeError::InstanceImage(_) => write!(
|
||||
f,
|
||||
"Execution interrupted by a suspend signal: instance image returned"
|
||||
),
|
||||
RuntimeError::User(user_error) => {
|
||||
write!(f, "User supplied error: ")?;
|
||||
if let Some(s) = user_error.downcast_ref::<String>() {
|
||||
|
@ -30,7 +30,7 @@ pub mod raw {
|
||||
use crate::codegen::{BreakpointInfo, BreakpointMap};
|
||||
use crate::error::{InvokeError, RuntimeError};
|
||||
use crate::state::x64::{build_instance_image, read_stack, X64Register, GPR};
|
||||
use crate::state::{CodeVersion, ExecutionStateImage, InstanceImage};
|
||||
use crate::state::{CodeVersion, ExecutionStateImage};
|
||||
use crate::vm;
|
||||
use libc::{mmap, mprotect, siginfo_t, MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE};
|
||||
use nix::sys::signal::{
|
||||
@ -61,7 +61,7 @@ type SetJmpBuffer = [i32; SETJMP_BUFFER_LEN];
|
||||
struct UnwindInfo {
|
||||
jmpbuf: SetJmpBuffer, // in
|
||||
breakpoints: Option<BreakpointMap>,
|
||||
payload: Option<RuntimeError>, // out
|
||||
payload: Option<Box<RuntimeError>>, // out
|
||||
}
|
||||
|
||||
/// A store for boundary register preservation.
|
||||
@ -195,7 +195,7 @@ pub unsafe fn catch_unsafe_unwind<R, F: FnOnce() -> R>(
|
||||
// error
|
||||
let ret = (*unwind).as_mut().unwrap().payload.take().unwrap();
|
||||
*unwind = old;
|
||||
Err(ret)
|
||||
Err(*ret)
|
||||
} else {
|
||||
let ret = f();
|
||||
// implicit control flow to the error case...
|
||||
@ -205,7 +205,7 @@ pub unsafe fn catch_unsafe_unwind<R, F: FnOnce() -> R>(
|
||||
}
|
||||
|
||||
/// Begins an unsafe unwind.
|
||||
pub unsafe fn begin_unsafe_unwind(e: RuntimeError) -> ! {
|
||||
pub unsafe fn begin_unsafe_unwind(e: Box<RuntimeError>) -> ! {
|
||||
let unwind = UNWIND.with(|x| x.get());
|
||||
let inner = (*unwind)
|
||||
.as_mut()
|
||||
@ -279,7 +279,11 @@ extern "C" fn signal_trap_handler(
|
||||
static ARCH: Architecture = Architecture::Aarch64;
|
||||
|
||||
let mut should_unwind = false;
|
||||
let mut unwind_result: Option<Result<InstanceImage, RuntimeError>> = None;
|
||||
let mut unwind_result: Option<Box<RuntimeError>> = None;
|
||||
let get_unwind_result = |uw_result: Option<Box<RuntimeError>>| -> Box<RuntimeError> {
|
||||
uw_result
|
||||
.unwrap_or_else(|| Box::new(RuntimeError::InvokeError(InvokeError::FailedWithNoError)))
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let fault = get_fault_info(siginfo as _, ucontext);
|
||||
@ -313,7 +317,7 @@ extern "C" fn signal_trap_handler(
|
||||
if let Some(Ok(())) = out {
|
||||
} else if let Some(Err(e)) = out {
|
||||
should_unwind = true;
|
||||
unwind_result = Some(Err(e));
|
||||
unwind_result = Some(Box::new(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -328,7 +332,7 @@ extern "C" fn signal_trap_handler(
|
||||
})
|
||||
});
|
||||
if should_unwind {
|
||||
begin_unsafe_unwind(unwind_result.unwrap().unwrap_err());
|
||||
begin_unsafe_unwind(get_unwind_result(unwind_result));
|
||||
}
|
||||
if early_return {
|
||||
return;
|
||||
@ -357,7 +361,7 @@ extern "C" fn signal_trap_handler(
|
||||
return false;
|
||||
}
|
||||
Some(Err(e)) => {
|
||||
unwind_result = Some(Err(e));
|
||||
unwind_result = Some(Box::new(e));
|
||||
return true;
|
||||
}
|
||||
None => {}
|
||||
@ -389,7 +393,7 @@ extern "C" fn signal_trap_handler(
|
||||
if is_suspend_signal {
|
||||
// If this is a suspend signal, we parse the runtime state and return the resulting image.
|
||||
let image = build_instance_image(ctx, es_image);
|
||||
unwind_result = Some(Ok(image));
|
||||
unwind_result = Some(Box::new(RuntimeError::InstanceImage(Box::new(image))));
|
||||
} else {
|
||||
// Otherwise, this is a real exception and we just throw it to the caller.
|
||||
if !es_image.frames.is_empty() {
|
||||
@ -417,11 +421,12 @@ extern "C" fn signal_trap_handler(
|
||||
None
|
||||
});
|
||||
if let Some(code) = exc_code {
|
||||
unwind_result = Some(Err(RuntimeError::InvokeError(InvokeError::TrapCode {
|
||||
code,
|
||||
// TODO:
|
||||
srcloc: 0,
|
||||
})));
|
||||
unwind_result =
|
||||
Some(Box::new(RuntimeError::InvokeError(InvokeError::TrapCode {
|
||||
code,
|
||||
// TODO:
|
||||
srcloc: 0,
|
||||
})));
|
||||
}
|
||||
}
|
||||
|
||||
@ -429,7 +434,7 @@ extern "C" fn signal_trap_handler(
|
||||
});
|
||||
|
||||
if should_unwind {
|
||||
begin_unsafe_unwind(unwind_result.unwrap().unwrap_err());
|
||||
begin_unsafe_unwind(get_unwind_result(unwind_result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ pub type Invoke = unsafe extern "C" fn(
|
||||
func: NonNull<vm::Func>,
|
||||
args: *const u64,
|
||||
rets: *mut u64,
|
||||
error_out: *mut Option<InvokeError>,
|
||||
error_out: *mut Option<RuntimeError>,
|
||||
extra: Option<NonNull<c_void>>,
|
||||
) -> bool;
|
||||
|
||||
|
Reference in New Issue
Block a user