use crate::component::{MAX_FLAT_PARAMS, MAX_FLAT_RESULTS};
use crate::{
EntityType, Global, GlobalInit, ModuleTypes, ModuleTypesBuilder, PrimaryMap, SignatureIndex,
};
use anyhow::{bail, Result};
use cranelift_entity::EntityRef;
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::hash::Hash;
use std::ops::Index;
use wasmparser::{
ComponentAlias, ComponentOuterAliasKind, ComponentTypeDeclaration, InstanceTypeDeclaration,
};
use wasmtime_component_util::{DiscriminantSize, FlagsSize};
const MAX_TYPE_DEPTH: u32 = 100;
macro_rules! indices {
($(
$(#[$a:meta])*
pub struct $name:ident(u32);
)*) => ($(
$(#[$a])*
#[derive(
Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug,
Serialize, Deserialize,
)]
pub struct $name(u32);
cranelift_entity::entity_impl!($name);
)*);
}
indices! {
pub struct ComponentTypeIndex(u32);
pub struct ModuleIndex(u32);
pub struct ComponentIndex(u32);
pub struct ModuleInstanceIndex(u32);
pub struct ComponentInstanceIndex(u32);
pub struct ComponentFuncIndex(u32);
pub struct TypeComponentIndex(u32);
pub struct TypeComponentInstanceIndex(u32);
pub struct TypeModuleIndex(u32);
pub struct TypeFuncIndex(u32);
pub struct TypeRecordIndex(u32);
pub struct TypeVariantIndex(u32);
pub struct TypeTupleIndex(u32);
pub struct TypeFlagsIndex(u32);
pub struct TypeEnumIndex(u32);
pub struct TypeUnionIndex(u32);
pub struct TypeOptionIndex(u32);
pub struct TypeResultIndex(u32);
pub struct TypeListIndex(u32);
pub struct ModuleUpvarIndex(u32);
pub struct ComponentUpvarIndex(u32);
pub struct StaticModuleIndex(u32);
pub struct StaticComponentIndex(u32);
pub struct RuntimeInstanceIndex(u32);
pub struct RuntimeComponentInstanceIndex(u32);
pub struct ImportIndex(u32);
pub struct RuntimeImportIndex(u32);
pub struct LoweredIndex(u32);
pub struct RuntimeAlwaysTrapIndex(u32);
pub struct RuntimeMemoryIndex(u32);
pub struct RuntimeReallocIndex(u32);
pub struct RuntimePostReturnIndex(u32);
pub struct RuntimeModuleIndex(u32);
pub struct RuntimeTranscoderIndex(u32);
}
pub use crate::{FuncIndex, GlobalIndex, MemoryIndex, TableIndex, TypeIndex};
#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
#[allow(missing_docs)]
pub enum ComponentItem {
Func(ComponentFuncIndex),
Module(ModuleIndex),
Component(ComponentIndex),
ComponentInstance(ComponentInstanceIndex),
Type(TypeDef),
}
#[derive(Default, Serialize, Deserialize)]
pub struct ComponentTypes {
modules: PrimaryMap<TypeModuleIndex, TypeModule>,
components: PrimaryMap<TypeComponentIndex, TypeComponent>,
component_instances: PrimaryMap<TypeComponentInstanceIndex, TypeComponentInstance>,
functions: PrimaryMap<TypeFuncIndex, TypeFunc>,
lists: PrimaryMap<TypeListIndex, TypeList>,
records: PrimaryMap<TypeRecordIndex, TypeRecord>,
variants: PrimaryMap<TypeVariantIndex, TypeVariant>,
tuples: PrimaryMap<TypeTupleIndex, TypeTuple>,
enums: PrimaryMap<TypeEnumIndex, TypeEnum>,
flags: PrimaryMap<TypeFlagsIndex, TypeFlags>,
unions: PrimaryMap<TypeUnionIndex, TypeUnion>,
options: PrimaryMap<TypeOptionIndex, TypeOption>,
results: PrimaryMap<TypeResultIndex, TypeResult>,
module_types: ModuleTypes,
}
impl ComponentTypes {
pub fn module_types(&self) -> &ModuleTypes {
&self.module_types
}
pub fn canonical_abi(&self, ty: &InterfaceType) -> &CanonicalAbiInfo {
match ty {
InterfaceType::U8 | InterfaceType::S8 | InterfaceType::Bool => {
&CanonicalAbiInfo::SCALAR1
}
InterfaceType::U16 | InterfaceType::S16 => &CanonicalAbiInfo::SCALAR2,
InterfaceType::U32
| InterfaceType::S32
| InterfaceType::Float32
| InterfaceType::Char => &CanonicalAbiInfo::SCALAR4,
InterfaceType::U64 | InterfaceType::S64 | InterfaceType::Float64 => {
&CanonicalAbiInfo::SCALAR8
}
InterfaceType::String | InterfaceType::List(_) => &CanonicalAbiInfo::POINTER_PAIR,
InterfaceType::Record(i) => &self[*i].abi,
InterfaceType::Variant(i) => &self[*i].abi,
InterfaceType::Tuple(i) => &self[*i].abi,
InterfaceType::Flags(i) => &self[*i].abi,
InterfaceType::Enum(i) => &self[*i].abi,
InterfaceType::Union(i) => &self[*i].abi,
InterfaceType::Option(i) => &self[*i].abi,
InterfaceType::Result(i) => &self[*i].abi,
}
}
}
macro_rules! impl_index {
($(impl Index<$ty:ident> for ComponentTypes { $output:ident => $field:ident })*) => ($(
impl std::ops::Index<$ty> for ComponentTypes {
type Output = $output;
fn index(&self, idx: $ty) -> &$output {
&self.$field[idx]
}
}
)*)
}
impl_index! {
impl Index<TypeModuleIndex> for ComponentTypes { TypeModule => modules }
impl Index<TypeComponentIndex> for ComponentTypes { TypeComponent => components }
impl Index<TypeComponentInstanceIndex> for ComponentTypes { TypeComponentInstance => component_instances }
impl Index<TypeFuncIndex> for ComponentTypes { TypeFunc => functions }
impl Index<TypeRecordIndex> for ComponentTypes { TypeRecord => records }
impl Index<TypeVariantIndex> for ComponentTypes { TypeVariant => variants }
impl Index<TypeTupleIndex> for ComponentTypes { TypeTuple => tuples }
impl Index<TypeEnumIndex> for ComponentTypes { TypeEnum => enums }
impl Index<TypeFlagsIndex> for ComponentTypes { TypeFlags => flags }
impl Index<TypeUnionIndex> for ComponentTypes { TypeUnion => unions }
impl Index<TypeOptionIndex> for ComponentTypes { TypeOption => options }
impl Index<TypeResultIndex> for ComponentTypes { TypeResult => results }
impl Index<TypeListIndex> for ComponentTypes { TypeList => lists }
}
impl<T> Index<T> for ComponentTypes
where
ModuleTypes: Index<T>,
{
type Output = <ModuleTypes as Index<T>>::Output;
fn index(&self, idx: T) -> &Self::Output {
self.module_types.index(idx)
}
}
#[derive(Default)]
pub struct ComponentTypesBuilder {
type_scopes: Vec<TypeScope>,
functions: HashMap<TypeFunc, TypeFuncIndex>,
lists: HashMap<TypeList, TypeListIndex>,
records: HashMap<TypeRecord, TypeRecordIndex>,
variants: HashMap<TypeVariant, TypeVariantIndex>,
tuples: HashMap<TypeTuple, TypeTupleIndex>,
enums: HashMap<TypeEnum, TypeEnumIndex>,
flags: HashMap<TypeFlags, TypeFlagsIndex>,
unions: HashMap<TypeUnion, TypeUnionIndex>,
options: HashMap<TypeOption, TypeOptionIndex>,
results: HashMap<TypeResult, TypeResultIndex>,
component_types: ComponentTypes,
module_types: ModuleTypesBuilder,
type_info: TypeInformationCache,
}
#[derive(Default)]
struct TypeScope {
core: PrimaryMap<TypeIndex, TypeDef>,
component: PrimaryMap<ComponentTypeIndex, TypeDef>,
}
macro_rules! intern_and_fill_flat_types {
($me:ident, $name:ident, $val:ident) => {{
if let Some(idx) = $me.$name.get(&$val) {
return *idx;
}
let idx = $me.component_types.$name.push($val.clone());
let mut info = TypeInformation::new();
info.$name($me, &$val);
let idx2 = $me.type_info.$name.push(info);
assert_eq!(idx, idx2);
$me.$name.insert($val, idx);
return idx;
}};
}
impl ComponentTypesBuilder {
pub fn finish(mut self) -> ComponentTypes {
self.component_types.module_types = self.module_types.finish();
self.component_types
}
pub fn component_types(&self) -> &ComponentTypes {
&self.component_types
}
pub fn module_types_builder(&mut self) -> &mut ModuleTypesBuilder {
&mut self.module_types
}
pub fn push_type_scope(&mut self) {
self.type_scopes.push(Default::default());
}
pub fn push_component_typedef(&mut self, ty: TypeDef) -> ComponentTypeIndex {
debug_assert!(!matches!(ty, TypeDef::Module(_) | TypeDef::CoreFunc(_)));
self.type_scopes.last_mut().unwrap().component.push(ty)
}
pub fn push_core_typedef(&mut self, ty: TypeDef) -> TypeIndex {
debug_assert!(matches!(ty, TypeDef::Module(_) | TypeDef::CoreFunc(_)));
self.type_scopes.last_mut().unwrap().core.push(ty)
}
pub fn component_outer_type(&self, count: u32, ty: ComponentTypeIndex) -> TypeDef {
let idx = self.type_scopes.len() - (count as usize) - 1;
self.type_scopes[idx].component[ty]
}
pub fn core_outer_type(&self, count: u32, ty: TypeIndex) -> TypeDef {
let idx = self.type_scopes.len() - (count as usize) - 1;
self.type_scopes[idx].core[ty]
}
pub fn pop_type_scope(&mut self) {
self.type_scopes.pop().unwrap();
}
pub fn intern_component_type(&mut self, ty: &wasmparser::ComponentType<'_>) -> Result<TypeDef> {
Ok(match ty {
wasmparser::ComponentType::Defined(ty) => TypeDef::Interface(self.defined_type(ty)?),
wasmparser::ComponentType::Func(ty) => TypeDef::ComponentFunc(self.func_type(ty)),
wasmparser::ComponentType::Component(ty) => {
TypeDef::Component(self.component_type(ty)?)
}
wasmparser::ComponentType::Instance(ty) => {
TypeDef::ComponentInstance(self.component_instance_type(ty)?)
}
})
}
pub fn intern_core_type(&mut self, ty: &wasmparser::CoreType<'_>) -> Result<TypeDef> {
Ok(match ty {
wasmparser::CoreType::Func(ty) => {
TypeDef::CoreFunc(self.module_types.wasm_func_type(ty.clone().try_into()?))
}
wasmparser::CoreType::Module(ty) => TypeDef::Module(self.module_type(ty)?),
})
}
pub fn component_type_ref(&self, ty: &wasmparser::ComponentTypeRef) -> TypeDef {
match ty {
wasmparser::ComponentTypeRef::Module(ty) => {
self.core_outer_type(0, TypeIndex::from_u32(*ty))
}
wasmparser::ComponentTypeRef::Func(ty)
| wasmparser::ComponentTypeRef::Type(wasmparser::TypeBounds::Eq, ty)
| wasmparser::ComponentTypeRef::Instance(ty)
| wasmparser::ComponentTypeRef::Component(ty) => {
self.component_outer_type(0, ComponentTypeIndex::from_u32(*ty))
}
wasmparser::ComponentTypeRef::Value(..) => {
unimplemented!("references to value types");
}
}
}
fn module_type(
&mut self,
ty: &[wasmparser::ModuleTypeDeclaration<'_>],
) -> Result<TypeModuleIndex> {
let mut result = TypeModule::default();
self.push_type_scope();
for item in ty {
match item {
wasmparser::ModuleTypeDeclaration::Type(wasmparser::Type::Func(f)) => {
let ty =
TypeDef::CoreFunc(self.module_types.wasm_func_type(f.clone().try_into()?));
self.push_core_typedef(ty);
}
wasmparser::ModuleTypeDeclaration::Export { name, ty } => {
let prev = result
.exports
.insert(name.to_string(), self.entity_type(ty)?);
assert!(prev.is_none());
}
wasmparser::ModuleTypeDeclaration::Import(import) => {
let prev = result.imports.insert(
(import.module.to_string(), import.name.to_string()),
self.entity_type(&import.ty)?,
);
assert!(prev.is_none());
}
wasmparser::ModuleTypeDeclaration::OuterAlias {
kind: wasmparser::OuterAliasKind::Type,
count,
index,
} => {
let ty = self.core_outer_type(*count, TypeIndex::from_u32(*index));
self.push_core_typedef(ty);
}
}
}
self.pop_type_scope();
Ok(self.component_types.modules.push(result))
}
fn entity_type(&self, ty: &wasmparser::TypeRef) -> Result<EntityType> {
Ok(match ty {
wasmparser::TypeRef::Func(idx) => {
let idx = TypeIndex::from_u32(*idx);
match self.core_outer_type(0, idx) {
TypeDef::CoreFunc(idx) => EntityType::Function(idx),
_ => unreachable!(), }
}
wasmparser::TypeRef::Table(ty) => EntityType::Table(ty.clone().try_into()?),
wasmparser::TypeRef::Memory(ty) => EntityType::Memory(ty.clone().into()),
wasmparser::TypeRef::Global(ty) => {
EntityType::Global(Global::new(ty.clone(), GlobalInit::Import)?)
}
wasmparser::TypeRef::Tag(_) => bail!("exceptions proposal not implemented"),
})
}
fn component_type(
&mut self,
ty: &[ComponentTypeDeclaration<'_>],
) -> Result<TypeComponentIndex> {
let mut result = TypeComponent::default();
self.push_type_scope();
for item in ty {
match item {
ComponentTypeDeclaration::Type(ty) => self.type_declaration_type(ty)?,
ComponentTypeDeclaration::CoreType(ty) => self.type_declaration_core_type(ty)?,
ComponentTypeDeclaration::Alias(alias) => self.type_declaration_alias(alias)?,
ComponentTypeDeclaration::Export { name, ty } => {
let ty = self.component_type_ref(ty);
result.exports.insert(name.to_string(), ty);
}
ComponentTypeDeclaration::Import(import) => {
let ty = self.component_type_ref(&import.ty);
result.imports.insert(import.name.to_string(), ty);
}
}
}
self.pop_type_scope();
Ok(self.component_types.components.push(result))
}
fn component_instance_type(
&mut self,
ty: &[InstanceTypeDeclaration<'_>],
) -> Result<TypeComponentInstanceIndex> {
let mut result = TypeComponentInstance::default();
self.push_type_scope();
for item in ty {
match item {
InstanceTypeDeclaration::Type(ty) => self.type_declaration_type(ty)?,
InstanceTypeDeclaration::CoreType(ty) => self.type_declaration_core_type(ty)?,
InstanceTypeDeclaration::Alias(alias) => self.type_declaration_alias(alias)?,
InstanceTypeDeclaration::Export { name, ty } => {
let ty = self.component_type_ref(ty);
result.exports.insert(name.to_string(), ty);
}
}
}
self.pop_type_scope();
Ok(self.component_types.component_instances.push(result))
}
fn type_declaration_type(&mut self, ty: &wasmparser::ComponentType<'_>) -> Result<()> {
let ty = self.intern_component_type(ty)?;
self.push_component_typedef(ty);
Ok(())
}
fn type_declaration_core_type(&mut self, ty: &wasmparser::CoreType<'_>) -> Result<()> {
let ty = self.intern_core_type(ty)?;
self.push_core_typedef(ty);
Ok(())
}
fn type_declaration_alias(&mut self, alias: &wasmparser::ComponentAlias<'_>) -> Result<()> {
match alias {
ComponentAlias::Outer {
kind: ComponentOuterAliasKind::CoreType,
count,
index,
} => {
let ty = self.core_outer_type(*count, TypeIndex::from_u32(*index));
self.push_core_typedef(ty);
}
ComponentAlias::Outer {
kind: ComponentOuterAliasKind::Type,
count,
index,
} => {
let ty = self.component_outer_type(*count, ComponentTypeIndex::from_u32(*index));
self.push_component_typedef(ty);
}
a => unreachable!("invalid alias {a:?}"),
}
Ok(())
}
fn func_type(&mut self, ty: &wasmparser::ComponentFuncType<'_>) -> TypeFuncIndex {
let ty = TypeFunc {
params: ty
.params
.iter()
.map(|(_name, ty)| self.valtype(ty))
.collect(),
results: ty
.results
.iter()
.map(|(_name, ty)| self.valtype(ty))
.collect(),
};
self.add_func_type(ty)
}
fn defined_type(&mut self, ty: &wasmparser::ComponentDefinedType<'_>) -> Result<InterfaceType> {
let result = match ty {
wasmparser::ComponentDefinedType::Primitive(ty) => ty.into(),
wasmparser::ComponentDefinedType::Record(e) => {
InterfaceType::Record(self.record_type(e))
}
wasmparser::ComponentDefinedType::Variant(e) => {
InterfaceType::Variant(self.variant_type(e))
}
wasmparser::ComponentDefinedType::List(e) => InterfaceType::List(self.list_type(e)),
wasmparser::ComponentDefinedType::Tuple(e) => InterfaceType::Tuple(self.tuple_type(e)),
wasmparser::ComponentDefinedType::Flags(e) => InterfaceType::Flags(self.flags_type(e)),
wasmparser::ComponentDefinedType::Enum(e) => InterfaceType::Enum(self.enum_type(e)),
wasmparser::ComponentDefinedType::Union(e) => InterfaceType::Union(self.union_type(e)),
wasmparser::ComponentDefinedType::Option(e) => {
InterfaceType::Option(self.option_type(e))
}
wasmparser::ComponentDefinedType::Result { ok, err } => {
InterfaceType::Result(self.result_type(ok, err))
}
};
let info = self.type_information(&result);
if info.depth > MAX_TYPE_DEPTH {
bail!("type nesting is too deep");
}
Ok(result)
}
fn valtype(&mut self, ty: &wasmparser::ComponentValType) -> InterfaceType {
match ty {
wasmparser::ComponentValType::Primitive(p) => p.into(),
wasmparser::ComponentValType::Type(idx) => {
let idx = ComponentTypeIndex::from_u32(*idx);
match self.component_outer_type(0, idx) {
TypeDef::Interface(ty) => ty,
_ => unreachable!(),
}
}
}
}
fn record_type(&mut self, record: &[(&str, wasmparser::ComponentValType)]) -> TypeRecordIndex {
let fields = record
.iter()
.map(|(name, ty)| RecordField {
name: name.to_string(),
ty: self.valtype(ty),
})
.collect::<Box<[_]>>();
let abi = CanonicalAbiInfo::record(
fields
.iter()
.map(|field| self.component_types.canonical_abi(&field.ty)),
);
self.add_record_type(TypeRecord { fields, abi })
}
fn variant_type(&mut self, cases: &[wasmparser::VariantCase<'_>]) -> TypeVariantIndex {
let cases = cases
.iter()
.map(|case| {
assert!(case.refines.is_none());
VariantCase {
name: case.name.to_string(),
ty: case.ty.as_ref().map(|ty| self.valtype(ty)),
}
})
.collect::<Box<[_]>>();
let (info, abi) = VariantInfo::new(cases.iter().map(|c| {
c.ty.as_ref()
.map(|ty| self.component_types.canonical_abi(ty))
}));
self.add_variant_type(TypeVariant { cases, abi, info })
}
fn tuple_type(&mut self, types: &[wasmparser::ComponentValType]) -> TypeTupleIndex {
let types = types
.iter()
.map(|ty| self.valtype(ty))
.collect::<Box<[_]>>();
let abi = CanonicalAbiInfo::record(
types
.iter()
.map(|ty| self.component_types.canonical_abi(ty)),
);
self.add_tuple_type(TypeTuple { types, abi })
}
fn flags_type(&mut self, flags: &[&str]) -> TypeFlagsIndex {
let flags = TypeFlags {
names: flags.iter().map(|s| s.to_string()).collect(),
abi: CanonicalAbiInfo::flags(flags.len()),
};
self.add_flags_type(flags)
}
fn enum_type(&mut self, variants: &[&str]) -> TypeEnumIndex {
let names = variants.iter().map(|s| s.to_string()).collect::<Box<[_]>>();
let (info, abi) = VariantInfo::new(names.iter().map(|_| None));
self.add_enum_type(TypeEnum { names, abi, info })
}
fn union_type(&mut self, types: &[wasmparser::ComponentValType]) -> TypeUnionIndex {
let types = types
.iter()
.map(|ty| self.valtype(ty))
.collect::<Box<[_]>>();
let (info, abi) = VariantInfo::new(
types
.iter()
.map(|t| Some(self.component_types.canonical_abi(t))),
);
self.add_union_type(TypeUnion { types, abi, info })
}
fn option_type(&mut self, ty: &wasmparser::ComponentValType) -> TypeOptionIndex {
let ty = self.valtype(ty);
let (info, abi) = VariantInfo::new([None, Some(self.component_types.canonical_abi(&ty))]);
self.add_option_type(TypeOption { ty, abi, info })
}
fn result_type(
&mut self,
ok: &Option<wasmparser::ComponentValType>,
err: &Option<wasmparser::ComponentValType>,
) -> TypeResultIndex {
let ok = ok.as_ref().map(|ty| self.valtype(ty));
let err = err.as_ref().map(|ty| self.valtype(ty));
let (info, abi) = VariantInfo::new([
ok.as_ref().map(|t| self.component_types.canonical_abi(t)),
err.as_ref().map(|t| self.component_types.canonical_abi(t)),
]);
self.add_result_type(TypeResult { ok, err, abi, info })
}
fn list_type(&mut self, ty: &wasmparser::ComponentValType) -> TypeListIndex {
let element = self.valtype(ty);
self.add_list_type(TypeList { element })
}
pub fn add_func_type(&mut self, ty: TypeFunc) -> TypeFuncIndex {
intern(&mut self.functions, &mut self.component_types.functions, ty)
}
pub fn add_record_type(&mut self, ty: TypeRecord) -> TypeRecordIndex {
intern_and_fill_flat_types!(self, records, ty)
}
pub fn add_flags_type(&mut self, ty: TypeFlags) -> TypeFlagsIndex {
intern_and_fill_flat_types!(self, flags, ty)
}
pub fn add_tuple_type(&mut self, ty: TypeTuple) -> TypeTupleIndex {
intern_and_fill_flat_types!(self, tuples, ty)
}
pub fn add_variant_type(&mut self, ty: TypeVariant) -> TypeVariantIndex {
intern_and_fill_flat_types!(self, variants, ty)
}
pub fn add_union_type(&mut self, ty: TypeUnion) -> TypeUnionIndex {
intern_and_fill_flat_types!(self, unions, ty)
}
pub fn add_enum_type(&mut self, ty: TypeEnum) -> TypeEnumIndex {
intern_and_fill_flat_types!(self, enums, ty)
}
pub fn add_option_type(&mut self, ty: TypeOption) -> TypeOptionIndex {
intern_and_fill_flat_types!(self, options, ty)
}
pub fn add_result_type(&mut self, ty: TypeResult) -> TypeResultIndex {
intern_and_fill_flat_types!(self, results, ty)
}
pub fn add_list_type(&mut self, ty: TypeList) -> TypeListIndex {
intern_and_fill_flat_types!(self, lists, ty)
}
pub fn canonical_abi(&self, ty: &InterfaceType) -> &CanonicalAbiInfo {
self.component_types.canonical_abi(ty)
}
pub fn flat_types(&self, ty: &InterfaceType) -> Option<FlatTypes<'_>> {
self.type_information(ty).flat.as_flat_types()
}
fn type_information(&self, ty: &InterfaceType) -> &TypeInformation {
match ty {
InterfaceType::U8
| InterfaceType::S8
| InterfaceType::Bool
| InterfaceType::U16
| InterfaceType::S16
| InterfaceType::U32
| InterfaceType::S32
| InterfaceType::Char => {
static INFO: TypeInformation = TypeInformation::primitive(FlatType::I32);
&INFO
}
InterfaceType::U64 | InterfaceType::S64 => {
static INFO: TypeInformation = TypeInformation::primitive(FlatType::I64);
&INFO
}
InterfaceType::Float32 => {
static INFO: TypeInformation = TypeInformation::primitive(FlatType::F32);
&INFO
}
InterfaceType::Float64 => {
static INFO: TypeInformation = TypeInformation::primitive(FlatType::F64);
&INFO
}
InterfaceType::String => {
static INFO: TypeInformation = TypeInformation::string();
&INFO
}
InterfaceType::List(i) => &self.type_info.lists[*i],
InterfaceType::Record(i) => &self.type_info.records[*i],
InterfaceType::Variant(i) => &self.type_info.variants[*i],
InterfaceType::Tuple(i) => &self.type_info.tuples[*i],
InterfaceType::Flags(i) => &self.type_info.flags[*i],
InterfaceType::Enum(i) => &self.type_info.enums[*i],
InterfaceType::Union(i) => &self.type_info.unions[*i],
InterfaceType::Option(i) => &self.type_info.options[*i],
InterfaceType::Result(i) => &self.type_info.results[*i],
}
}
}
impl<T> Index<T> for ComponentTypesBuilder
where
ComponentTypes: Index<T>,
{
type Output = <ComponentTypes as Index<T>>::Output;
fn index(&self, sig: T) -> &Self::Output {
&self.component_types[sig]
}
}
fn intern<T, U>(map: &mut HashMap<T, U>, list: &mut PrimaryMap<U, T>, item: T) -> U
where
T: Hash + Clone + Eq,
U: Copy + EntityRef,
{
if let Some(idx) = map.get(&item) {
return *idx;
}
let idx = list.push(item.clone());
map.insert(item, idx);
return idx;
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub enum TypeDef {
Component(TypeComponentIndex),
ComponentInstance(TypeComponentInstanceIndex),
ComponentFunc(TypeFuncIndex),
Interface(InterfaceType),
Module(TypeModuleIndex),
CoreFunc(SignatureIndex),
}
#[derive(Serialize, Deserialize, Default)]
pub struct TypeModule {
pub imports: IndexMap<(String, String), EntityType>,
pub exports: IndexMap<String, EntityType>,
}
#[derive(Serialize, Deserialize, Default)]
pub struct TypeComponent {
pub imports: IndexMap<String, TypeDef>,
pub exports: IndexMap<String, TypeDef>,
}
#[derive(Serialize, Deserialize, Default)]
pub struct TypeComponentInstance {
pub exports: IndexMap<String, TypeDef>,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeFunc {
pub params: Box<[InterfaceType]>,
pub results: Box<[InterfaceType]>,
}
#[derive(Serialize, Deserialize, Copy, Clone, Hash, Eq, PartialEq, Debug)]
#[allow(missing_docs)]
pub enum InterfaceType {
Bool,
S8,
U8,
S16,
U16,
S32,
U32,
S64,
U64,
Float32,
Float64,
Char,
String,
Record(TypeRecordIndex),
Variant(TypeVariantIndex),
List(TypeListIndex),
Tuple(TypeTupleIndex),
Flags(TypeFlagsIndex),
Enum(TypeEnumIndex),
Union(TypeUnionIndex),
Option(TypeOptionIndex),
Result(TypeResultIndex),
}
impl From<&wasmparser::PrimitiveValType> for InterfaceType {
fn from(ty: &wasmparser::PrimitiveValType) -> InterfaceType {
match ty {
wasmparser::PrimitiveValType::Bool => InterfaceType::Bool,
wasmparser::PrimitiveValType::S8 => InterfaceType::S8,
wasmparser::PrimitiveValType::U8 => InterfaceType::U8,
wasmparser::PrimitiveValType::S16 => InterfaceType::S16,
wasmparser::PrimitiveValType::U16 => InterfaceType::U16,
wasmparser::PrimitiveValType::S32 => InterfaceType::S32,
wasmparser::PrimitiveValType::U32 => InterfaceType::U32,
wasmparser::PrimitiveValType::S64 => InterfaceType::S64,
wasmparser::PrimitiveValType::U64 => InterfaceType::U64,
wasmparser::PrimitiveValType::Float32 => InterfaceType::Float32,
wasmparser::PrimitiveValType::Float64 => InterfaceType::Float64,
wasmparser::PrimitiveValType::Char => InterfaceType::Char,
wasmparser::PrimitiveValType::String => InterfaceType::String,
}
}
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct CanonicalAbiInfo {
pub size32: u32,
pub align32: u32,
pub size64: u32,
pub align64: u32,
pub flat_count: Option<u8>,
}
impl Default for CanonicalAbiInfo {
fn default() -> CanonicalAbiInfo {
CanonicalAbiInfo {
size32: 0,
align32: 1,
size64: 0,
align64: 1,
flat_count: Some(0),
}
}
}
const fn align_to(a: u32, b: u32) -> u32 {
assert!(b.is_power_of_two());
(a + (b - 1)) & !(b - 1)
}
const fn max(a: u32, b: u32) -> u32 {
if a > b {
a
} else {
b
}
}
impl CanonicalAbiInfo {
const ZERO: CanonicalAbiInfo = CanonicalAbiInfo {
size32: 0,
align32: 1,
size64: 0,
align64: 1,
flat_count: Some(0),
};
pub const SCALAR1: CanonicalAbiInfo = CanonicalAbiInfo::scalar(1);
pub const SCALAR2: CanonicalAbiInfo = CanonicalAbiInfo::scalar(2);
pub const SCALAR4: CanonicalAbiInfo = CanonicalAbiInfo::scalar(4);
pub const SCALAR8: CanonicalAbiInfo = CanonicalAbiInfo::scalar(8);
const fn scalar(size: u32) -> CanonicalAbiInfo {
CanonicalAbiInfo {
size32: size,
align32: size,
size64: size,
align64: size,
flat_count: Some(1),
}
}
pub const POINTER_PAIR: CanonicalAbiInfo = CanonicalAbiInfo {
size32: 8,
align32: 4,
size64: 16,
align64: 8,
flat_count: Some(2),
};
pub fn record<'a>(fields: impl Iterator<Item = &'a CanonicalAbiInfo>) -> CanonicalAbiInfo {
let mut ret = CanonicalAbiInfo::default();
for field in fields {
ret.size32 = align_to(ret.size32, field.align32) + field.size32;
ret.align32 = ret.align32.max(field.align32);
ret.size64 = align_to(ret.size64, field.align64) + field.size64;
ret.align64 = ret.align64.max(field.align64);
ret.flat_count = add_flat(ret.flat_count, field.flat_count);
}
ret.size32 = align_to(ret.size32, ret.align32);
ret.size64 = align_to(ret.size64, ret.align64);
return ret;
}
pub const fn record_static(fields: &[CanonicalAbiInfo]) -> CanonicalAbiInfo {
let mut ret = CanonicalAbiInfo::ZERO;
let mut i = 0;
while i < fields.len() {
let field = &fields[i];
ret.size32 = align_to(ret.size32, field.align32) + field.size32;
ret.align32 = max(ret.align32, field.align32);
ret.size64 = align_to(ret.size64, field.align64) + field.size64;
ret.align64 = max(ret.align64, field.align64);
ret.flat_count = add_flat(ret.flat_count, field.flat_count);
i += 1;
}
ret.size32 = align_to(ret.size32, ret.align32);
ret.size64 = align_to(ret.size64, ret.align64);
return ret;
}
pub fn next_field32(&self, offset: &mut u32) -> u32 {
*offset = align_to(*offset, self.align32) + self.size32;
*offset - self.size32
}
pub fn next_field32_size(&self, offset: &mut usize) -> usize {
let cur = u32::try_from(*offset).unwrap();
let cur = align_to(cur, self.align32) + self.size32;
*offset = usize::try_from(cur).unwrap();
usize::try_from(cur - self.size32).unwrap()
}
pub fn next_field64(&self, offset: &mut u32) -> u32 {
*offset = align_to(*offset, self.align64) + self.size64;
*offset - self.size64
}
pub fn next_field64_size(&self, offset: &mut usize) -> usize {
let cur = u32::try_from(*offset).unwrap();
let cur = align_to(cur, self.align64) + self.size64;
*offset = usize::try_from(cur).unwrap();
usize::try_from(cur - self.size64).unwrap()
}
pub const fn flags(count: usize) -> CanonicalAbiInfo {
let (size, align, flat_count) = match FlagsSize::from_count(count) {
FlagsSize::Size0 => (0, 1, 0),
FlagsSize::Size1 => (1, 1, 1),
FlagsSize::Size2 => (2, 2, 1),
FlagsSize::Size4Plus(n) => ((n as u32) * 4, 4, n),
};
CanonicalAbiInfo {
size32: size,
align32: align,
size64: size,
align64: align,
flat_count: Some(flat_count),
}
}
fn variant<'a, I>(cases: I) -> CanonicalAbiInfo
where
I: IntoIterator<Item = Option<&'a CanonicalAbiInfo>>,
I::IntoIter: ExactSizeIterator,
{
let cases = cases.into_iter();
let discrim_size = u32::from(DiscriminantSize::from_count(cases.len()).unwrap());
let mut max_size32 = 0;
let mut max_align32 = discrim_size;
let mut max_size64 = 0;
let mut max_align64 = discrim_size;
let mut max_case_count = Some(0);
for case in cases {
if let Some(case) = case {
max_size32 = max_size32.max(case.size32);
max_align32 = max_align32.max(case.align32);
max_size64 = max_size64.max(case.size64);
max_align64 = max_align64.max(case.align64);
max_case_count = max_flat(max_case_count, case.flat_count);
}
}
CanonicalAbiInfo {
size32: align_to(
align_to(discrim_size, max_align32) + max_size32,
max_align32,
),
align32: max_align32,
size64: align_to(
align_to(discrim_size, max_align64) + max_size64,
max_align64,
),
align64: max_align64,
flat_count: add_flat(max_case_count, Some(1)),
}
}
pub const fn variant_static(cases: &[Option<CanonicalAbiInfo>]) -> CanonicalAbiInfo {
let discrim_size = match DiscriminantSize::from_count(cases.len()) {
Some(size) => size.byte_size(),
None => unreachable!(),
};
let mut max_size32 = 0;
let mut max_align32 = discrim_size;
let mut max_size64 = 0;
let mut max_align64 = discrim_size;
let mut max_case_count = Some(0);
let mut i = 0;
while i < cases.len() {
let case = &cases[i];
if let Some(case) = case {
max_size32 = max(max_size32, case.size32);
max_align32 = max(max_align32, case.align32);
max_size64 = max(max_size64, case.size64);
max_align64 = max(max_align64, case.align64);
max_case_count = max_flat(max_case_count, case.flat_count);
}
i += 1;
}
CanonicalAbiInfo {
size32: align_to(
align_to(discrim_size, max_align32) + max_size32,
max_align32,
),
align32: max_align32,
size64: align_to(
align_to(discrim_size, max_align64) + max_size64,
max_align64,
),
align64: max_align64,
flat_count: add_flat(max_case_count, Some(1)),
}
}
pub fn flat_count(&self, max: usize) -> Option<usize> {
let flat = usize::from(self.flat_count?);
if flat > max {
None
} else {
Some(flat)
}
}
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct VariantInfo {
#[serde(with = "serde_discrim_size")]
pub size: DiscriminantSize,
pub payload_offset32: u32,
pub payload_offset64: u32,
}
impl VariantInfo {
pub fn new<'a, I>(cases: I) -> (VariantInfo, CanonicalAbiInfo)
where
I: IntoIterator<Item = Option<&'a CanonicalAbiInfo>>,
I::IntoIter: ExactSizeIterator,
{
let cases = cases.into_iter();
let size = DiscriminantSize::from_count(cases.len()).unwrap();
let abi = CanonicalAbiInfo::variant(cases);
(
VariantInfo {
size,
payload_offset32: align_to(u32::from(size), abi.align32),
payload_offset64: align_to(u32::from(size), abi.align64),
},
abi,
)
}
pub const fn new_static(cases: &[Option<CanonicalAbiInfo>]) -> VariantInfo {
let size = match DiscriminantSize::from_count(cases.len()) {
Some(size) => size,
None => unreachable!(),
};
let abi = CanonicalAbiInfo::variant_static(cases);
VariantInfo {
size,
payload_offset32: align_to(size.byte_size(), abi.align32),
payload_offset64: align_to(size.byte_size(), abi.align64),
}
}
}
mod serde_discrim_size {
use super::DiscriminantSize;
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
pub fn serialize<S>(disc: &DiscriminantSize, ser: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
u32::from(*disc).serialize(ser)
}
pub fn deserialize<'de, D>(deser: D) -> Result<DiscriminantSize, D::Error>
where
D: Deserializer<'de>,
{
match u32::deserialize(deser)? {
1 => Ok(DiscriminantSize::Size1),
2 => Ok(DiscriminantSize::Size2),
4 => Ok(DiscriminantSize::Size4),
_ => Err(D::Error::custom("invalid discriminant size")),
}
}
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeRecord {
pub fields: Box<[RecordField]>,
pub abi: CanonicalAbiInfo,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct RecordField {
pub name: String,
pub ty: InterfaceType,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeVariant {
pub cases: Box<[VariantCase]>,
pub abi: CanonicalAbiInfo,
pub info: VariantInfo,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct VariantCase {
pub name: String,
pub ty: Option<InterfaceType>,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeTuple {
pub types: Box<[InterfaceType]>,
pub abi: CanonicalAbiInfo,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeFlags {
pub names: Box<[String]>,
pub abi: CanonicalAbiInfo,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeEnum {
pub names: Box<[String]>,
pub abi: CanonicalAbiInfo,
pub info: VariantInfo,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeUnion {
pub types: Box<[InterfaceType]>,
pub abi: CanonicalAbiInfo,
pub info: VariantInfo,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeOption {
pub ty: InterfaceType,
pub abi: CanonicalAbiInfo,
pub info: VariantInfo,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeResult {
pub ok: Option<InterfaceType>,
pub err: Option<InterfaceType>,
pub abi: CanonicalAbiInfo,
pub info: VariantInfo,
}
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeList {
pub element: InterfaceType,
}
const MAX_FLAT_TYPES: usize = if MAX_FLAT_PARAMS > MAX_FLAT_RESULTS {
MAX_FLAT_PARAMS
} else {
MAX_FLAT_RESULTS
};
const fn add_flat(a: Option<u8>, b: Option<u8>) -> Option<u8> {
const MAX: u8 = MAX_FLAT_TYPES as u8;
let sum = match (a, b) {
(Some(a), Some(b)) => match a.checked_add(b) {
Some(c) => c,
None => return None,
},
_ => return None,
};
if sum > MAX {
None
} else {
Some(sum)
}
}
const fn max_flat(a: Option<u8>, b: Option<u8>) -> Option<u8> {
match (a, b) {
(Some(a), Some(b)) => {
if a > b {
Some(a)
} else {
Some(b)
}
}
_ => None,
}
}
pub struct FlatTypes<'a> {
pub memory32: &'a [FlatType],
pub memory64: &'a [FlatType],
}
#[allow(missing_docs)]
impl FlatTypes<'_> {
pub fn len(&self) -> usize {
assert_eq!(self.memory32.len(), self.memory64.len());
self.memory32.len()
}
}
#[derive(PartialEq, Eq, Copy, Clone)]
#[allow(missing_docs)]
pub enum FlatType {
I32,
I64,
F32,
F64,
}
struct FlatTypesStorage {
memory32: [FlatType; MAX_FLAT_TYPES],
memory64: [FlatType; MAX_FLAT_TYPES],
len: u8,
}
impl FlatTypesStorage {
const fn new() -> FlatTypesStorage {
FlatTypesStorage {
memory32: [FlatType::I32; MAX_FLAT_TYPES],
memory64: [FlatType::I32; MAX_FLAT_TYPES],
len: 0,
}
}
fn as_flat_types(&self) -> Option<FlatTypes<'_>> {
let len = usize::from(self.len);
if len > MAX_FLAT_TYPES {
assert_eq!(len, MAX_FLAT_TYPES + 1);
None
} else {
Some(FlatTypes {
memory32: &self.memory32[..len],
memory64: &self.memory64[..len],
})
}
}
fn push(&mut self, t32: FlatType, t64: FlatType) -> bool {
let len = usize::from(self.len);
if len < MAX_FLAT_TYPES {
self.memory32[len] = t32;
self.memory64[len] = t64;
self.len += 1;
true
} else {
if len == MAX_FLAT_TYPES {
self.len += 1;
}
false
}
}
}
impl FlatType {
fn join(&mut self, other: FlatType) {
if *self == other {
return;
}
*self = match (*self, other) {
(FlatType::I32, FlatType::F32) | (FlatType::F32, FlatType::I32) => FlatType::I32,
_ => FlatType::I64,
};
}
}
#[derive(Default)]
struct TypeInformationCache {
records: PrimaryMap<TypeRecordIndex, TypeInformation>,
variants: PrimaryMap<TypeVariantIndex, TypeInformation>,
tuples: PrimaryMap<TypeTupleIndex, TypeInformation>,
enums: PrimaryMap<TypeEnumIndex, TypeInformation>,
flags: PrimaryMap<TypeFlagsIndex, TypeInformation>,
unions: PrimaryMap<TypeUnionIndex, TypeInformation>,
options: PrimaryMap<TypeOptionIndex, TypeInformation>,
results: PrimaryMap<TypeResultIndex, TypeInformation>,
lists: PrimaryMap<TypeListIndex, TypeInformation>,
}
struct TypeInformation {
depth: u32,
flat: FlatTypesStorage,
}
impl TypeInformation {
const fn new() -> TypeInformation {
TypeInformation {
depth: 0,
flat: FlatTypesStorage::new(),
}
}
const fn primitive(flat: FlatType) -> TypeInformation {
let mut info = TypeInformation::new();
info.depth = 1;
info.flat.memory32[0] = flat;
info.flat.memory64[0] = flat;
info.flat.len = 1;
info
}
const fn string() -> TypeInformation {
let mut info = TypeInformation::new();
info.depth = 1;
info.flat.memory32[0] = FlatType::I32;
info.flat.memory32[1] = FlatType::I32;
info.flat.memory64[0] = FlatType::I64;
info.flat.memory64[1] = FlatType::I64;
info.flat.len = 2;
info
}
fn build_record<'a>(&mut self, types: impl Iterator<Item = &'a TypeInformation>) {
self.depth = 1;
for info in types {
self.depth = self.depth.max(1 + info.depth);
match info.flat.as_flat_types() {
Some(types) => {
for (t32, t64) in types.memory32.iter().zip(types.memory64) {
if !self.flat.push(*t32, *t64) {
break;
}
}
}
None => {
self.flat.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap();
}
}
}
}
fn build_variant<'a, I>(&mut self, cases: I)
where
I: IntoIterator<Item = Option<&'a TypeInformation>>,
{
let cases = cases.into_iter();
self.flat.push(FlatType::I32, FlatType::I32);
self.depth = 1;
for info in cases {
let info = match info {
Some(info) => info,
None => continue,
};
self.depth = self.depth.max(1 + info.depth);
if usize::from(self.flat.len) > MAX_FLAT_TYPES {
continue;
}
let types = match info.flat.as_flat_types() {
Some(types) => types,
None => {
self.flat.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap();
continue;
}
};
if types.memory32.len() >= MAX_FLAT_TYPES {
self.flat.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap();
continue;
}
let dst = self
.flat
.memory32
.iter_mut()
.zip(&mut self.flat.memory64)
.skip(1);
for (i, ((t32, t64), (dst32, dst64))) in types
.memory32
.iter()
.zip(types.memory64)
.zip(dst)
.enumerate()
{
if i + 1 < usize::from(self.flat.len) {
dst32.join(*t32);
dst64.join(*t64);
} else {
self.flat.len += 1;
*dst32 = *t32;
*dst64 = *t64;
}
}
}
}
fn records(&mut self, types: &ComponentTypesBuilder, ty: &TypeRecord) {
self.build_record(ty.fields.iter().map(|f| types.type_information(&f.ty)));
}
fn tuples(&mut self, types: &ComponentTypesBuilder, ty: &TypeTuple) {
self.build_record(ty.types.iter().map(|t| types.type_information(t)));
}
fn enums(&mut self, _types: &ComponentTypesBuilder, _ty: &TypeEnum) {
self.depth = 1;
self.flat.push(FlatType::I32, FlatType::I32);
}
fn flags(&mut self, _types: &ComponentTypesBuilder, ty: &TypeFlags) {
self.depth = 1;
match FlagsSize::from_count(ty.names.len()) {
FlagsSize::Size0 => {}
FlagsSize::Size1 | FlagsSize::Size2 => {
self.flat.push(FlatType::I32, FlatType::I32);
}
FlagsSize::Size4Plus(n) => {
for _ in 0..n {
self.flat.push(FlatType::I32, FlatType::I32);
}
}
}
}
fn variants(&mut self, types: &ComponentTypesBuilder, ty: &TypeVariant) {
self.build_variant(
ty.cases
.iter()
.map(|c| c.ty.as_ref().map(|ty| types.type_information(ty))),
)
}
fn unions(&mut self, types: &ComponentTypesBuilder, ty: &TypeUnion) {
self.build_variant(ty.types.iter().map(|t| Some(types.type_information(t))))
}
fn results(&mut self, types: &ComponentTypesBuilder, ty: &TypeResult) {
self.build_variant([
ty.ok.as_ref().map(|ty| types.type_information(ty)),
ty.err.as_ref().map(|ty| types.type_information(ty)),
])
}
fn options(&mut self, types: &ComponentTypesBuilder, ty: &TypeOption) {
self.build_variant([None, Some(types.type_information(&ty.ty))]);
}
fn lists(&mut self, types: &ComponentTypesBuilder, ty: &TypeList) {
*self = TypeInformation::string();
let info = types.type_information(&ty.element);
self.depth += info.depth;
}
}