Path: blob/main/cranelift/codegen/src/ir/trapcode.rs
1693 views
//! Trap codes describing the reason for a trap.12use core::fmt::{self, Display, Formatter};3use core::num::NonZeroU8;4use core::str::FromStr;5#[cfg(feature = "enable-serde")]6use serde_derive::{Deserialize, Serialize};78/// A trap code describing the reason for a trap.9///10/// All trap instructions have an explicit trap code.11#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]12#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]13pub struct TrapCode(NonZeroU8);1415impl TrapCode {16/// Number of reserved opcodes for Cranelift itself. This number of traps are17/// defined below starting at the high end of the byte space (e.g. 255, 254,18/// ...)19const RESERVED: u8 = 5;20const RESERVED_START: u8 = u8::MAX - Self::RESERVED + 1;2122/// Internal helper to create new reserved trap codes.23const fn reserved(byte: u8) -> TrapCode {24if let Some(code) = byte.checked_add(Self::RESERVED_START) {25if let Some(nz) = NonZeroU8::new(code) {26return TrapCode(nz);27}28}29panic!("invalid reserved opcode")30}3132/// The current stack space was exhausted.33pub const STACK_OVERFLOW: TrapCode = TrapCode::reserved(0);34/// An integer arithmetic operation caused an overflow.35pub const INTEGER_OVERFLOW: TrapCode = TrapCode::reserved(1);36/// A `heap_addr` instruction detected an out-of-bounds error.37///38/// Note that not all out-of-bounds heap accesses are reported this way;39/// some are detected by a segmentation fault on the heap unmapped or40/// offset-guard pages.41pub const HEAP_OUT_OF_BOUNDS: TrapCode = TrapCode::reserved(2);4243/// An integer division by zero.44pub const INTEGER_DIVISION_BY_ZERO: TrapCode = TrapCode::reserved(3);4546/// Failed float-to-int conversion.47pub const BAD_CONVERSION_TO_INTEGER: TrapCode = TrapCode::reserved(4);4849/// Create a user-defined trap code.50///51/// Returns `None` if `code` is zero or too large and is reserved by52/// Cranelift.53pub const fn user(code: u8) -> Option<TrapCode> {54if code >= Self::RESERVED_START {55return None;56}57match NonZeroU8::new(code) {58Some(nz) => Some(TrapCode(nz)),59None => None,60}61}6263/// Alias for [`TrapCode::user`] with a panic built-in.64pub const fn unwrap_user(code: u8) -> TrapCode {65match TrapCode::user(code) {66Some(code) => code,67None => panic!("invalid user trap code"),68}69}7071/// Returns the raw byte representing this trap.72pub const fn as_raw(&self) -> NonZeroU8 {73self.074}7576/// Creates a trap code from its raw byte, likely returned by77/// [`TrapCode::as_raw`] previously.78pub const fn from_raw(byte: NonZeroU8) -> TrapCode {79TrapCode(byte)80}8182/// Returns a slice of all traps except `TrapCode::User` traps83pub const fn non_user_traps() -> &'static [TrapCode] {84&[85TrapCode::STACK_OVERFLOW,86TrapCode::HEAP_OUT_OF_BOUNDS,87TrapCode::INTEGER_OVERFLOW,88TrapCode::INTEGER_DIVISION_BY_ZERO,89TrapCode::BAD_CONVERSION_TO_INTEGER,90]91}92}9394impl Display for TrapCode {95fn fmt(&self, f: &mut Formatter) -> fmt::Result {96let identifier = match *self {97Self::STACK_OVERFLOW => "stk_ovf",98Self::HEAP_OUT_OF_BOUNDS => "heap_oob",99Self::INTEGER_OVERFLOW => "int_ovf",100Self::INTEGER_DIVISION_BY_ZERO => "int_divz",101Self::BAD_CONVERSION_TO_INTEGER => "bad_toint",102TrapCode(x) => return write!(f, "user{x}"),103};104f.write_str(identifier)105}106}107108impl FromStr for TrapCode {109type Err = ();110111fn from_str(s: &str) -> Result<Self, Self::Err> {112match s {113"stk_ovf" => Ok(Self::STACK_OVERFLOW),114"heap_oob" => Ok(Self::HEAP_OUT_OF_BOUNDS),115"int_ovf" => Ok(Self::INTEGER_OVERFLOW),116"int_divz" => Ok(Self::INTEGER_DIVISION_BY_ZERO),117"bad_toint" => Ok(Self::BAD_CONVERSION_TO_INTEGER),118_ if s.starts_with("user") => {119let num = s[4..].parse().map_err(|_| ())?;120TrapCode::user(num).ok_or(())121}122_ => Err(()),123}124}125}126127#[cfg(test)]128mod tests {129use super::*;130use alloc::string::ToString;131132#[test]133fn display() {134for r in TrapCode::non_user_traps() {135let tc = *r;136assert_eq!(tc.to_string().parse(), Ok(tc));137}138assert_eq!("bogus".parse::<TrapCode>(), Err(()));139140assert_eq!(TrapCode::unwrap_user(17).to_string(), "user17");141assert_eq!("user22".parse(), Ok(TrapCode::unwrap_user(22)));142assert_eq!("user".parse::<TrapCode>(), Err(()));143assert_eq!("user-1".parse::<TrapCode>(), Err(()));144assert_eq!("users".parse::<TrapCode>(), Err(()));145}146}147148149