use cranelift_codegen::cursor::FuncCursor;
use cranelift_codegen::ir::{self, InstBuilder, Type};
use cranelift_entity::entity_impl;
use smallvec::SmallVec;
use wasmtime_environ::{IndexType, Memory};
pub use wasmtime_environ::MemoryKind;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct Load {
pub offset: u32,
pub flags: ir::MemFlagsData,
pub ty: ir::Type,
}
impl Load {
pub fn emit(&self, cursor: &mut FuncCursor<'_>, base: ir::Value) -> ir::Value {
cursor.ins().load(
self.ty,
self.flags,
base,
i32::try_from(self.offset).unwrap(),
)
}
pub fn emit_global(&self, func: &mut ir::Function, base: ir::GlobalValue) -> ir::GlobalValue {
let flags = func.dfg.mem_flags.insert(self.flags).unwrap();
func.global_values.push(ir::GlobalValueData::Load {
base,
offset: i32::try_from(self.offset).unwrap().into(),
global_type: self.ty,
flags,
})
}
}
#[derive(Clone, PartialEq, Hash)]
pub struct VmctxLoadChain(SmallVec<[Load; 2]>);
impl VmctxLoadChain {
pub fn new(loads: SmallVec<[Load; 2]>) -> Self {
assert!(!loads.is_empty());
VmctxLoadChain(loads)
}
pub fn emit(&self, cursor: &mut FuncCursor<'_>, vmctx: ir::Value) -> ir::Value {
let mut val = vmctx;
for load in &self.0 {
val = load.emit(cursor, val);
}
val
}
pub fn emit_global(&self, func: &mut ir::Function) -> ir::GlobalValue {
let mut val = func.global_values.push(ir::GlobalValueData::VMContext);
for load in &self.0 {
val = load.emit_global(func, val);
}
val
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Heap(u32);
entity_impl!(Heap, "heap");
#[derive(Clone, PartialEq, Hash)]
pub struct HeapData {
pub base: VmctxLoadChain,
pub bound: VmctxLoadChain,
pub memory: Memory,
pub kind: MemoryKind,
}
impl HeapData {
pub fn index_type(&self) -> Type {
match self.memory.idx_type {
IndexType::I32 => ir::types::I32,
IndexType::I64 => ir::types::I64,
}
}
pub fn memory_tunables<'a>(
&self,
tunables: &'a wasmtime_environ::Tunables,
) -> wasmtime_environ::MemoryTunables<'a> {
wasmtime_environ::MemoryTunables::new(tunables, self.kind)
}
}