//! Throw action computation (handler search).1//!2//! In order to throw exceptions from within Cranelift-compiled code,3//! we provide a runtime function helper meant to be called by host4//! code that is invoked by guest code.5//!6//! The helper below must be provided a delimited range on the stack7//! corresponding to Cranelift frames above the current host code. It8//! will look for any handlers in this code, given a closure that9//! knows how to use an absolute PC to look up a module's exception10//! table and its start-of-code-segment. If a handler is found, the11//! helper below will return the SP, FP and PC that must be12//! restored. Architecture-specific helpers are provided to jump to13//! this new context with payload values. Otherwise, if no handler is14//! found, the return type indicates this, and it is the caller's15//! responsibility to invoke alternative behavior (e.g., abort the16//! program or unwind all the way to initial Cranelift-code entry).1718use crate::{Frame, Unwind};19use core::ops::ControlFlow;2021/// Description of a frame on the stack that is ready to catch an exception.22#[derive(Debug)]23pub struct Handler {24/// Program counter of handler return point.25pub pc: usize,26/// Stack pointer to restore before jumping to handler.27pub sp: usize,28/// Frame pointer to restore before jumping to handler.29pub fp: usize,30}3132impl Handler {33/// Implementation of stack-walking to find a handler.34///35/// This function searches for a handler in the given range of stack36/// frames, starting from the throw stub and up to a specified entry37/// frame.38///39/// # Safety40///41/// The safety of this function is the same as [`crate::visit_frames`] where the42/// values passed in configuring the frame pointer walk must be correct and43/// Wasm-defined for this to not have UB.44pub unsafe fn find<F: Fn(&Frame) -> Option<(usize, usize)>>(45unwind: &dyn Unwind,46frame_handler: F,47exit_pc: usize,48exit_trampoline_frame: usize,49entry_frame: usize,50) -> Option<Handler> {51// SAFETY: the safety of `visit_frames` relies on the correctness of the52// parameters passed in which is forwarded as a contract to this function53// tiself.54let result = unsafe {55crate::stackwalk::visit_frames(56unwind,57exit_pc,58exit_trampoline_frame,59entry_frame,60|frame| {61log::trace!("visit_frame: frame {frame:?}");62if let Some((handler_pc, handler_sp)) = frame_handler(&frame) {63return ControlFlow::Break(Handler {64pc: handler_pc,65sp: handler_sp,66fp: frame.fp(),67});68}69ControlFlow::Continue(())70},71)72};73match result {74ControlFlow::Break(handler) => Some(handler),75ControlFlow::Continue(()) => None,76}77}78}798081