use crate::codegen::{BuiltinFunction, OperandSize};
use smallvec::{smallvec, SmallVec};
use std::collections::{
hash_map::Entry::{Occupied, Vacant},
HashMap,
};
use wasmparser::BlockType;
use wasmtime_environ::{
FuncIndex, GlobalIndex, ModuleTranslation, ModuleTypes, PtrSize, TableIndex, TablePlan,
TypeConvert, TypeIndex, VMOffsets, WasmFuncType, WasmType,
};
#[derive(Debug, Copy, Clone)]
pub struct TableData {
pub offset: u32,
pub current_elems_offset: u32,
pub base: Option<u32>,
pub(crate) element_size: OperandSize,
pub(crate) current_elements_size: OperandSize,
}
#[derive(Clone)]
pub enum Callee {
Local(CalleeInfo),
Import(CalleeInfo),
FuncRef(WasmFuncType),
Builtin(BuiltinFunction),
}
#[derive(Clone)]
pub struct CalleeInfo {
pub ty: WasmFuncType,
pub index: FuncIndex,
}
pub struct FuncEnv<'a, 'translation: 'a, 'data: 'translation, P: PtrSize> {
pub vmoffsets: &'a VMOffsets<P>,
pub translation: &'translation ModuleTranslation<'data>,
pub types: &'translation ModuleTypes,
resolved_tables: HashMap<TableIndex, TableData>,
}
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, 'translation, 'data, P: PtrSize> FuncEnv<'a, 'translation, 'data, P> {
pub fn new(
vmoffsets: &'a VMOffsets<P>,
translation: &'translation ModuleTranslation<'data>,
types: &'translation ModuleTypes,
) -> Self {
Self {
vmoffsets,
translation,
types,
resolved_tables: HashMap::new(),
}
}
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.core_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(&mut self, index: TableIndex) -> TableData {
match self.resolved_tables.entry(index) {
Occupied(entry) => *entry.get(),
Vacant(entry) => {
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(),
),
};
*entry.insert(TableData {
base: from_offset,
offset: base_offset,
current_elems_offset,
element_size: OperandSize::from_bytes(self.vmoffsets.ptr.size()),
current_elements_size: OperandSize::from_bytes(
self.vmoffsets.size_of_vmtable_definition_current_elements(),
),
})
}
}
}
pub fn table_plan(&mut self, index: TableIndex) -> &TablePlan {
&self.translation.module.table_plans[index]
}
}