use cranelift_codegen::{
binemit,
ir::{self, ExternalName, UserExternalNameRef},
settings, MachReloc, MachTrap,
};
use std::collections::BTreeMap;
use wasmtime_environ::{FlagValue, FuncIndex, Trap, TrapInformation};
pub mod isa_builder;
mod obj;
pub use obj::*;
mod compiled_function;
pub use compiled_function::*;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Relocation {
pub reloc: binemit::Reloc,
pub reloc_target: RelocationTarget,
pub offset: binemit::CodeOffset,
pub addend: binemit::Addend,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum RelocationTarget {
UserFunc(FuncIndex),
LibCall(ir::LibCall),
}
pub fn clif_flags_to_wasmtime(
flags: impl IntoIterator<Item = settings::Value>,
) -> BTreeMap<String, FlagValue> {
flags
.into_iter()
.map(|val| (val.name.to_string(), to_flag_value(&val)))
.collect()
}
fn to_flag_value(v: &settings::Value) -> FlagValue {
match v.kind() {
settings::SettingKind::Enum => FlagValue::Enum(v.as_enum().unwrap().into()),
settings::SettingKind::Num => FlagValue::Num(v.as_num().unwrap()),
settings::SettingKind::Bool => FlagValue::Bool(v.as_bool().unwrap()),
settings::SettingKind::Preset => unreachable!(),
}
}
const DEBUG_ASSERT_TRAP_CODE: u16 = u16::MAX;
pub const ALWAYS_TRAP_CODE: u16 = 100;
pub const CANNOT_ENTER_CODE: u16 = 101;
pub fn mach_trap_to_trap(trap: &MachTrap) -> Option<TrapInformation> {
let &MachTrap { offset, code } = trap;
Some(TrapInformation {
code_offset: offset,
trap_code: match code {
ir::TrapCode::StackOverflow => Trap::StackOverflow,
ir::TrapCode::HeapOutOfBounds => Trap::MemoryOutOfBounds,
ir::TrapCode::HeapMisaligned => Trap::HeapMisaligned,
ir::TrapCode::TableOutOfBounds => Trap::TableOutOfBounds,
ir::TrapCode::IndirectCallToNull => Trap::IndirectCallToNull,
ir::TrapCode::BadSignature => Trap::BadSignature,
ir::TrapCode::IntegerOverflow => Trap::IntegerOverflow,
ir::TrapCode::IntegerDivisionByZero => Trap::IntegerDivisionByZero,
ir::TrapCode::BadConversionToInteger => Trap::BadConversionToInteger,
ir::TrapCode::UnreachableCodeReached => Trap::UnreachableCodeReached,
ir::TrapCode::Interrupt => Trap::Interrupt,
ir::TrapCode::User(ALWAYS_TRAP_CODE) => Trap::AlwaysTrapAdapter,
ir::TrapCode::User(CANNOT_ENTER_CODE) => Trap::CannotEnterComponent,
ir::TrapCode::NullReference => Trap::NullReference,
ir::TrapCode::User(DEBUG_ASSERT_TRAP_CODE) => return None,
ir::TrapCode::User(_) => unreachable!(),
},
})
}
fn mach_reloc_to_reloc<F>(reloc: &MachReloc, transform_user_func_ref: F) -> Relocation
where
F: Fn(UserExternalNameRef) -> (u32, u32),
{
let &MachReloc {
offset,
kind,
ref name,
addend,
} = reloc;
let reloc_target = if let ExternalName::User(user_func_ref) = *name {
let (namespace, index) = transform_user_func_ref(user_func_ref);
debug_assert_eq!(namespace, 0);
RelocationTarget::UserFunc(FuncIndex::from_u32(index))
} else if let ExternalName::LibCall(libcall) = *name {
RelocationTarget::LibCall(libcall)
} else {
panic!("unrecognized external name")
};
Relocation {
reloc: kind,
reloc_target,
offset,
addend,
}
}