Skip to content

Commit 01ad907

Browse files
committed
direct host-to-host functions work too
1 parent ca486fb commit 01ad907

File tree

3 files changed

+63
-28
lines changed

3 files changed

+63
-28
lines changed

crates/wasmtime/src/runtime/func.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1527,7 +1527,7 @@ pub(crate) fn invoke_wasm_and_catch_traps<T>(
15271527
let result = crate::runtime::vm::catch_traps(store, &mut previous_runtime_state, closure);
15281528
core::mem::drop(previous_runtime_state);
15291529
store.0.call_hook(CallHook::ReturningFromWasm)?;
1530-
result.map_err(|t| crate::trap::from_runtime_box(store.0, t))
1530+
result
15311531
}
15321532
}
15331533

crates/wasmtime/src/runtime/vm/traphandlers.rs

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::runtime::store::{ExecutorRef, StoreOpaque};
2020
use crate::runtime::vm::sys::traphandlers;
2121
use crate::runtime::vm::{InterpreterRef, VMContext, VMStoreContext, f32x4, f64x2, i8x16};
2222
use crate::store::AutoAssertNoGc;
23-
use crate::{EntryStoreContext, prelude::*};
23+
use crate::{EntryStoreContext, ExnRef, prelude::*};
2424
use crate::{StoreContextMut, WasmBacktrace};
2525
use core::cell::Cell;
2626
use core::num::NonZeroU32;
@@ -415,7 +415,7 @@ pub unsafe fn catch_traps<T, F>(
415415
store: &mut StoreContextMut<'_, T>,
416416
old_state: &mut EntryStoreContext,
417417
mut closure: F,
418-
) -> Result<(), Box<Trap>>
418+
) -> Result<()>
419419
where
420420
F: FnMut(NonNull<VMContext>, Option<InterpreterRef<'_>>) -> bool,
421421
{
@@ -461,16 +461,40 @@ where
461461
},
462462
});
463463

464-
return match result {
464+
match result {
465465
Ok(x) => Ok(x),
466-
Err((UnwindReason::Trap(reason), backtrace, coredumpstack)) => Err(Box::new(Trap {
467-
reason,
466+
Err(UnwindState::UnwindToHost {
467+
reason: UnwindReason::Trap(reason),
468468
backtrace,
469-
coredumpstack,
470-
})),
469+
coredump_stack,
470+
}) => Err(crate::trap::from_runtime_box(
471+
store.0,
472+
Box::new(Trap {
473+
reason,
474+
backtrace,
475+
coredumpstack: coredump_stack,
476+
}),
477+
)),
471478
#[cfg(all(feature = "std", panic = "unwind"))]
472-
Err((UnwindReason::Panic(panic), _, _)) => std::panic::resume_unwind(panic),
473-
};
479+
Err(UnwindState::UnwindToHost {
480+
reason: UnwindReason::Panic(panic),
481+
..
482+
}) => std::panic::resume_unwind(panic),
483+
#[cfg(feature = "gc")]
484+
Err(UnwindState::ThrowException) => {
485+
// We may have gotten here if a host function (created via
486+
// `Func::new`) was called directly with `Func::call` and
487+
// returned an exception: in that case, no trampoline to
488+
// call `unwind()` exists, so we have to fetch the pending
489+
// exception explicitly here.
490+
let exnref = store.0.take_pending_exception();
491+
let exnref = ExnRef::from_raw(store, exnref.as_gc_ref().as_raw_u32()).unwrap();
492+
Err(exnref.into())
493+
}
494+
Err(UnwindState::None) => {
495+
unreachable!("We should not have gotten an error with no unwind state");
496+
}
497+
}
474498
}
475499

476500
// Module to hide visibility of the `CallThreadState::prev` field and force
@@ -719,32 +743,18 @@ where
719743

720744
impl CallThreadState {
721745
#[inline]
722-
fn with(
723-
mut self,
724-
closure: impl FnOnce(&CallThreadState) -> bool,
725-
) -> Result<(), (UnwindReason, Option<Backtrace>, Option<CoreDumpStack>)> {
746+
fn with(mut self, closure: impl FnOnce(&CallThreadState) -> bool) -> Result<(), UnwindState> {
726747
let succeeded = tls::set(&mut self, |me| closure(me));
727748
if succeeded {
728749
Ok(())
729750
} else {
730-
Err(self.read_unwind_to_host())
751+
Err(self.read_unwind())
731752
}
732753
}
733754

734755
#[cold]
735-
fn read_unwind_to_host(&self) -> (UnwindReason, Option<Backtrace>, Option<CoreDumpStack>) {
736-
match self.unwind.replace(UnwindState::None) {
737-
UnwindState::UnwindToHost {
738-
reason,
739-
backtrace,
740-
coredump_stack,
741-
} => (reason, backtrace, coredump_stack),
742-
#[cfg(feature = "gc")]
743-
UnwindState::ThrowException => {
744-
panic!("Exception should have been resolved by unwind() before reaching caller")
745-
}
746-
UnwindState::None => panic!("No unwind state with erroneous return code"),
747-
}
756+
fn read_unwind(&self) -> UnwindState {
757+
self.unwind.replace(UnwindState::None)
748758
}
749759

750760
/// Records the unwind information provided within this `CallThreadState`,

tests/all/exceptions.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,28 @@ fn exception_from_host() -> Result<()> {
168168

169169
Ok(())
170170
}
171+
172+
#[test]
173+
fn exception_across_no_wasm() -> Result<()> {
174+
let mut store = gc_and_exceptions_store()?;
175+
let engine = store.engine();
176+
177+
let functy = FuncType::new(&engine, [ValType::I32], []);
178+
let tagty = TagType::new(functy.clone());
179+
let exnty = ExnType::from_tag_type(&tagty).unwrap();
180+
let exnpre = ExnRefPre::new(&mut store, exnty);
181+
let tag = Tag::new(&mut store, &tagty)?;
182+
let extfunc = Func::new(&mut store, functy, move |caller, args, _rets| {
183+
let exn = ExnRef::new(caller, &exnpre, &tag, &[Val::I32(args[0].unwrap_i32())]).unwrap();
184+
Err(exn.into())
185+
});
186+
let mut results = [];
187+
let result = extfunc.call(&mut store, &[Val::I32(42)], &mut results[..]);
188+
assert!(result.is_err());
189+
let exn = result.unwrap_err().downcast::<Rooted<ExnRef>>().unwrap();
190+
let exntag = exn.tag(&mut store)?;
191+
assert!(Tag::eq(&exntag, &tag, &store));
192+
assert_eq!(exn.field(&mut store, 0)?.unwrap_i32(), 42);
193+
194+
Ok(())
195+
}

0 commit comments

Comments
 (0)