use crate::{
abi::{ABIResults, ABIResultsData},
codegen::{BuiltinFunction, OperandSize, ABI},
CallingConvention,
};
use std::collections::{
hash_map::Entry::{Occupied, Vacant},
HashMap,
};
use wasmparser::BlockType;
use wasmtime_environ::{
FuncIndex, GlobalIndex, MemoryIndex, ModuleTranslation, ModuleTypesBuilder, PtrSize,
TableIndex, TablePlan, TypeConvert, TypeIndex, VMOffsets, WasmFuncType, WasmHeapType, WasmType,
};
#[derive(Debug, Copy, Clone)]
pub struct TableData {
pub offset: u32,
pub current_elems_offset: u32,
pub import_from: Option<u32>,
pub(crate) element_size: OperandSize,
pub(crate) current_elements_size: OperandSize,
}
#[derive(Debug, Copy, Clone)]
pub struct HeapData {
pub offset: u32,
pub current_length_offset: u32,
pub import_from: Option<u32>,
pub ty: WasmType,
}
#[derive(Clone)]
pub enum Callee {
Local(CalleeInfo),
Import(CalleeInfo),
FuncRef(WasmFuncType),
Builtin(BuiltinFunction),
}
#[derive(Clone)]
pub struct CalleeInfo {
pub ty: WasmFuncType,
pub index: FuncIndex,
}
#[derive(Default, Debug, Copy, Clone)]
pub(crate) struct BlockTypeInfo {
pub param_count: usize,
pub result_count: usize,
}
impl BlockTypeInfo {
pub fn with_single_result() -> Self {
Self {
param_count: 0,
result_count: 1,
}
}
pub fn new(params: usize, results: usize) -> Self {
Self {
param_count: params,
result_count: results,
}
}
}
pub struct FuncEnv<'a, 'translation: 'a, 'data: 'translation, P: PtrSize> {
pub vmoffsets: &'a VMOffsets<P>,
pub translation: &'translation ModuleTranslation<'data>,
pub types: &'translation ModuleTypesBuilder,
resolved_tables: HashMap<TableIndex, TableData>,
resolved_heaps: HashMap<MemoryIndex, HeapData>,
}
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 ModuleTypesBuilder,
) -> Self {
Self {
vmoffsets,
translation,
types,
resolved_tables: HashMap::new(),
resolved_heaps: 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.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(crate) fn resolve_block_type_info(&self, ty: BlockType) -> BlockTypeInfo {
use BlockType::*;
match ty {
Empty => BlockTypeInfo::default(),
Type(_) => BlockTypeInfo::with_single_result(),
FuncType(idx) => {
let sig_index =
self.translation.module.types[TypeIndex::from_u32(idx)].unwrap_function();
let sig = &self.types[sig_index];
BlockTypeInfo::new(sig.params().len(), sig.returns().len())
}
}
}
pub(crate) fn resolve_block_results_data<A: ABI>(&self, blockty: BlockType) -> ABIResultsData {
use BlockType::*;
match blockty {
Empty => ABIResultsData::wrap(ABIResults::default()),
Type(ty) => {
let ty = self.convert_valtype(ty);
let results = <A as ABI>::abi_results(&[ty], &CallingConvention::Default);
ABIResultsData::wrap(results)
}
FuncType(idx) => {
let sig_index =
self.translation.module.types[TypeIndex::from_u32(idx)].unwrap_function();
let results = <A as ABI>::abi_results(
&self.types[sig_index].returns(),
&CallingConvention::Default,
);
ABIResultsData::wrap(results)
}
}
}
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 {
import_from: 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 resolve_heap(&mut self, index: MemoryIndex) -> HeapData {
match self.resolved_heaps.entry(index) {
Occupied(entry) => *entry.get(),
Vacant(entry) => {
let (import_from, base_offset, current_length_offset) =
match self.translation.module.defined_memory_index(index) {
Some(defined) => {
let owned = self.translation.module.owned_memory_index(defined);
(
None,
self.vmoffsets.vmctx_vmmemory_definition_base(owned),
self.vmoffsets
.vmctx_vmmemory_definition_current_length(owned),
)
}
None => (
Some(self.vmoffsets.vmctx_vmmemory_import_from(index)),
self.vmoffsets.ptr.vmmemory_definition_base().into(),
self.vmoffsets
.ptr
.vmmemory_definition_current_length()
.into(),
),
};
*entry.insert(HeapData {
offset: base_offset,
import_from,
current_length_offset,
ty: if self.translation.module.memory_plans[index].memory.memory64 {
WasmType::I64
} else {
WasmType::I32
},
})
}
}
}
pub fn table_plan(&mut self, index: TableIndex) -> &TablePlan {
&self.translation.module.table_plans[index]
}
}
impl<P: PtrSize> TypeConvert for FuncEnv<'_, '_, '_, P> {
fn lookup_heap_type(&self, idx: wasmparser::UnpackedIndex) -> WasmHeapType {
wasmtime_environ::WasmparserTypeConverter {
module: &self.translation.module,
types: self.types,
}
.lookup_heap_type(idx)
}
}