Skip to content

Commit

Permalink
feat!: propagate errors from linked modules (#388)
Browse files Browse the repository at this point in the history
* propagate errors

* pregare for merge

* support new interface in js backend

* use wasmer-it from crates.io

* fix marine-js tests + update aquavm version for tests
  • Loading branch information
ValeryAntopol authored Nov 3, 2023
1 parent 977e4a8 commit a94494b
Show file tree
Hide file tree
Showing 22 changed files with 222 additions and 244 deletions.
10 changes: 6 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ marine-min-it-version = { path = "../crates/min-it-version", version = "0.3.0"
marine-wasm-backend-traits = {path = "../crates/wasm-backend-traits", version = "0.3.0"}
marine-wasmtime-backend = { path = "../crates/wasmtime-backend", version = "0.3.0", optional = true}

wasmer-it = { package = "wasmer-interface-types-fl", version = "0.26.1" }
it-lilo = "0.5.1"
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.27.0" }
it-lilo = "0.6.0"
it-memory-traits = "0.4.0"
bytesize = "1.2.0"

Expand Down
9 changes: 7 additions & 2 deletions core/src/host_imports/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,13 @@ pub(crate) fn create_host_import_func<WB: WasmBackend>(

let func = move |call_context: <WB as WasmBackend>::ImportCallContext<'_>,
inputs: &[WValue]|
-> Vec<WValue> {
call_host_import(call_context, inputs, &descriptor, record_types.clone())
-> anyhow::Result<Vec<WValue>> {
Ok(call_host_import(
call_context,
inputs,
&descriptor,
record_types.clone(),
))
};

<WB as WasmBackend>::HostFunction::new_with_caller(
Expand Down
4 changes: 2 additions & 2 deletions core/src/module/exports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub(crate) struct ITExport {
name: String,
arguments: Vec<IFunctionArg>,
outputs: Vec<IType>,
function: fn(arguments: &[IValue]) -> Result<Vec<IValue>, ()>,
function: fn(arguments: &[IValue]) -> Result<Vec<IValue>, anyhow::Error>,
}

impl ITExport {
Expand Down Expand Up @@ -63,7 +63,7 @@ impl wasm::structures::Export for ITExport {
&self.outputs
}

fn call(&self, arguments: &[IValue]) -> Result<Vec<IValue>, ()> {
fn call(&self, arguments: &[IValue]) -> Result<Vec<IValue>, anyhow::Error> {
(self.function)(arguments)
}
}
33 changes: 21 additions & 12 deletions core/src/module/marine_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,10 @@ impl<WB: WasmBackend> MModule<WB> {
raw_import: F,
) -> <WB as WasmBackend>::HostFunction
where
F: for<'c> Fn(<WB as WasmBackend>::ImportCallContext<'c>, &[WValue]) -> Vec<WValue>
F: for<'c> Fn(
<WB as WasmBackend>::ImportCallContext<'c>,
&[WValue],
) -> anyhow::Result<Vec<WValue>>
+ Sync
+ Send
+ 'static,
Expand All @@ -330,13 +333,16 @@ impl<WB: WasmBackend> MModule<WB> {
interpreter: ITInterpreter<WB>,
import_namespace: String,
import_name: String,
) -> impl for<'c> Fn(<WB as WasmBackend>::ImportCallContext<'c>, &[WValue]) -> Vec<WValue>
) -> impl for<'c> Fn(
<WB as WasmBackend>::ImportCallContext<'c>,
&[WValue],
) -> anyhow::Result<Vec<WValue>>
+ Sync
+ Send
+ 'static {
move |mut ctx: <WB as WasmBackend>::ImportCallContext<'_>,
inputs: &[WValue]|
-> Vec<WValue> {
-> anyhow::Result<Vec<WValue>> {
use wasmer_it::interpreter::stack::Stackable;

use super::type_converters::wval_to_ival;
Expand All @@ -354,11 +360,16 @@ impl<WB: WasmBackend> MModule<WB> {
let wit_inputs = inputs.iter().map(wval_to_ival).collect::<Vec<_>>();
let outputs = unsafe {
// error here will be propagated by the special error instruction
interpreter.run(
&wit_inputs,
Arc::make_mut(&mut wit_instance_callable.assume_init()),
&mut ctx.as_context_mut(),
)
interpreter
.run(
&wit_inputs,
Arc::make_mut(&mut wit_instance_callable.assume_init()),
&mut ctx.as_context_mut(),
)
.map_err(|e| {
log::error!("interpreter got error {e}");
anyhow::anyhow!(e)
})?
};

log::trace!(
Expand All @@ -368,13 +379,11 @@ impl<WB: WasmBackend> MModule<WB> {
);

// TODO: optimize by prevent copying stack values
outputs
.map_err(|e| log::error!("interpreter got error {e}"))
.unwrap_or_default()
Ok(outputs
.as_slice()
.iter()
.map(ival_to_wval)
.collect::<Vec<_>>()
.collect::<Vec<_>>())
}
}

Expand Down
8 changes: 5 additions & 3 deletions core/src/module/wit_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ use marine_wasm_backend_traits::ExportFunction;

use wasmer_it::interpreter::wasm;

use anyhow::anyhow;

use std::sync::Arc;

#[derive(Clone)]
Expand Down Expand Up @@ -139,7 +141,7 @@ impl<WB: WasmBackend> wasm::structures::LocalImport<DelayedContextLifetime<WB>>
&self,
store: &mut <WB as WasmBackend>::ContextMut<'_>,
arguments: &[IValue],
) -> std::result::Result<Vec<IValue>, ()> {
) -> std::result::Result<Vec<IValue>, anyhow::Error> {
use super::type_converters::wval_to_ival;
use super::type_converters::ival_to_wval;
match &self.inner {
Expand All @@ -153,11 +155,11 @@ impl<WB: WasmBackend> wasm::structures::LocalImport<DelayedContextLifetime<WB>>
.collect::<Vec<WValue>>()
.as_slice(),
)
.map_err(|_| ())
.map_err(|e| anyhow!(e))
.map(|results| results.iter().map(wval_to_ival).collect()),
WITFunctionInner::Import { callable, .. } => Arc::make_mut(&mut callable.clone())
.call(store, arguments)
.map_err(|_| ()),
.map_err(|e| anyhow!(e)),
}
}
}
4 changes: 2 additions & 2 deletions crates/it-generator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ path = "src/lib.rs"
marine-it-parser = { path = "../it-parser", version = "0.13.0" }
marine-macro-impl = "0.7.1"

wasmer-it = { package = "wasmer-interface-types-fl", version = "0.26.1" }
it-lilo = "0.5.1"
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.27.0" }
it-lilo = "0.6.0"

thiserror = "1.0.50"
walrus = "0.20.1"
Expand Down
2 changes: 1 addition & 1 deletion crates/it-interfaces/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ name = "marine_it_interfaces"
path = "src/lib.rs"

[dependencies]
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.26.1" }
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.27.0" }
multimap = "0.8.3"
2 changes: 1 addition & 1 deletion crates/it-json-serde/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ name = "it_json_serde"
path = "src/lib.rs"

[dependencies]
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.26.1" }
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.27.0" }

serde = { version = "1.0.147", features = ["derive"] }
serde_json = "1.0.107"
Expand Down
2 changes: 1 addition & 1 deletion crates/it-parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ marine-wasm-backend-traits = { path = "../wasm-backend-traits", version = "0.3.0

anyhow = "1.0.75"
walrus = "0.20.1"
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.26.1" }
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.27.0" }
nom = "7.1"

itertools = "0.10.5"
Expand Down
23 changes: 15 additions & 8 deletions crates/js-backend/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ impl HostImportFunction {
impl HostFunction<JsWasmBackend> for HostImportFunction {
fn new<F>(store: &mut impl AsContextMut<JsWasmBackend>, signature: FuncSig, func: F) -> Self
where
F: for<'c> Fn(&'c [WValue]) -> Vec<WValue> + Sync + Send + 'static,
F: for<'c> Fn(&'c [WValue]) -> anyhow::Result<Vec<WValue>> + Sync + Send + 'static,
{
let with_caller = move |_, args: &'_ [WValue]| func(args);
Self::new_with_caller(store, signature, with_caller)
Expand All @@ -160,7 +160,10 @@ impl HostFunction<JsWasmBackend> for HostImportFunction {
func: F,
) -> Self
where
F: for<'c> Fn(JsImportCallContext, &[WValue]) -> Vec<WValue> + Sync + Send + 'static,
F: for<'c> Fn(JsImportCallContext, &[WValue]) -> anyhow::Result<Vec<WValue>>
+ Sync
+ Send
+ 'static,
{
// Safety: JsStoreInner is stored inside a Box and the Store is required by wasm-backend traits contract
// to be valid for function execution. So it is safe to capture this ptr into closure and deference there
Expand Down Expand Up @@ -197,7 +200,10 @@ fn wrap_raw_host_fn<F>(
raw_host_function: F,
) -> Box<dyn FnMut(&Array) -> Array>
where
F: for<'c> Fn(JsImportCallContext, &[WValue]) -> Vec<WValue> + Sync + Send + 'static,
F: for<'c> Fn(JsImportCallContext, &[WValue]) -> anyhow::Result<Vec<WValue>>
+ Sync
+ Send
+ 'static,
{
let func = move |args: &js_sys::Array| -> js_sys::Array {
log::debug!(
Expand All @@ -216,7 +222,8 @@ where
};

let args = wval_array_from_js_array(args, signature.params().iter());
let result = raw_host_function(caller, &args);
let result = raw_host_function(caller, &args).unwrap_throw(); // TODO is it right?

js_array_from_wval_array(&result)
};

Expand Down Expand Up @@ -266,10 +273,10 @@ macro_rules! impl_func_construction {
fn [< new_typed_with_env_ $num >] <F>(mut ctx: JsContextMut<'_>, func: F) -> HostImportFunction
where F: Fn(JsImportCallContext, $(replace_with!($args -> i32),)*) + Send + Sync + 'static {

let func = move |caller: JsImportCallContext, args: &[WValue]| -> Vec<WValue> {
let func = move |caller: JsImportCallContext, args: &[WValue]| -> anyhow::Result<Vec<WValue>> {
let [$($args,)*] = args else { todo!() }; // TODO: Safety: explain why it will never fire
func(caller, $(wval_to_i32($args),)*);
vec![]
Ok(vec![])
};

let arg_ty = vec![WType::I32; $num];
Expand All @@ -282,10 +289,10 @@ macro_rules! impl_func_construction {
fn [< new_typed_with_env_ $num _r>] <F>(mut ctx: JsContextMut<'_>, func: F) -> HostImportFunction
where F: Fn(JsImportCallContext, $(replace_with!($args -> i32),)*) -> i32 + Send + Sync + 'static {

let func = move |caller: JsImportCallContext, args: &[WValue]| -> Vec<WValue> {
let func = move |caller: JsImportCallContext, args: &[WValue]| -> anyhow::Result<Vec<WValue>> {
let [$($args,)*] = args else { panic!("args do not match signature") }; // Safety: signature should b
let res = func(caller, $(wval_to_i32(&$args),)*);
vec![WValue::I32(res)]
Ok(vec![WValue::I32(res)])
};

let arg_ty = vec![WType::I32; $num];
Expand Down
2 changes: 1 addition & 1 deletion crates/module-interface/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ marine-it-interfaces = { path = "../it-interfaces", version = "0.8.1" }

anyhow = "1.0.75"
walrus = "0.20.1"
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.26.1" }
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.27.0" }
nom = "7.1.3"

itertools = "0.10.5"
Expand Down
2 changes: 1 addition & 1 deletion crates/wasm-backend-traits/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ license = "Apache-2.0"
edition = "2021"

[dependencies]
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.26.1" }
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.27.0" }
it-memory-traits = "0.4.0"

thiserror = "1.0.50"
Expand Down
4 changes: 2 additions & 2 deletions crates/wasm-backend-traits/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ pub enum RuntimeError {
#[error("Unsupported type encountered: {0}")]
UnsupportedType(WType),

#[error(transparent)]
#[error("Trap occurred: {0}")]
Trap(anyhow::Error),

#[error(transparent)]
Expand All @@ -86,7 +86,7 @@ pub enum RuntimeError {
#[error("A function returned invalid number of results: expected {expected}, got {actual}")]
IncorrectResultsNumber { expected: usize, actual: usize },

#[error(transparent)]
#[error("Unrecognized error: {0}")]
Other(anyhow::Error),
}

Expand Down
7 changes: 5 additions & 2 deletions crates/wasm-backend-traits/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@ pub trait HostFunction<WB: WasmBackend>: Send + Sync + Clone {
/// The signature check is performed at runtime.
fn new<F>(store: &mut impl AsContextMut<WB>, sig: FuncSig, func: F) -> Self
where
F: for<'c> Fn(&[WValue]) -> Vec<WValue> + Sync + Send + 'static;
F: for<'c> Fn(&[WValue]) -> anyhow::Result<Vec<WValue>> + Sync + Send + 'static;

/// Creates a new function with dynamic signature that needs a context.
fn new_with_caller<F>(store: &mut impl AsContextMut<WB>, sig: FuncSig, func: F) -> Self
where
F: for<'c> Fn(<WB as WasmBackend>::ImportCallContext<'c>, &[WValue]) -> Vec<WValue>
F: for<'c> Fn(
<WB as WasmBackend>::ImportCallContext<'c>,
&[WValue],
) -> anyhow::Result<Vec<WValue>>
+ Sync
+ Send
+ 'static;
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmtime-backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ license = "Apache-2.0"

[dependencies]
marine-wasm-backend-traits = {path = "../wasm-backend-traits", version = "0.3.0"}
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.26.1" }
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.27.0" }
it-memory-traits = "0.4.0"

# all default features except async
Expand Down
8 changes: 4 additions & 4 deletions crates/wasmtime-backend/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ pub struct WasmtimeFunction {
impl HostFunction<WasmtimeWasmBackend> for WasmtimeFunction {
fn new<F>(store: &mut impl AsContextMut<WasmtimeWasmBackend>, sig: FuncSig, func: F) -> Self
where
F: for<'c> Fn(&[WValue]) -> Vec<WValue> + Sync + Send + 'static,
F: for<'c> Fn(&[WValue]) -> anyhow::Result<Vec<WValue>> + Sync + Send + 'static,
{
let ty = sig_to_fn_ty(&sig);
let func = move |_: wasmtime::Caller<'_, StoreState>,
args: &[wasmtime::Val],
results_out: &mut [wasmtime::Val]|
-> Result<(), anyhow::Error> {
let args = process_func_args(args).map_err(|e| anyhow!(e))?; // TODO move earlier
let results = func(&args);
let results = func(&args)?;
process_func_results(&results, results_out).map_err(|e| anyhow!(e))
};

Expand All @@ -63,7 +63,7 @@ impl HostFunction<WasmtimeWasmBackend> for WasmtimeFunction {
F: for<'c> Fn(
<WasmtimeWasmBackend as WasmBackend>::ImportCallContext<'c>,
&[WValue],
) -> Vec<WValue>
) -> anyhow::Result<Vec<WValue>>
+ Sync
+ Send
+ 'static,
Expand All @@ -76,7 +76,7 @@ impl HostFunction<WasmtimeWasmBackend> for WasmtimeFunction {
-> Result<(), anyhow::Error> {
let caller = WasmtimeImportCallContext { inner: caller };
let args = process_func_args(args).map_err(|e| anyhow!(e))?;
let results = func(caller, &args);
let results = func(caller, &args)?;
process_func_results(&results, results_out).map_err(|e| anyhow!(e))
};

Expand Down
8 changes: 4 additions & 4 deletions marine-js/npm-package/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit a94494b

Please sign in to comment.