wasmtime_cranelift_shared/
lib.rs

1use cranelift_codegen::{
2    binemit,
3    ir::{self, ExternalName, UserExternalNameRef},
4    settings, FinalizedMachReloc, FinalizedRelocTarget, MachTrap,
5};
6use wasmtime_environ::{FlagValue, FuncIndex, Trap, TrapInformation};
7
8pub mod isa_builder;
9mod obj;
10pub use obj::*;
11mod compiled_function;
12pub use compiled_function::*;
13
14/// A record of a relocation to perform.
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct Relocation {
17    /// The relocation code.
18    pub reloc: binemit::Reloc,
19    /// Relocation target.
20    pub reloc_target: RelocationTarget,
21    /// The offset where to apply the relocation.
22    pub offset: binemit::CodeOffset,
23    /// The addend to add to the relocation value.
24    pub addend: binemit::Addend,
25}
26
27/// Destination function. Can be either user function or some special one, like `memory.grow`.
28#[derive(Debug, Copy, Clone, PartialEq, Eq)]
29pub enum RelocationTarget {
30    /// The user function index.
31    UserFunc(FuncIndex),
32    /// A compiler-generated libcall.
33    LibCall(ir::LibCall),
34}
35
36/// Converts cranelift_codegen settings to the wasmtime_environ equivalent.
37pub fn clif_flags_to_wasmtime(
38    flags: impl IntoIterator<Item = settings::Value>,
39) -> Vec<(&'static str, FlagValue<'static>)> {
40    flags
41        .into_iter()
42        .map(|val| (val.name, to_flag_value(&val)))
43        .collect()
44}
45
46fn to_flag_value(v: &settings::Value) -> FlagValue<'static> {
47    match v.kind() {
48        settings::SettingKind::Enum => FlagValue::Enum(v.as_enum().unwrap()),
49        settings::SettingKind::Num => FlagValue::Num(v.as_num().unwrap()),
50        settings::SettingKind::Bool => FlagValue::Bool(v.as_bool().unwrap()),
51        settings::SettingKind::Preset => unreachable!(),
52    }
53}
54
55/// Trap code used for debug assertions we emit in our JIT code.
56const DEBUG_ASSERT_TRAP_CODE: u16 = u16::MAX;
57
58/// A custom code with `TrapCode::User` which is used by always-trap shims which
59/// indicates that, as expected, the always-trapping function indeed did trap.
60/// This effectively provides a better error message as opposed to a bland
61/// "unreachable code reached"
62pub const ALWAYS_TRAP_CODE: u16 = 100;
63
64/// A custom code with `TrapCode::User` corresponding to being unable to reenter
65/// a component due to its reentrance limitations. This is used in component
66/// adapters to provide a more useful error message in such situations.
67pub const CANNOT_ENTER_CODE: u16 = 101;
68
69/// Converts machine traps to trap information.
70pub fn mach_trap_to_trap(trap: &MachTrap) -> Option<TrapInformation> {
71    let &MachTrap { offset, code } = trap;
72    Some(TrapInformation {
73        code_offset: offset,
74        trap_code: match code {
75            ir::TrapCode::StackOverflow => Trap::StackOverflow,
76            ir::TrapCode::HeapOutOfBounds => Trap::MemoryOutOfBounds,
77            ir::TrapCode::HeapMisaligned => Trap::HeapMisaligned,
78            ir::TrapCode::TableOutOfBounds => Trap::TableOutOfBounds,
79            ir::TrapCode::IndirectCallToNull => Trap::IndirectCallToNull,
80            ir::TrapCode::BadSignature => Trap::BadSignature,
81            ir::TrapCode::IntegerOverflow => Trap::IntegerOverflow,
82            ir::TrapCode::IntegerDivisionByZero => Trap::IntegerDivisionByZero,
83            ir::TrapCode::BadConversionToInteger => Trap::BadConversionToInteger,
84            ir::TrapCode::UnreachableCodeReached => Trap::UnreachableCodeReached,
85            ir::TrapCode::Interrupt => Trap::Interrupt,
86            ir::TrapCode::User(ALWAYS_TRAP_CODE) => Trap::AlwaysTrapAdapter,
87            ir::TrapCode::User(CANNOT_ENTER_CODE) => Trap::CannotEnterComponent,
88            ir::TrapCode::NullReference => Trap::NullReference,
89
90            // These do not get converted to wasmtime traps, since they
91            // shouldn't ever be hit in theory. Instead of catching and handling
92            // these, we let the signal crash the process.
93            ir::TrapCode::User(DEBUG_ASSERT_TRAP_CODE) => return None,
94
95            // these should never be emitted by wasmtime-cranelift
96            ir::TrapCode::User(_) => unreachable!(),
97        },
98    })
99}
100
101/// Converts machine relocations to relocation information
102/// to perform.
103fn mach_reloc_to_reloc<F>(reloc: &FinalizedMachReloc, transform_user_func_ref: F) -> Relocation
104where
105    F: Fn(UserExternalNameRef) -> (u32, u32),
106{
107    let &FinalizedMachReloc {
108        offset,
109        kind,
110        ref target,
111        addend,
112    } = reloc;
113    let reloc_target = match *target {
114        FinalizedRelocTarget::ExternalName(ExternalName::User(user_func_ref)) => {
115            let (namespace, index) = transform_user_func_ref(user_func_ref);
116            debug_assert_eq!(namespace, 0);
117            RelocationTarget::UserFunc(FuncIndex::from_u32(index))
118        }
119        FinalizedRelocTarget::ExternalName(ExternalName::LibCall(libcall)) => {
120            RelocationTarget::LibCall(libcall)
121        }
122        _ => panic!("unrecognized external name"),
123    };
124    Relocation {
125        reloc: kind,
126        reloc_target,
127        offset,
128        addend,
129    }
130}