use cranelift_codegen::ir;
use cranelift_codegen::isa::{unwind::UnwindInfo, CallConv, TargetIsa};
use cranelift_entity::PrimaryMap;
use cranelift_wasm::{DefinedFuncIndex, FuncIndex, WasmFuncType, WasmType};
use target_lexicon::{Architecture, CallingConvention};
use wasmtime_cranelift_shared::Relocation;
use wasmtime_environ::{
FilePos, InstructionAddressMap, ModuleTranslation, ModuleTypes, TrapInformation,
};
pub use builder::builder;
mod builder;
mod compiler;
mod debug;
mod func_environ;
type CompiledFunctions<'a> = PrimaryMap<DefinedFuncIndex, &'a CompiledFunction>;
#[derive(Default)]
pub struct CompiledFunction {
body: Vec<u8>,
unwind_info: Option<UnwindInfo>,
address_map: FunctionAddressMap,
traps: Vec<TrapInformation>,
relocations: Vec<Relocation>,
value_labels_ranges: cranelift_codegen::ValueLabelsRanges,
sized_stack_slots: ir::StackSlots,
alignment: u32,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
struct FunctionAddressMap {
instructions: Box<[InstructionAddressMap]>,
start_srcloc: FilePos,
end_srcloc: FilePos,
body_offset: usize,
body_len: u32,
}
fn blank_sig(isa: &dyn TargetIsa, call_conv: CallConv) -> ir::Signature {
let pointer_type = isa.pointer_type();
let mut sig = ir::Signature::new(call_conv);
sig.params.push(ir::AbiParam::special(
pointer_type,
ir::ArgumentPurpose::VMContext,
));
sig.params.push(ir::AbiParam::new(pointer_type));
return sig;
}
fn wasmtime_call_conv(isa: &dyn TargetIsa) -> CallConv {
match isa.triple().default_calling_convention() {
Ok(CallingConvention::AppleAarch64) => CallConv::WasmtimeAppleAarch64,
Ok(CallingConvention::SystemV) | Err(()) => CallConv::WasmtimeSystemV,
Ok(CallingConvention::WindowsFastcall) => CallConv::WasmtimeFastcall,
Ok(unimp) => unimplemented!("calling convention: {:?}", unimp),
}
}
fn push_types(isa: &dyn TargetIsa, sig: &mut ir::Signature, wasm: &WasmFuncType) {
let cvt = |ty: &WasmType| ir::AbiParam::new(value_type(isa, *ty));
sig.params.extend(wasm.params().iter().map(&cvt));
sig.returns.extend(wasm.returns().iter().map(&cvt));
}
fn value_type(isa: &dyn TargetIsa, ty: WasmType) -> ir::types::Type {
match ty {
WasmType::I32 => ir::types::I32,
WasmType::I64 => ir::types::I64,
WasmType::F32 => ir::types::F32,
WasmType::F64 => ir::types::F64,
WasmType::V128 => ir::types::I8X16,
WasmType::FuncRef | WasmType::ExternRef => reference_type(ty, isa.pointer_type()),
}
}
fn indirect_signature(isa: &dyn TargetIsa, wasm: &WasmFuncType) -> ir::Signature {
let mut sig = blank_sig(isa, wasmtime_call_conv(isa));
push_types(isa, &mut sig, wasm);
return sig;
}
fn func_signature(
isa: &dyn TargetIsa,
translation: &ModuleTranslation,
types: &ModuleTypes,
index: FuncIndex,
) -> ir::Signature {
let func = &translation.module.functions[index];
let call_conv = match translation.module.defined_func_index(index) {
Some(_idx) if !func.is_escaping() => {
let on_apple_aarch64 = isa
.triple()
.default_calling_convention()
.unwrap_or(CallingConvention::SystemV)
== CallingConvention::AppleAarch64;
if on_apple_aarch64 {
CallConv::WasmtimeAppleAarch64
} else if isa.triple().architecture == Architecture::S390x {
wasmtime_call_conv(isa)
} else {
CallConv::Fast
}
}
_ => wasmtime_call_conv(isa),
};
let mut sig = blank_sig(isa, call_conv);
push_types(isa, &mut sig, &types[func.signature]);
return sig;
}
fn reference_type(wasm_ty: cranelift_wasm::WasmType, pointer_type: ir::Type) -> ir::Type {
match wasm_ty {
cranelift_wasm::WasmType::FuncRef => pointer_type,
cranelift_wasm::WasmType::ExternRef => match pointer_type {
ir::types::I32 => ir::types::R32,
ir::types::I64 => ir::types::R64,
_ => panic!("unsupported pointer type"),
},
_ => panic!("unsupported Wasm reference type"),
}
}