use super::core::Module;
#[cfg(feature = "component-model")]
use crate::validator::component::ComponentState;
#[cfg(feature = "component-model")]
use crate::validator::component_types::{ComponentTypeAlloc, ComponentTypeList};
use crate::{AbstractHeapType, collections::map::Entry};
use crate::{CompositeInnerType, prelude::*};
use crate::{
Export, ExternalKind, GlobalType, Import, Matches, MemoryType, PackedIndex, RecGroup, RefType,
Result, SubType, TableType, TypeRef, UnpackedIndex, ValType, WithRecGroup,
};
use crate::{FuncType, HeapType, ValidatorId};
use alloc::sync::Arc;
use core::ops::{Deref, DerefMut, Index, Range};
use core::{hash::Hash, mem};
pub trait TypeIdentifier: core::fmt::Debug + Copy + Eq + Sized + 'static {
type Data: TypeData<Id = Self>;
#[doc(hidden)]
fn from_index(index: u32) -> Self;
#[doc(hidden)]
fn list(types: &TypeList) -> &SnapshotList<Self::Data>;
#[doc(hidden)]
fn list_mut(types: &mut TypeList) -> &mut SnapshotList<Self::Data>;
#[doc(hidden)]
fn index(&self) -> usize;
}
pub trait TypeData: core::fmt::Debug {
type Id: TypeIdentifier<Data = Self>;
const IS_CORE_SUB_TYPE: bool;
#[doc(hidden)]
fn type_info(&self, types: &TypeList) -> TypeInfo;
}
macro_rules! define_type_id {
($name:ident, $data:ty, $($list:ident).*, $type_str:expr) => {
#[doc = "Represents a unique identifier for a "]
#[doc = $type_str]
#[doc = " type known to a [`crate::Validator`]."]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)] pub struct $name {
/// The index into the associated list of types.
index: u32,
}
impl TypeIdentifier for $name {
type Data = $data;
fn from_index(index: u32) -> Self {
$name { index }
}
fn list(types: &TypeList) -> &SnapshotList<Self::Data> {
&types.$($list).*
}
fn list_mut(types: &mut TypeList) -> &mut SnapshotList<Self::Data> {
&mut types.$($list).*
}
fn index(&self) -> usize {
usize::try_from(self.index).unwrap()
}
}
const _: () = {
assert!(core::mem::size_of::<$name>() <= 4);
};
};
}
#[cfg(feature = "component-model")]
pub(crate) use define_type_id;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct CoreTypeId {
index: u32,
}
#[test]
fn assert_core_type_id_small() {
assert!(core::mem::size_of::<CoreTypeId>() <= 4);
}
impl TypeIdentifier for CoreTypeId {
type Data = SubType;
fn from_index(index: u32) -> Self {
CoreTypeId { index }
}
fn list(types: &TypeList) -> &SnapshotList<Self::Data> {
&types.core_types
}
fn list_mut(types: &mut TypeList) -> &mut SnapshotList<Self::Data> {
&mut types.core_types
}
fn index(&self) -> usize {
usize::try_from(self.index).unwrap()
}
}
impl TypeData for SubType {
type Id = CoreTypeId;
const IS_CORE_SUB_TYPE: bool = true;
fn type_info(&self, _types: &TypeList) -> TypeInfo {
let size = 1 + match &self.composite_type.inner {
CompositeInnerType::Func(ty) => 1 + (ty.params().len() + ty.results().len()) as u32,
CompositeInnerType::Array(_) => 2,
CompositeInnerType::Struct(ty) => 1 + 2 * ty.fields.len() as u32,
CompositeInnerType::Cont(_) => 1,
};
TypeInfo::core(size)
}
}
define_type_id!(
RecGroupId,
Range<CoreTypeId>,
rec_group_elements,
"recursion group"
);
impl TypeData for Range<CoreTypeId> {
type Id = RecGroupId;
const IS_CORE_SUB_TYPE: bool = true;
fn type_info(&self, _types: &TypeList) -> TypeInfo {
let size = self.end.index() - self.start.index();
TypeInfo::core(u32::try_from(size).unwrap())
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[doc(hidden)]
pub struct TypeInfo(u32);
impl TypeInfo {
pub(crate) fn new() -> TypeInfo {
TypeInfo::_new(1, false)
}
#[cfg(feature = "component-model")]
pub(crate) fn borrow() -> TypeInfo {
TypeInfo::_new(1, true)
}
pub(crate) fn core(size: u32) -> TypeInfo {
TypeInfo::_new(size, false)
}
fn _new(size: u32, contains_borrow: bool) -> TypeInfo {
assert!(size < (1 << 24));
TypeInfo(size | ((contains_borrow as u32) << 31))
}
#[cfg(feature = "component-model")]
pub(crate) fn combine(&mut self, other: TypeInfo, offset: usize) -> Result<()> {
*self = TypeInfo::_new(
super::combine_type_sizes(self.size(), other.size(), offset)?,
self.contains_borrow() || other.contains_borrow(),
);
Ok(())
}
pub(crate) fn size(&self) -> u32 {
self.0 & 0xffffff
}
#[cfg(feature = "component-model")]
pub(crate) fn contains_borrow(&self) -> bool {
(self.0 >> 31) != 0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EntityType {
Func(CoreTypeId),
Table(TableType),
Memory(MemoryType),
Global(GlobalType),
Tag(CoreTypeId),
FuncExact(CoreTypeId),
}
impl EntityType {
#[cfg(feature = "component-model")]
pub(crate) fn desc(&self) -> &'static str {
match self {
Self::Func(_) => "func",
Self::Table(_) => "table",
Self::Memory(_) => "memory",
Self::Global(_) => "global",
Self::Tag(_) => "tag",
Self::FuncExact(_) => "func_exact",
}
}
pub(crate) fn info(&self, types: &TypeList) -> TypeInfo {
match self {
Self::Func(id) | Self::Tag(id) | Self::FuncExact(id) => types[*id].type_info(types),
Self::Table(_) | Self::Memory(_) | Self::Global(_) => TypeInfo::new(),
}
}
}
#[allow(clippy::large_enum_variant)]
pub(super) enum TypesKind {
Module(Arc<Module>),
#[cfg(feature = "component-model")]
Component(ComponentState),
}
pub struct Types {
id: ValidatorId,
pub(super) list: TypeList,
pub(super) kind: TypesKind,
}
#[derive(Clone, Copy)]
pub(super) enum TypesRefKind<'a> {
Module(&'a Module),
#[cfg(feature = "component-model")]
Component(&'a ComponentState),
}
#[derive(Clone, Copy)]
pub struct TypesRef<'a> {
id: ValidatorId,
pub(super) list: &'a TypeList,
pub(super) kind: TypesRefKind<'a>,
}
impl<'a> TypesRef<'a> {
pub(crate) fn from_module(id: ValidatorId, types: &'a TypeList, module: &'a Module) -> Self {
Self {
id,
list: types,
kind: TypesRefKind::Module(module),
}
}
#[cfg(feature = "component-model")]
pub(crate) fn from_component(
id: ValidatorId,
types: &'a TypeList,
component: &'a ComponentState,
) -> Self {
Self {
id,
list: types,
kind: TypesRefKind::Component(component),
}
}
#[inline]
pub fn id(&self) -> ValidatorId {
self.id
}
pub fn get<T>(&self, id: T) -> Option<&'a T::Data>
where
T: TypeIdentifier,
{
self.list.get(id)
}
pub fn rec_group_id_of(&self, id: CoreTypeId) -> RecGroupId {
self.list.rec_group_id_of(id)
}
pub fn rec_group_elements(&self, id: RecGroupId) -> impl ExactSizeIterator<Item = CoreTypeId> {
let range = &self.list.rec_group_elements[id];
(range.start.index..range.end.index).map(|index| CoreTypeId { index })
}
pub fn supertype_of(&self, id: CoreTypeId) -> Option<CoreTypeId> {
self.list.supertype_of(id)
}
pub fn core_type_at_in_module(&self, index: u32) -> CoreTypeId {
match &self.kind {
TypesRefKind::Module(module) => module.types[index as usize].into(),
#[cfg(feature = "component-model")]
TypesRefKind::Component(_) => panic!("use `core_type_at_in_component` instead"),
}
}
pub fn core_type_count_in_module(&self) -> u32 {
match &self.kind {
TypesRefKind::Module(module) => module.types.len() as u32,
#[cfg(feature = "component-model")]
TypesRefKind::Component(_) => 0,
}
}
pub fn table_at(&self, index: u32) -> TableType {
let tables = match &self.kind {
TypesRefKind::Module(module) => &module.tables,
#[cfg(feature = "component-model")]
TypesRefKind::Component(component) => &component.core_tables,
};
tables[index as usize]
}
pub fn table_count(&self) -> u32 {
match &self.kind {
TypesRefKind::Module(module) => module.tables.len() as u32,
#[cfg(feature = "component-model")]
TypesRefKind::Component(component) => component.core_tables.len() as u32,
}
}
pub fn memory_at(&self, index: u32) -> MemoryType {
let memories = match &self.kind {
TypesRefKind::Module(module) => &module.memories,
#[cfg(feature = "component-model")]
TypesRefKind::Component(component) => &component.core_memories,
};
memories[index as usize]
}
pub fn memory_count(&self) -> u32 {
match &self.kind {
TypesRefKind::Module(module) => module.memories.len() as u32,
#[cfg(feature = "component-model")]
TypesRefKind::Component(component) => component.core_memories.len() as u32,
}
}
pub fn global_at(&self, index: u32) -> GlobalType {
let globals = match &self.kind {
TypesRefKind::Module(module) => &module.globals,
#[cfg(feature = "component-model")]
TypesRefKind::Component(component) => &component.core_globals,
};
globals[index as usize]
}
pub fn global_count(&self) -> u32 {
match &self.kind {
TypesRefKind::Module(module) => module.globals.len() as u32,
#[cfg(feature = "component-model")]
TypesRefKind::Component(component) => component.core_globals.len() as u32,
}
}
pub fn tag_at(&self, index: u32) -> CoreTypeId {
let tags = match &self.kind {
TypesRefKind::Module(module) => &module.tags,
#[cfg(feature = "component-model")]
TypesRefKind::Component(component) => &component.core_tags,
};
tags[index as usize]
}
pub fn tag_count(&self) -> u32 {
match &self.kind {
TypesRefKind::Module(module) => module.tags.len() as u32,
#[cfg(feature = "component-model")]
TypesRefKind::Component(component) => component.core_tags.len() as u32,
}
}
pub fn core_function_at(&self, index: u32) -> CoreTypeId {
match &self.kind {
TypesRefKind::Module(module) => module.types[module.functions[index as usize] as usize],
#[cfg(feature = "component-model")]
TypesRefKind::Component(component) => component.core_funcs[index as usize],
}
}
pub fn function_count(&self) -> u32 {
match &self.kind {
TypesRefKind::Module(module) => module.functions.len() as u32,
#[cfg(feature = "component-model")]
TypesRefKind::Component(component) => component.core_funcs.len() as u32,
}
}
pub fn element_at(&self, index: u32) -> RefType {
match &self.kind {
TypesRefKind::Module(module) => module.element_types[index as usize],
#[cfg(feature = "component-model")]
TypesRefKind::Component(_) => {
panic!("no elements on a component")
}
}
}
pub fn element_count(&self) -> u32 {
match &self.kind {
TypesRefKind::Module(module) => module.element_types.len() as u32,
#[cfg(feature = "component-model")]
TypesRefKind::Component(_) => 0,
}
}
pub fn entity_type_from_import(&self, import: &Import) -> Option<EntityType> {
match &self.kind {
TypesRefKind::Module(module) => Some(match import.ty {
TypeRef::Func(idx) => EntityType::Func(*module.types.get(idx as usize)?),
TypeRef::FuncExact(idx) => EntityType::FuncExact(*module.types.get(idx as usize)?),
TypeRef::Table(ty) => EntityType::Table(ty),
TypeRef::Memory(ty) => EntityType::Memory(ty),
TypeRef::Global(ty) => EntityType::Global(ty),
TypeRef::Tag(ty) => EntityType::Tag(*module.types.get(ty.func_type_idx as usize)?),
}),
#[cfg(feature = "component-model")]
TypesRefKind::Component(_) => None,
}
}
pub fn entity_type_from_export(&self, export: &Export) -> Option<EntityType> {
match &self.kind {
TypesRefKind::Module(module) => Some(match export.kind {
ExternalKind::Func | ExternalKind::FuncExact => EntityType::Func(
module.types[*module.functions.get(export.index as usize)? as usize],
),
ExternalKind::Table => {
EntityType::Table(*module.tables.get(export.index as usize)?)
}
ExternalKind::Memory => {
EntityType::Memory(*module.memories.get(export.index as usize)?)
}
ExternalKind::Global => {
EntityType::Global(*module.globals.get(export.index as usize)?)
}
ExternalKind::Tag => EntityType::Tag(*module.tags.get(export.index as usize)?),
}),
#[cfg(feature = "component-model")]
TypesRefKind::Component(_) => None,
}
}
pub fn core_imports(
&self,
) -> Option<impl Iterator<Item = (&'a str, &'a str, EntityType)> + 'a> {
match &self.kind {
TypesRefKind::Module(module) => Some(
module
.imports
.iter()
.flat_map(|((m, n), t)| t.iter().map(move |t| (m.as_str(), n.as_str(), *t))),
),
#[cfg(feature = "component-model")]
TypesRefKind::Component(_) => None,
}
}
pub fn core_exports(&self) -> Option<impl Iterator<Item = (&'a str, EntityType)> + 'a> {
match &self.kind {
TypesRefKind::Module(module) => {
Some(module.exports.iter().map(|(n, t)| (n.as_str(), *t)))
}
#[cfg(feature = "component-model")]
TypesRefKind::Component(_) => None,
}
}
}
impl<T> Index<T> for TypesRef<'_>
where
T: TypeIdentifier,
{
type Output = T::Data;
fn index(&self, index: T) -> &Self::Output {
&self.list[index]
}
}
impl Types {
pub(crate) fn from_module(id: ValidatorId, types: TypeList, module: Arc<Module>) -> Self {
Self {
id,
list: types,
kind: TypesKind::Module(module),
}
}
#[cfg(feature = "component-model")]
pub(crate) fn from_component(
id: ValidatorId,
types: TypeList,
component: ComponentState,
) -> Self {
Self {
id,
list: types,
kind: TypesKind::Component(component),
}
}
pub fn as_ref(&self) -> TypesRef<'_> {
TypesRef {
id: self.id,
list: &self.list,
kind: match &self.kind {
TypesKind::Module(module) => TypesRefKind::Module(module),
#[cfg(feature = "component-model")]
TypesKind::Component(component) => TypesRefKind::Component(component),
},
}
}
}
impl<T> Index<T> for Types
where
T: TypeIdentifier,
{
type Output = T::Data;
fn index(&self, id: T) -> &Self::Output {
&self.list[id]
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct SnapshotList<T> {
snapshots: Vec<Arc<Snapshot<T>>>,
snapshots_total: usize,
cur: Vec<T>,
}
#[derive(Debug)]
struct Snapshot<T> {
prior_types: usize,
items: Vec<T>,
}
impl<T> SnapshotList<T> {
pub(crate) fn get(&self, index: usize) -> Option<&T> {
if index >= self.snapshots_total {
return self.cur.get(index - self.snapshots_total);
}
let i = match self
.snapshots
.binary_search_by_key(&index, |snapshot| snapshot.prior_types)
{
Ok(i) => i,
Err(i) => i - 1,
};
let snapshot = &self.snapshots[i];
Some(&snapshot.items[index - snapshot.prior_types])
}
pub(crate) fn push(&mut self, val: T) {
self.cur.push(val);
}
pub(crate) fn len(&self) -> usize {
self.cur.len() + self.snapshots_total
}
#[cfg(feature = "component-model")]
pub(crate) fn truncate(&mut self, len: usize) {
assert!(len >= self.snapshots_total);
self.cur.truncate(len - self.snapshots_total);
}
pub(crate) fn commit(&mut self) -> SnapshotList<T> {
let len = self.cur.len();
if len > 0 {
self.cur.shrink_to_fit();
self.snapshots.push(Arc::new(Snapshot {
prior_types: self.snapshots_total,
items: mem::take(&mut self.cur),
}));
self.snapshots_total += len;
}
SnapshotList {
snapshots: self.snapshots.clone(),
snapshots_total: self.snapshots_total,
cur: Vec::new(),
}
}
}
impl<T> Index<usize> for SnapshotList<T> {
type Output = T;
#[inline]
fn index(&self, index: usize) -> &T {
match self.get(index) {
Some(x) => x,
None => panic!(
"out-of-bounds indexing into `SnapshotList`: index is {index}, but length is {}",
self.len()
),
}
}
}
impl<T, U> Index<U> for SnapshotList<T>
where
U: TypeIdentifier<Data = T>,
{
type Output = T;
#[inline]
fn index(&self, id: U) -> &T {
self.get(id.index()).unwrap()
}
}
impl<T> Default for SnapshotList<T> {
fn default() -> SnapshotList<T> {
SnapshotList {
snapshots: Vec::new(),
snapshots_total: 0,
cur: Vec::new(),
}
}
}
#[derive(Default, Debug)]
#[doc(hidden)]
pub struct TypeList {
pub(super) core_types: SnapshotList<SubType>,
pub(super) core_type_to_rec_group: SnapshotList<RecGroupId>,
pub(super) core_type_to_supertype: SnapshotList<Option<CoreTypeId>>,
pub(super) core_type_to_depth: Option<IndexMap<CoreTypeId, u8>>,
pub(super) rec_group_elements: SnapshotList<Range<CoreTypeId>>,
pub(super) canonical_rec_groups: Option<Map<RecGroup, RecGroupId>>,
#[cfg(feature = "component-model")]
pub(super) component: ComponentTypeList,
}
impl TypeList {
pub fn get<T>(&self, id: T) -> Option<&T::Data>
where
T: TypeIdentifier,
{
T::list(self).get(id.index())
}
pub fn push<T>(&mut self, ty: T) -> T::Id
where
T: TypeData,
{
let index = u32::try_from(T::Id::list(self).len()).unwrap();
let id = T::Id::from_index(index);
T::Id::list_mut(self).push(ty);
id
}
pub fn intern_canonical_rec_group(
&mut self,
needs_type_canonicalization: bool,
mut rec_group: RecGroup,
) -> (bool, RecGroupId) {
let rec_group_id = self.rec_group_elements.len();
let rec_group_id = u32::try_from(rec_group_id).unwrap();
let rec_group_id = RecGroupId::from_index(rec_group_id);
if needs_type_canonicalization {
let canonical_rec_groups = self
.canonical_rec_groups
.as_mut()
.expect("cannot intern into a committed list");
let entry = match canonical_rec_groups.entry(rec_group) {
Entry::Occupied(e) => return (false, *e.get()),
Entry::Vacant(e) => e,
};
rec_group = entry.key().clone();
entry.insert(rec_group_id);
}
let start = self.core_types.len();
let start = u32::try_from(start).unwrap();
let start = CoreTypeId::from_index(start);
for mut ty in rec_group.into_types() {
debug_assert_eq!(self.core_types.len(), self.core_type_to_supertype.len());
debug_assert_eq!(self.core_types.len(), self.core_type_to_rec_group.len());
self.core_type_to_supertype
.push(ty.supertype_idx.and_then(|idx| match idx.unpack() {
UnpackedIndex::RecGroup(offset) => {
Some(CoreTypeId::from_index(start.index + offset))
}
UnpackedIndex::Id(id) => Some(id),
UnpackedIndex::Module(_) => None,
}));
ty.remap_indices(&mut |index| {
if let UnpackedIndex::RecGroup(offset) = index.unpack() {
*index = UnpackedIndex::Id(CoreTypeId::from_index(start.index + offset))
.pack()
.unwrap();
}
Ok(())
})
.expect("cannot fail");
self.core_types.push(ty);
self.core_type_to_rec_group.push(rec_group_id);
}
let end = self.core_types.len();
let end = u32::try_from(end).unwrap();
let end = CoreTypeId::from_index(end);
let range = start..end;
self.rec_group_elements.push(range.clone());
return (true, rec_group_id);
}
pub fn intern_sub_type(&mut self, sub_ty: SubType, offset: usize) -> CoreTypeId {
let (_is_new, group_id) =
self.intern_canonical_rec_group(true, RecGroup::implicit(offset, sub_ty));
self[group_id].start
}
pub fn intern_func_type(&mut self, ty: FuncType, offset: usize) -> CoreTypeId {
self.intern_sub_type(SubType::func(ty, false), offset)
}
pub fn rec_group_local_id(
&self,
rec_group: RecGroupId,
index: u32,
offset: usize,
) -> Result<CoreTypeId> {
let elems = &self[rec_group];
let len = elems.end.index() - elems.start.index();
let len = u32::try_from(len).unwrap();
if index < len {
let id = u32::try_from(elems.start.index()).unwrap() + index;
let id = CoreTypeId::from_index(id);
Ok(id)
} else {
bail!(
offset,
"unknown type {index}: type index out of rec group bounds"
)
}
}
pub fn rec_group_id_of(&self, id: CoreTypeId) -> RecGroupId {
self.core_type_to_rec_group[id.index()]
}
pub fn supertype_of(&self, id: CoreTypeId) -> Option<CoreTypeId> {
self.core_type_to_supertype[id.index()]
}
pub fn get_subtyping_depth(&self, id: CoreTypeId) -> u8 {
let depth = self
.core_type_to_depth
.as_ref()
.expect("cannot get subtype depth from a committed list")[&id];
debug_assert!(usize::from(depth) <= crate::limits::MAX_WASM_SUBTYPING_DEPTH);
depth
}
pub fn set_subtyping_depth(&mut self, id: CoreTypeId, depth: u8) {
debug_assert!(usize::from(depth) <= crate::limits::MAX_WASM_SUBTYPING_DEPTH);
let map = self
.core_type_to_depth
.as_mut()
.expect("cannot set a subtype depth in a committed list");
debug_assert!(!map.contains_key(&id));
map.insert(id, depth);
}
pub fn at_canonicalized_packed_index(
&self,
rec_group: RecGroupId,
index: PackedIndex,
offset: usize,
) -> Result<CoreTypeId> {
self.at_canonicalized_unpacked_index(rec_group, index.unpack(), offset)
}
pub fn at_canonicalized_unpacked_index(
&self,
rec_group: RecGroupId,
index: UnpackedIndex,
offset: usize,
) -> Result<CoreTypeId> {
match index {
UnpackedIndex::Module(_) => panic!("not canonicalized"),
UnpackedIndex::Id(id) => Ok(id),
UnpackedIndex::RecGroup(idx) => self.rec_group_local_id(rec_group, idx, offset),
}
}
pub fn matches(&self, a: CoreTypeId, b: CoreTypeId) -> bool {
let a = WithRecGroup::new(self, a);
let a = WithRecGroup::map(a, |a| &self[a]);
let b = WithRecGroup::new(self, b);
let b = WithRecGroup::map(b, |b| &self[b]);
Matches::matches(self, a, b)
}
pub fn id_is_subtype(&self, mut a: CoreTypeId, b: CoreTypeId) -> bool {
loop {
if a == b {
return true;
}
a = match self.supertype_of(a) {
Some(a) => a,
None => return false,
};
}
}
pub fn reftype_is_subtype(&self, a: RefType, b: RefType) -> bool {
self.reftype_is_subtype_impl(a, None, b, None)
}
pub(crate) fn reftype_is_subtype_impl(
&self,
a: RefType,
a_group: Option<RecGroupId>,
b: RefType,
b_group: Option<RecGroupId>,
) -> bool {
if a == b && a_group == b_group {
return true;
}
if a.is_nullable() && !b.is_nullable() {
return false;
}
let core_type_id = |group: Option<RecGroupId>, index: UnpackedIndex| -> CoreTypeId {
if let Some(id) = index.as_core_type_id() {
id
} else {
self.at_canonicalized_unpacked_index(group.unwrap(), index, usize::MAX)
.expect("type references are checked during canonicalization")
}
};
let subtype = |group, index| -> &SubType {
let id = core_type_id(group, index);
&self[id]
};
use AbstractHeapType::*;
use CompositeInnerType as CT;
use HeapType as HT;
match (a.heap_type(), b.heap_type()) {
(a, b) if a == b => true,
(
HT::Abstract {
shared: a_shared,
ty: a_ty,
},
HT::Abstract {
shared: b_shared,
ty: b_ty,
},
) => a_shared == b_shared && a_ty.is_subtype_of(b_ty),
(HT::Concrete(a), HT::Abstract { shared, ty })
| (HT::Exact(a), HT::Abstract { shared, ty }) => {
let a_ty = &subtype(a_group, a).composite_type;
if a_ty.shared != shared {
return false;
}
match ty {
Any | Eq => matches!(a_ty.inner, CT::Array(_) | CT::Struct(_)),
Struct => matches!(a_ty.inner, CT::Struct(_)),
Array => matches!(a_ty.inner, CT::Array(_)),
Func => matches!(a_ty.inner, CT::Func(_)),
Cont => matches!(a_ty.inner, CT::Cont(_)),
Extern | Exn | I31 | None | NoFunc | NoExtern | NoExn | NoCont => false,
}
}
(HT::Abstract { shared, ty }, HT::Concrete(b))
| (HT::Abstract { shared, ty }, HT::Exact(b)) => {
let b_ty = &subtype(b_group, b).composite_type;
if shared != b_ty.shared {
return false;
}
match ty {
None => matches!(b_ty.inner, CT::Array(_) | CT::Struct(_)),
NoFunc => matches!(b_ty.inner, CT::Func(_)),
NoCont => matches!(b_ty.inner, CT::Cont(_)),
Cont | Func | Extern | Exn | Any | Eq | Array | I31 | Struct | NoExtern
| NoExn => false,
}
}
(HT::Concrete(a), HT::Concrete(b)) | (HT::Exact(a), HT::Concrete(b)) => {
self.id_is_subtype(core_type_id(a_group, a), core_type_id(b_group, b))
}
(HT::Exact(a), HT::Exact(b)) => core_type_id(a_group, a) == core_type_id(b_group, b),
(HT::Concrete(_), HT::Exact(_)) => false,
}
}
pub fn valtype_is_subtype(&self, a: ValType, b: ValType) -> bool {
match (a, b) {
(a, b) if a == b => true,
(ValType::Ref(a), ValType::Ref(b)) => self.reftype_is_subtype(a, b),
(ValType::Ref(_), _)
| (ValType::I32, _)
| (ValType::I64, _)
| (ValType::F32, _)
| (ValType::F64, _)
| (ValType::V128, _) => false,
}
}
pub fn valtype_is_shared(&self, ty: ValType) -> bool {
match ty {
ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => true,
ValType::Ref(rt) => self.reftype_is_shared(rt),
}
}
pub fn reftype_is_shared(&self, ty: RefType) -> bool {
match ty.heap_type() {
HeapType::Abstract { shared, .. } => shared,
HeapType::Concrete(index) | HeapType::Exact(index) => {
self[index.as_core_type_id().unwrap()].composite_type.shared
}
}
}
pub fn top_type(&self, heap_type: &HeapType) -> HeapType {
use AbstractHeapType::*;
match *heap_type {
HeapType::Concrete(idx) | HeapType::Exact(idx) => {
let ty = &self[idx.as_core_type_id().unwrap()].composite_type;
let shared = ty.shared;
match ty.inner {
CompositeInnerType::Func(_) => HeapType::Abstract { shared, ty: Func },
CompositeInnerType::Array(_) | CompositeInnerType::Struct(_) => {
HeapType::Abstract { shared, ty: Any }
}
CompositeInnerType::Cont(_) => HeapType::Abstract { shared, ty: Cont },
}
}
HeapType::Abstract { shared, ty } => {
let ty = match ty {
Func | NoFunc => Func,
Extern | NoExtern => Extern,
Any | Eq | Struct | Array | I31 | None => Any,
Exn | NoExn => Exn,
Cont | NoCont => Cont,
};
HeapType::Abstract { shared, ty }
}
}
}
pub fn commit(&mut self) -> TypeList {
TypeList {
core_types: self.core_types.commit(),
core_type_to_rec_group: self.core_type_to_rec_group.commit(),
core_type_to_supertype: self.core_type_to_supertype.commit(),
core_type_to_depth: None,
rec_group_elements: self.rec_group_elements.commit(),
canonical_rec_groups: None,
#[cfg(feature = "component-model")]
component: self.component.commit(),
}
}
}
impl<T> Index<T> for TypeList
where
T: TypeIdentifier,
{
type Output = T::Data;
fn index(&self, id: T) -> &Self::Output {
let arena = T::list(self);
&arena[id.index()]
}
}
pub(crate) struct TypeAlloc {
list: TypeList,
#[cfg(feature = "component-model")]
pub(super) component_alloc: ComponentTypeAlloc,
}
impl Default for TypeAlloc {
fn default() -> TypeAlloc {
let mut ret = TypeAlloc {
list: TypeList::default(),
#[cfg(feature = "component-model")]
component_alloc: ComponentTypeAlloc::default(),
};
ret.list.core_type_to_depth = Some(Default::default());
ret.list.canonical_rec_groups = Some(Default::default());
ret
}
}
impl Deref for TypeAlloc {
type Target = TypeList;
fn deref(&self) -> &TypeList {
&self.list
}
}
impl DerefMut for TypeAlloc {
fn deref_mut(&mut self) -> &mut TypeList {
&mut self.list
}
}
impl<T> Index<T> for TypeAlloc
where
T: TypeIdentifier,
{
type Output = T::Data;
#[inline]
fn index(&self, id: T) -> &T::Data {
&self.list[id]
}
}