Skip to content

Commit

Permalink
make trap just a byte
Browse files Browse the repository at this point in the history
  • Loading branch information
alexcrichton committed Sep 28, 2024
1 parent de8fc46 commit f15c243
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 132 deletions.
52 changes: 7 additions & 45 deletions cranelift/codegen/src/ir/memflags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ pub struct MemFlags {
// * 3 - big endian flag
// * 4 - checked flag
// * 5/6 - alias region
// * 7/8/9/10 - trap code
// * 11/12/13/14/15 - unallocated
// * 7/8/9/10/11/12/13/14 - trap code
// * 15 - unallocated
//
// Current properties upheld are:
//
Expand Down Expand Up @@ -108,7 +108,7 @@ const MASK_ALIAS_REGION: u16 = 0b11 << ALIAS_REGION_OFFSET;
const ALIAS_REGION_OFFSET: u16 = 5;

/// Trap code, if any, for this memory operation.
const MASK_TRAP_CODE: u16 = 0b1111 << TRAP_CODE_OFFSET;
const MASK_TRAP_CODE: u16 = 0b1111_1111 << TRAP_CODE_OFFSET;
const TRAP_CODE_OFFSET: u16 = 7;

impl MemFlags {
Expand Down Expand Up @@ -199,7 +199,6 @@ impl MemFlags {
"checked" => self.with_checked(),

other => match TrapCode::from_str(other) {
Ok(TrapCode::User(_)) => return Err("cannot set user trap code on mem flags"),
Ok(code) => self.with_trap_code(Some(code)),
Err(()) => return Ok(false),
},
Expand Down Expand Up @@ -343,30 +342,7 @@ impl MemFlags {
///
/// A `None` trap code indicates that this memory access does not trap.
pub const fn trap_code(self) -> Option<TrapCode> {
// NB: keep this encoding in sync with `with_trap_code` below.
//
// Also note that the default, all zeros, is `HeapOutOfBounds`. It is
// intentionally not `None` so memory operations are all considered
// effect-ful by default.
match (self.bits & MASK_TRAP_CODE) >> TRAP_CODE_OFFSET {
0b0000 => Some(TrapCode::HeapOutOfBounds),
0b0001 => Some(TrapCode::StackOverflow),
0b0010 => Some(TrapCode::HeapMisaligned),
0b0011 => Some(TrapCode::TableOutOfBounds),
0b0100 => Some(TrapCode::IndirectCallToNull),
0b0101 => Some(TrapCode::BadSignature),
0b0110 => Some(TrapCode::IntegerOverflow),
0b0111 => Some(TrapCode::IntegerDivisionByZero),
0b1000 => Some(TrapCode::BadConversionToInteger),
0b1001 => Some(TrapCode::UnreachableCodeReached),
0b1010 => Some(TrapCode::Interrupt),
0b1011 => Some(TrapCode::NullReference),
0b1100 => Some(TrapCode::ArrayOutOfBounds),
// 0b1101 => {} not allocated
// 0b1110 => {} not allocated
0b1111 => None,
_ => unreachable!(),
}
TrapCode::from_raw(((self.bits & MASK_TRAP_CODE) >> TRAP_CODE_OFFSET) as u8)
}

/// Configures these flags with the specified trap code `code`.
Expand All @@ -378,22 +354,8 @@ impl MemFlags {
/// communicated and which instruction trapped.
pub const fn with_trap_code(mut self, code: Option<TrapCode>) -> Self {
let bits = match code {
Some(TrapCode::HeapOutOfBounds) => 0b0000,
Some(TrapCode::StackOverflow) => 0b0001,
Some(TrapCode::HeapMisaligned) => 0b0010,
Some(TrapCode::TableOutOfBounds) => 0b0011,
Some(TrapCode::IndirectCallToNull) => 0b0100,
Some(TrapCode::BadSignature) => 0b0101,
Some(TrapCode::IntegerOverflow) => 0b0110,
Some(TrapCode::IntegerDivisionByZero) => 0b0111,
Some(TrapCode::BadConversionToInteger) => 0b1000,
Some(TrapCode::UnreachableCodeReached) => 0b1001,
Some(TrapCode::Interrupt) => 0b1010,
Some(TrapCode::NullReference) => 0b1011,
Some(TrapCode::ArrayOutOfBounds) => 0b1100,
None => 0b1111,

Some(TrapCode::User(_)) => panic!("cannot set user trap code in mem flags"),
Some(code) => code.as_raw() as u16,
None => 0,
};
self.bits &= !MASK_TRAP_CODE;
self.bits |= bits << TRAP_CODE_OFFSET;
Expand All @@ -407,7 +369,7 @@ impl fmt::Display for MemFlags {
None => write!(f, " notrap")?,
// This is the default trap code, so don't print anything extra
// for this.
Some(TrapCode::HeapOutOfBounds) => {}
Some(TrapCode::HEAP_OUT_OF_BOUNDS) => {}
Some(t) => write!(f, " {t}")?,
}
if self.aligned() {
Expand Down
136 changes: 56 additions & 80 deletions cranelift/codegen/src/ir/trapcode.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Trap codes describing the reason for a trap.

use core::fmt::{self, Display, Formatter};
use core::num::NonZeroU8;
use core::str::FromStr;
#[cfg(feature = "enable-serde")]
use serde_derive::{Deserialize, Serialize};
Expand All @@ -10,92 +11,76 @@ use serde_derive::{Deserialize, Serialize};
/// All trap instructions have an explicit trap code.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub enum TrapCode {
/// The current stack space was exhausted.
StackOverflow,
pub struct TrapCode(NonZeroU8);

impl TrapCode {
const RESERVED: u8 = 5;
const RESERVED_START: u8 = u8::MAX - Self::RESERVED + 1;

const fn reserved(byte: u8) -> TrapCode {
match NonZeroU8::new(byte + Self::RESERVED_START) {
Some(nz) => TrapCode(nz),
None => panic!("invalid reserved opcode"),
}
}

/// The current stack space was exhausted.
pub const STACK_OVERFLOW: TrapCode = TrapCode::reserved(0);
/// An integer arithmetic operation caused an overflow.
pub const INTEGER_OVERFLOW: TrapCode = TrapCode::reserved(1);
/// A `heap_addr` instruction detected an out-of-bounds error.
///
/// Note that not all out-of-bounds heap accesses are reported this way;
/// some are detected by a segmentation fault on the heap unmapped or
/// offset-guard pages.
HeapOutOfBounds,

/// A wasm atomic operation was presented with a not-naturally-aligned linear-memory address.
HeapMisaligned,

/// A `table_addr` instruction detected an out-of-bounds error.
TableOutOfBounds,

/// An array access attempted to index beyond its array's bounds.
ArrayOutOfBounds,

/// Indirect call to a null table entry.
IndirectCallToNull,

/// Signature mismatch on indirect call.
BadSignature,

/// An integer arithmetic operation caused an overflow.
IntegerOverflow,
pub const HEAP_OUT_OF_BOUNDS: TrapCode = TrapCode::reserved(2);

/// An integer division by zero.
IntegerDivisionByZero,
pub const INTEGER_DIVISION_BY_ZERO: TrapCode = TrapCode::reserved(3);

/// Failed float-to-int conversion.
BadConversionToInteger,

/// Code that was supposed to have been unreachable was reached.
UnreachableCodeReached,

/// Execution has potentially run too long and may be interrupted.
Interrupt,
pub const BAD_CONVERSION_TO_INTEGER: TrapCode = TrapCode::reserved(4);

/// Create a user-defined trap code.
pub const fn user(code: u8) -> TrapCode {
assert!(
code < Self::RESERVED_START,
"user code collides with built-in trap code"
);
match NonZeroU8::new(code) {
Some(nz) => TrapCode(nz),
None => panic!("user trap code cannot be zero"),
}
}

/// A user-defined trap code.
User(u16),
/// TODO
pub const fn as_raw(&self) -> u8 {
self.0.get()
}

/// A null reference was encountered which was required to be non-null.
NullReference,
}
/// TODO
pub const fn from_raw(byte: u8) -> Option<TrapCode> {
match NonZeroU8::new(byte) {
Some(nz) => Some(TrapCode(nz)),
None => None,
}
}

impl TrapCode {
/// Returns a slice of all traps except `TrapCode::User` traps
pub const fn non_user_traps() -> &'static [TrapCode] {
&[
TrapCode::StackOverflow,
TrapCode::HeapOutOfBounds,
TrapCode::HeapMisaligned,
TrapCode::TableOutOfBounds,
TrapCode::IndirectCallToNull,
TrapCode::BadSignature,
TrapCode::IntegerOverflow,
TrapCode::IntegerDivisionByZero,
TrapCode::BadConversionToInteger,
TrapCode::UnreachableCodeReached,
TrapCode::Interrupt,
TrapCode::NullReference,
]
&[TrapCode::STACK_OVERFLOW]
}
}

impl Display for TrapCode {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use self::TrapCode::*;
let identifier = match *self {
StackOverflow => "stk_ovf",
HeapOutOfBounds => "heap_oob",
HeapMisaligned => "heap_misaligned",
TableOutOfBounds => "table_oob",
IndirectCallToNull => "icall_null",
BadSignature => "bad_sig",
IntegerOverflow => "int_ovf",
IntegerDivisionByZero => "int_divz",
BadConversionToInteger => "bad_toint",
UnreachableCodeReached => "unreachable",
Interrupt => "interrupt",
User(x) => return write!(f, "user{x}"),
NullReference => "null_reference",
ArrayOutOfBounds => "array_oob",
Self::STACK_OVERFLOW => "stk_ovf",
Self::HEAP_OUT_OF_BOUNDS => "heap_oob",
Self::INTEGER_OVERFLOW => "int_ovf",
Self::INTEGER_DIVISION_BY_ZERO => "int_divz",
Self::BAD_CONVERSION_TO_INTEGER => "bad_toint",
TrapCode(x) => return write!(f, "user{x}"),
};
f.write_str(identifier)
}
Expand All @@ -105,22 +90,13 @@ impl FromStr for TrapCode {
type Err = ();

fn from_str(s: &str) -> Result<Self, Self::Err> {
use self::TrapCode::*;
match s {
"stk_ovf" => Ok(StackOverflow),
"heap_oob" => Ok(HeapOutOfBounds),
"heap_misaligned" => Ok(HeapMisaligned),
"table_oob" => Ok(TableOutOfBounds),
"icall_null" => Ok(IndirectCallToNull),
"bad_sig" => Ok(BadSignature),
"int_ovf" => Ok(IntegerOverflow),
"int_divz" => Ok(IntegerDivisionByZero),
"bad_toint" => Ok(BadConversionToInteger),
"unreachable" => Ok(UnreachableCodeReached),
"interrupt" => Ok(Interrupt),
"null_reference" => Ok(NullReference),
"array_oob" => Ok(ArrayOutOfBounds),
_ if s.starts_with("user") => s[4..].parse().map(User).map_err(|_| ()),
"stk_ovf" => Ok(Self::STACK_OVERFLOW),
"heap_oob" => Ok(Self::HEAP_OUT_OF_BOUNDS),
"int_ovf" => Ok(Self::INTEGER_OVERFLOW),
"int_divz" => Ok(Self::INTEGER_DIVISION_BY_ZERO),
"bad_toint" => Ok(Self::BAD_CONVERSION_TO_INTEGER),
_ if s.starts_with("user") => s[4..].parse().map(TrapCode::user).map_err(|_| ()),
_ => Err(()),
}
}
Expand Down
2 changes: 1 addition & 1 deletion cranelift/codegen/src/isa/aarch64/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ impl ABIMachineSpec for AArch64MachineDeps {
extendop: ExtendOp::UXTX,
});
insts.push(Inst::TrapIf {
trap_code: ir::TrapCode::StackOverflow,
trap_code: ir::TrapCode::STACK_OVERFLOW,
// Here `Lo` == "less than" when interpreting the two
// operands as unsigned integers.
kind: CondBrKind::Cond(Cond::Lo),
Expand Down
6 changes: 3 additions & 3 deletions cranelift/codegen/src/isle_prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -648,15 +648,15 @@ macro_rules! isle_common_prelude_methods {
}

fn trap_code_division_by_zero(&mut self) -> TrapCode {
TrapCode::IntegerDivisionByZero
TrapCode::INTEGER_DIVISION_BY_ZERO
}

fn trap_code_integer_overflow(&mut self) -> TrapCode {
TrapCode::IntegerOverflow
TrapCode::INTEGER_OVERFLOW
}

fn trap_code_bad_conversion_to_integer(&mut self) -> TrapCode {
TrapCode::BadConversionToInteger
TrapCode::BAD_CONVERSION_TO_INTEGER
}

fn nonzero_u64_from_imm64(&mut self, val: Imm64) -> Option<u64> {
Expand Down
6 changes: 3 additions & 3 deletions cranelift/wasm/src/code_translator/bounds_checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ where
builder,
index,
access_size_val,
ir::TrapCode::HeapOutOfBounds,
ir::TrapCode::HEAP_OUT_OF_BOUNDS,
);
if pcc {
builder.func.dfg.facts[adjusted_index] = Some(Fact::value_offset(
Expand Down Expand Up @@ -325,7 +325,7 @@ where
"static memories require the ability to use virtual memory"
);
env.before_unconditionally_trapping_memory_access(builder)?;
env.trap(builder, ir::TrapCode::HeapOutOfBounds);
env.trap(builder, ir::TrapCode::HEAP_OUT_OF_BOUNDS);
Unreachable
}

Expand Down Expand Up @@ -569,7 +569,7 @@ fn explicit_check_oob_condition_and_compute_addr<FE: FuncEnvironment + ?Sized>(
oob_condition: ir::Value,
) -> ir::Value {
if !spectre_mitigations_enabled {
env.trapnz(builder, oob_condition, ir::TrapCode::HeapOutOfBounds);
env.trapnz(builder, oob_condition, ir::TrapCode::HEAP_OUT_OF_BOUNDS);
}
let addr_ty = env.pointer_type();

Expand Down

0 comments on commit f15c243

Please sign in to comment.