use crate::{codegen::BuiltinFunctions, CallingConvention};
use smallvec::{smallvec, SmallVec};
use wasmparser::BlockType;
use wasmtime_environ::{
FuncIndex, GlobalIndex, ModuleTranslation, ModuleTypes, PtrSize, TableIndex, TypeConvert,
TypeIndex, VMOffsets, WasmFuncType, WasmType,
};
pub struct TableData {
pub offset: u32,
pub current_elems_offset: u32,
pub base: Option<u32>,
pub element_size: u8,
}
pub enum Callee {
Local(CalleeInfo),
Import(CalleeInfo),
FuncRef(WasmFuncType),
}
pub struct CalleeInfo {
pub ty: WasmFuncType,
pub index: FuncIndex,
}
pub struct FuncEnv<'a, P: PtrSize> {
pub vmoffsets: VMOffsets<P>,
pub translation: &'a ModuleTranslation<'a>,
pub builtins: BuiltinFunctions,
pub types: &'a ModuleTypes,
}
pub fn ptr_type_from_ptr_size(size: u8) -> WasmType {
(size == 8)
.then(|| WasmType::I64)
.unwrap_or_else(|| unimplemented!("Support for non-64-bit architectures"))
}
impl<'a, P: PtrSize> FuncEnv<'a, P> {
pub fn new(
ptr: P,
translation: &'a ModuleTranslation,
types: &'a ModuleTypes,
call_conv: CallingConvention,
) -> Self {
let vmoffsets = VMOffsets::new(ptr, &translation.module);
let size = vmoffsets.ptr.size();
let builtins_base = vmoffsets.vmctx_builtin_functions();
Self {
vmoffsets,
translation,
builtins: BuiltinFunctions::new(size, call_conv, builtins_base),
types,
}
}
pub(crate) fn vmctx_args_type(&self) -> [WasmType; 2] {
let ty = self.ptr_type();
[ty, ty]
}
pub(crate) fn ptr_type(&self) -> WasmType {
ptr_type_from_ptr_size(self.ptr_size())
}
fn ptr_size(&self) -> u8 {
self.vmoffsets.ptr.size()
}
pub fn funcref(&self, idx: TypeIndex) -> Callee {
let sig_index = self.translation.module.types[idx].unwrap_function();
let ty = self.types[sig_index].clone();
Callee::FuncRef(ty)
}
pub fn callee_from_index(&self, idx: FuncIndex) -> Callee {
let types = &self.translation.get_types();
let ty = types[types.function_at(idx.as_u32())].unwrap_func();
let ty = self.translation.module.convert_func_type(ty);
let import = self.translation.module.is_imported_function(idx);
let info = CalleeInfo { ty, index: idx };
if import {
Callee::Import(info)
} else {
Callee::Local(info)
}
}
pub fn resolve_block_type(&self, blockty: BlockType) -> SmallVec<[WasmType; 1]> {
use BlockType::*;
match blockty {
Empty => smallvec![],
Type(ty) => smallvec![self.translation.module.convert_valtype(ty)],
_ => unimplemented!("multi-value"),
}
}
pub fn resolve_global_type_and_offset(&self, index: GlobalIndex) -> (WasmType, u32) {
let ty = self.translation.module.globals[index].wasm_ty;
let offset = match self.translation.module.defined_global_index(index) {
Some(defined_index) => self.vmoffsets.vmctx_vmglobal_definition(defined_index),
None => self.vmoffsets.vmctx_vmglobal_import_from(index),
};
(ty, offset)
}
pub fn resolve_table_data(&self, index: TableIndex) -> TableData {
let (from_offset, base_offset, current_elems_offset) =
match self.translation.module.defined_table_index(index) {
Some(defined) => (
None,
self.vmoffsets.vmctx_vmtable_definition_base(defined),
self.vmoffsets
.vmctx_vmtable_definition_current_elements(defined),
),
None => (
Some(self.vmoffsets.vmctx_vmtable_import_from(index)),
self.vmoffsets.vmtable_definition_base().into(),
self.vmoffsets.vmtable_definition_current_elements().into(),
),
};
TableData {
base: from_offset,
offset: base_offset,
current_elems_offset,
element_size: self.vmoffsets.ptr.size(),
}
}
}