Skip to content

Commit

Permalink
Unpack ResumableHostError for non-resumeble calls (#1044)
Browse files Browse the repository at this point in the history
* unpack ResumableHostError for non-resumeble calls

This was an oversight in #1041.

* add doc note

* add docs to ResumableHostError fields

* apply rustfmt

* fix clippy warnings

* fix clippy issues in tests
  • Loading branch information
Robbepop committed May 23, 2024
1 parent 0ab4ab9 commit d8d1a53
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 26 deletions.
3 changes: 3 additions & 0 deletions crates/wasmi/src/engine/executor/instrs/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand Down
6 changes: 5 additions & 1 deletion crates/wasmi/src/engine/executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions crates/wasmi/src/engine/executor/stack/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions crates/wasmi/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ pub enum ErrorKind {
/// A trap as defined by the WebAssembly specification.
Host(Box<dyn HostError>),
/// 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.
Expand Down
25 changes: 11 additions & 14 deletions crates/wasmi/src/module/instantiate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ impl Module {
/// [`Func`]: [`crate::Func`]
fn extract_imports<I>(
&self,
context: &impl AsContextMut,
context: impl AsContext,
builder: &mut InstanceEntityBuilder,
externals: I,
) -> Result<(), InstantiationError>
Expand Down Expand Up @@ -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,
) {
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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);
Expand Down Expand Up @@ -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(),
));
Expand Down Expand Up @@ -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 {
Expand All @@ -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 } => {
Expand Down
24 changes: 15 additions & 9 deletions crates/wasmi/tests/e2e/v1/resumable_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use core::slice;
use wasmi::{
core::{TrapCode, ValType},
errors::ErrorKind,
AsContext,
AsContextMut,
Caller,
Config,
Engine,
Expand Down Expand Up @@ -286,21 +288,25 @@ impl AssertResumable for ResumableCall {
}
}

fn run_test(wasm_fn: Func, mut store: &mut Store<TestData>, wasm_trap: bool) {
fn run_test(wasm_fn: Func, store: &mut Store<TestData>, 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) => {
Expand Down Expand Up @@ -342,18 +348,18 @@ impl<Results> AssertResumable for TypedResumableCall<Results> {
}
}

fn run_test_typed(wasm_fn: Func, mut store: &mut Store<TestData>, wasm_trap: bool) {
fn run_test_typed(wasm_fn: Func, store: &mut Store<TestData>, wasm_trap: bool) {
let invocation = wasm_fn
.typed::<i32, i32>(&store)
.typed::<i32, i32>(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) => {
Expand Down

0 comments on commit d8d1a53

Please sign in to comment.