diff --git a/crates/wasmi/src/engine/executor/instrs/call.rs b/crates/wasmi/src/engine/executor/instrs/call.rs index 3c5b8ec093..50b94a72d3 100644 --- a/crates/wasmi/src/engine/executor/instrs/call.rs +++ b/crates/wasmi/src/engine/executor/instrs/call.rs @@ -75,8 +75,11 @@ pub enum CallKind { /// Error returned from a called host function in a resumable state. #[derive(Debug)] pub struct ResumableHostError { + /// The error returned by the called host function. host_error: Error, + /// The host function that returned the error. host_func: Func, + /// The result registers of the caller of the host function. caller_results: RegisterSpan, } diff --git a/crates/wasmi/src/engine/executor/mod.rs b/crates/wasmi/src/engine/executor/mod.rs index dfd04c2067..db19778f72 100644 --- a/crates/wasmi/src/engine/executor/mod.rs +++ b/crates/wasmi/src/engine/executor/mod.rs @@ -51,7 +51,11 @@ impl EngineInner { let res = self.res.read(); let mut stack = self.stacks.lock().reuse_or_new(); let results = EngineExecutor::new(&res, &mut stack) - .execute_root_func(ctx.store, func, params, results); + .execute_root_func(ctx.store, func, params, results) + .map_err(|error| match error.into_resumable() { + Ok(error) => error.into_error(), + Err(error) => error, + }); self.stacks.lock().recycle(stack); results } diff --git a/crates/wasmi/src/engine/executor/stack/values.rs b/crates/wasmi/src/engine/executor/stack/values.rs index 03501c861c..ac4e473977 100644 --- a/crates/wasmi/src/engine/executor/stack/values.rs +++ b/crates/wasmi/src/engine/executor/stack/values.rs @@ -309,9 +309,9 @@ impl ValueStack { /// # Safety /// /// - This invalidates all [`FrameRegisters`] within the range `from..` and the caller has to - /// make sure to properly reinstantiate all those pointers after this operation. + /// make sure to properly reinstantiate all those pointers after this operation. /// - This also invalidates all [`FrameValueStackOffset`] and [`BaseValueStackOffset`] indices - /// within the range `from..`. + /// within the range `from..`. #[inline(always)] pub fn drain(&mut self, from: FrameValueStackOffset, to: FrameValueStackOffset) -> usize { debug_assert!(from <= to); diff --git a/crates/wasmi/src/error.rs b/crates/wasmi/src/error.rs index dd14a1c497..541e0aa75c 100644 --- a/crates/wasmi/src/error.rs +++ b/crates/wasmi/src/error.rs @@ -159,6 +159,12 @@ pub enum ErrorKind { /// A trap as defined by the WebAssembly specification. Host(Box), /// An error stemming from a host function call with resumable state information. + /// + /// # Note + /// + /// This variant is meant for internal uses only in order to store data necessary + /// to resume a call after a host function returned an error. This should never + /// actually reach user code thus we hide its documentation. #[doc(hidden)] ResumableHost(ResumableHostError), /// A global variable error. diff --git a/crates/wasmi/src/module/instantiate/mod.rs b/crates/wasmi/src/module/instantiate/mod.rs index 9a1652afab..50f56d34d3 100644 --- a/crates/wasmi/src/module/instantiate/mod.rs +++ b/crates/wasmi/src/module/instantiate/mod.rs @@ -93,7 +93,7 @@ impl Module { /// [`Func`]: [`crate::Func`] fn extract_imports( &self, - context: &impl AsContextMut, + context: impl AsContext, builder: &mut InstanceEntityBuilder, externals: I, ) -> Result<(), InstantiationError> @@ -166,7 +166,7 @@ impl Module { /// [`Func`]: [`crate::Func`] fn extract_functions( &self, - context: &mut impl AsContextMut, + mut context: impl AsContextMut, builder: &mut InstanceEntityBuilder, handle: Instance, ) { @@ -188,7 +188,7 @@ impl Module { /// [`Store`]: struct.Store.html fn extract_tables( &self, - context: &mut impl AsContextMut, + mut context: impl AsContextMut, builder: &mut InstanceEntityBuilder, ) -> Result<(), InstantiationError> { context @@ -210,7 +210,7 @@ impl Module { /// [`Store`]: struct.Store.html fn extract_memories( &self, - context: &mut impl AsContextMut, + mut context: impl AsContextMut, builder: &mut InstanceEntityBuilder, ) -> Result<(), MemoryError> { context @@ -229,11 +229,7 @@ impl Module { /// This also stores [`Global`] references into the [`Instance`] under construction. /// /// [`Store`]: struct.Store.html - fn extract_globals( - &self, - context: &mut impl AsContextMut, - builder: &mut InstanceEntityBuilder, - ) { + fn extract_globals(&self, mut context: impl AsContextMut, builder: &mut InstanceEntityBuilder) { for (global_type, global_init) in self.internal_globals() { let value_type = global_type.content(); let init_value = Self::eval_init_expr(context.as_context_mut(), builder, global_init); @@ -300,14 +296,14 @@ impl Module { /// Initializes the [`Instance`] tables with the Wasm element segments of the [`Module`]. fn initialize_table_elements( &self, - mut context: &mut impl AsContextMut, + mut context: impl AsContextMut, builder: &mut InstanceEntityBuilder, ) -> Result<(), Error> { for segment in &self.header.inner.element_segments[..] { let element = ElementSegment::new(context.as_context_mut(), segment); if let ElementSegmentKind::Active(active) = segment.kind() { let dst_index = u32::from(Self::eval_init_expr( - &mut *context, + context.as_context(), builder, active.offset(), )); @@ -347,7 +343,7 @@ impl Module { /// Initializes the [`Instance`] linear memories with the Wasm data segments of the [`Module`]. fn initialize_memory_data( &self, - context: &mut impl AsContextMut, + mut context: impl AsContextMut, builder: &mut InstanceEntityBuilder, ) -> Result<(), Error> { for segment in &self.data_segments { @@ -358,9 +354,10 @@ impl Module { bytes, } => { let offset = - u32::from(Self::eval_init_expr(&mut *context, builder, offset)) as usize; + u32::from(Self::eval_init_expr(context.as_context(), builder, offset)) + as usize; let memory = builder.get_memory(memory_index.into_u32()); - memory.write(&mut *context, offset, bytes)?; + memory.write(context.as_context_mut(), offset, bytes)?; DataSegment::new_active(context.as_context_mut()) } InitDataSegment::Passive { bytes } => { diff --git a/crates/wasmi/tests/e2e/v1/resumable_call.rs b/crates/wasmi/tests/e2e/v1/resumable_call.rs index 69fe2390e2..eda21a1ab6 100644 --- a/crates/wasmi/tests/e2e/v1/resumable_call.rs +++ b/crates/wasmi/tests/e2e/v1/resumable_call.rs @@ -4,6 +4,8 @@ use core::slice; use wasmi::{ core::{TrapCode, ValType}, errors::ErrorKind, + AsContext, + AsContextMut, Caller, Config, Engine, @@ -286,21 +288,25 @@ impl AssertResumable for ResumableCall { } } -fn run_test(wasm_fn: Func, mut store: &mut Store, wasm_trap: bool) { +fn run_test(wasm_fn: Func, store: &mut Store, wasm_trap: bool) { let mut results = Val::I32(0); let invocation = wasm_fn .call_resumable( - &mut store, + store.as_context_mut(), &[Val::I32(wasm_trap as i32)], slice::from_mut(&mut results), ) .unwrap() .assert_resumable(store, 10, &[ValType::I32]); let invocation = invocation - .resume(&mut store, &[Val::I32(2)], slice::from_mut(&mut results)) + .resume( + store.as_context_mut(), + &[Val::I32(2)], + slice::from_mut(&mut results), + ) .unwrap() .assert_resumable(store, 20, &[ValType::I32]); - let call = invocation.resume(&mut store, &[Val::I32(3)], slice::from_mut(&mut results)); + let call = invocation.resume(store, &[Val::I32(3)], slice::from_mut(&mut results)); if wasm_trap { match call.unwrap_err().kind() { ErrorKind::TrapCode(trap) => { @@ -342,18 +348,18 @@ impl AssertResumable for TypedResumableCall { } } -fn run_test_typed(wasm_fn: Func, mut store: &mut Store, wasm_trap: bool) { +fn run_test_typed(wasm_fn: Func, store: &mut Store, wasm_trap: bool) { let invocation = wasm_fn - .typed::(&store) + .typed::(store.as_context()) .unwrap() - .call_resumable(&mut store, wasm_trap as i32) + .call_resumable(store.as_context_mut(), wasm_trap as i32) .unwrap() .assert_resumable(store, 10, &[ValType::I32]); let invocation = invocation - .resume(&mut store, &[Val::I32(2)]) + .resume(store.as_context_mut(), &[Val::I32(2)]) .unwrap() .assert_resumable(store, 20, &[ValType::I32]); - let call = invocation.resume(&mut store, &[Val::I32(3)]); + let call = invocation.resume(store, &[Val::I32(3)]); if wasm_trap { match call.unwrap_err().kind() { ErrorKind::TrapCode(trap) => {