wasmparser/validator/
types.rs

1//! Types relating to type information provided by validation.
2
3use super::core::Module;
4#[cfg(feature = "component-model")]
5use crate::validator::component::ComponentState;
6#[cfg(feature = "component-model")]
7use crate::validator::component_types::{ComponentTypeAlloc, ComponentTypeList};
8use crate::{AbstractHeapType, collections::map::Entry};
9use crate::{CompositeInnerType, prelude::*};
10use crate::{
11    Export, ExternalKind, GlobalType, Import, Matches, MemoryType, PackedIndex, RecGroup, RefType,
12    Result, SubType, TableType, TypeRef, UnpackedIndex, ValType, WithRecGroup,
13};
14use crate::{FuncType, HeapType, ValidatorId};
15use alloc::sync::Arc;
16use core::ops::{Deref, DerefMut, Index, Range};
17use core::{hash::Hash, mem};
18
19/// A trait shared by all type identifiers.
20///
21/// Any id that can be used to get a type from a `Types`.
22//
23// Or, internally, from a `TypeList`.
24pub trait TypeIdentifier: core::fmt::Debug + Copy + Eq + Sized + 'static {
25    /// The data pointed to by this type of id.
26    type Data: TypeData<Id = Self>;
27
28    /// Create a type id from an index.
29    #[doc(hidden)]
30    fn from_index(index: u32) -> Self;
31
32    /// Get a shared reference to the list where this id's type data is stored
33    /// within.
34    #[doc(hidden)]
35    fn list(types: &TypeList) -> &SnapshotList<Self::Data>;
36
37    /// Get an exclusive reference to the list where this id's type data is
38    /// stored within.
39    #[doc(hidden)]
40    fn list_mut(types: &mut TypeList) -> &mut SnapshotList<Self::Data>;
41
42    /// The raw index of this id.
43    #[doc(hidden)]
44    fn index(&self) -> usize;
45}
46
47/// A trait shared by all types within a `Types`.
48///
49/// This is the data that can be retrieved by indexing with the associated
50/// [`TypeIdentifier`].
51pub trait TypeData: core::fmt::Debug {
52    /// The identifier for this type data.
53    type Id: TypeIdentifier<Data = Self>;
54
55    /// Is this type a core sub type (or rec group of sub types)?
56    const IS_CORE_SUB_TYPE: bool;
57
58    /// Get the info for this type.
59    #[doc(hidden)]
60    fn type_info(&self, types: &TypeList) -> TypeInfo;
61}
62
63macro_rules! define_type_id {
64    ($name:ident, $data:ty, $($list:ident).*, $type_str:expr) => {
65        #[doc = "Represents a unique identifier for a "]
66        #[doc = $type_str]
67        #[doc = " type known to a [`crate::Validator`]."]
68        #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
69        #[repr(C)] // Use fixed field layout to ensure minimal size.
70        pub struct $name {
71            /// The index into the associated list of types.
72            index: u32,
73        }
74
75        impl TypeIdentifier for $name {
76            type Data = $data;
77
78            fn from_index(index: u32) -> Self {
79                $name { index }
80            }
81
82            fn list(types: &TypeList) -> &SnapshotList<Self::Data> {
83                &types.$($list).*
84            }
85
86            fn list_mut(types: &mut TypeList) -> &mut SnapshotList<Self::Data> {
87                &mut types.$($list).*
88            }
89
90            fn index(&self) -> usize {
91                usize::try_from(self.index).unwrap()
92            }
93        }
94
95
96        // The size of type IDs was seen to have a large-ish impact in #844, so
97        // this assert ensures that it stays relatively small.
98        const _: () = {
99            assert!(core::mem::size_of::<$name>() <= 4);
100        };
101    };
102}
103pub(crate) use define_type_id;
104
105/// Represents a unique identifier for a core type type known to a
106/// [`crate::Validator`].
107#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
108#[repr(C)]
109pub struct CoreTypeId {
110    index: u32,
111}
112
113#[test]
114fn assert_core_type_id_small() {
115    assert!(core::mem::size_of::<CoreTypeId>() <= 4);
116}
117
118impl TypeIdentifier for CoreTypeId {
119    type Data = SubType;
120
121    fn from_index(index: u32) -> Self {
122        CoreTypeId { index }
123    }
124
125    fn list(types: &TypeList) -> &SnapshotList<Self::Data> {
126        &types.core_types
127    }
128
129    fn list_mut(types: &mut TypeList) -> &mut SnapshotList<Self::Data> {
130        &mut types.core_types
131    }
132
133    fn index(&self) -> usize {
134        usize::try_from(self.index).unwrap()
135    }
136}
137
138impl TypeData for SubType {
139    type Id = CoreTypeId;
140    const IS_CORE_SUB_TYPE: bool = true;
141    fn type_info(&self, _types: &TypeList) -> TypeInfo {
142        // TODO(#1036): calculate actual size for func, array, struct.
143        let size = 1 + match &self.composite_type.inner {
144            CompositeInnerType::Func(ty) => 1 + (ty.params().len() + ty.results().len()) as u32,
145            CompositeInnerType::Array(_) => 2,
146            CompositeInnerType::Struct(ty) => 1 + 2 * ty.fields.len() as u32,
147            CompositeInnerType::Cont(_) => 1,
148        };
149        TypeInfo::core(size)
150    }
151}
152
153define_type_id!(
154    RecGroupId,
155    Range<CoreTypeId>,
156    rec_group_elements,
157    "recursion group"
158);
159
160impl TypeData for Range<CoreTypeId> {
161    type Id = RecGroupId;
162    const IS_CORE_SUB_TYPE: bool = true;
163    fn type_info(&self, _types: &TypeList) -> TypeInfo {
164        let size = self.end.index() - self.start.index();
165        TypeInfo::core(u32::try_from(size).unwrap())
166    }
167}
168
169/// Metadata about a type and its transitive structure.
170///
171/// Currently contains two properties:
172///
173/// * The "size" of a type - a proxy to the recursive size of a type if
174///   everything in the type were unique (e.g. no shared references). Not an
175///   approximation of runtime size, but instead of type-complexity size if
176///   someone were to visit each element of the type individually. For example
177///   `u32` has size 1 and `(list u32)` has size 2 (roughly). Used to prevent
178///   massive trees of types.
179///
180/// * Whether or not a type contains a "borrow" transitively inside of it. For
181///   example `(borrow $t)` and `(list (borrow $t))` both contain borrows, but
182///   `(list u32)` does not. Used to validate that component function results do
183///   not contain borrows.
184///
185/// Currently this is represented as a compact 32-bit integer to ensure that
186/// `TypeId`, which this is stored in, remains relatively small. The maximum
187/// type size allowed in wasmparser is 1M at this time which is 20 bits of
188/// information, and then one more bit is used for whether or not a borrow is
189/// used. Currently this uses the low 24 bits for the type size and the MSB for
190/// the borrow bit.
191#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
192// Only public because it shows up in a public trait's `doc(hidden)` method.
193#[doc(hidden)]
194pub struct TypeInfo(u32);
195
196impl TypeInfo {
197    /// Creates a new blank set of type information.
198    ///
199    /// Defaults to size 1 to ensure that this consumes space in the final type
200    /// structure.
201    pub(crate) fn new() -> TypeInfo {
202        TypeInfo::_new(1, false)
203    }
204
205    /// Creates a new blank set of information about a leaf "borrow" type which
206    /// has size 1.
207    #[cfg(feature = "component-model")]
208    pub(crate) fn borrow() -> TypeInfo {
209        TypeInfo::_new(1, true)
210    }
211
212    /// Creates type information corresponding to a core type of the `size`
213    /// specified, meaning no borrows are contained within.
214    pub(crate) fn core(size: u32) -> TypeInfo {
215        TypeInfo::_new(size, false)
216    }
217
218    fn _new(size: u32, contains_borrow: bool) -> TypeInfo {
219        assert!(size < (1 << 24));
220        TypeInfo(size | ((contains_borrow as u32) << 31))
221    }
222
223    /// Combines another set of type information into this one, for example if
224    /// this is a record which has `other` as a field.
225    ///
226    /// Updates the size of `self` and whether or not this type contains a
227    /// borrow based on whether `other` contains a borrow.
228    ///
229    /// Returns an error if the type size would exceed this crate's static limit
230    /// of a type size.
231    #[cfg(feature = "component-model")]
232    pub(crate) fn combine(&mut self, other: TypeInfo, offset: usize) -> Result<()> {
233        *self = TypeInfo::_new(
234            super::combine_type_sizes(self.size(), other.size(), offset)?,
235            self.contains_borrow() || other.contains_borrow(),
236        );
237        Ok(())
238    }
239
240    pub(crate) fn size(&self) -> u32 {
241        self.0 & 0xffffff
242    }
243
244    #[cfg(feature = "component-model")]
245    pub(crate) fn contains_borrow(&self) -> bool {
246        (self.0 >> 31) != 0
247    }
248}
249
250/// The entity type for imports and exports of a module.
251#[derive(Debug, Clone, Copy, PartialEq, Eq)]
252pub enum EntityType {
253    /// The entity is a function.
254    Func(CoreTypeId),
255    /// The entity is a table.
256    Table(TableType),
257    /// The entity is a memory.
258    Memory(MemoryType),
259    /// The entity is a global.
260    Global(GlobalType),
261    /// The entity is a tag.
262    Tag(CoreTypeId),
263}
264
265impl EntityType {
266    #[cfg(feature = "component-model")]
267    pub(crate) fn desc(&self) -> &'static str {
268        match self {
269            Self::Func(_) => "func",
270            Self::Table(_) => "table",
271            Self::Memory(_) => "memory",
272            Self::Global(_) => "global",
273            Self::Tag(_) => "tag",
274        }
275    }
276
277    pub(crate) fn info(&self, types: &TypeList) -> TypeInfo {
278        match self {
279            Self::Func(id) | Self::Tag(id) => types[*id].type_info(types),
280            Self::Table(_) | Self::Memory(_) | Self::Global(_) => TypeInfo::new(),
281        }
282    }
283}
284
285#[allow(clippy::large_enum_variant)]
286pub(super) enum TypesKind {
287    Module(Arc<Module>),
288    #[cfg(feature = "component-model")]
289    Component(ComponentState),
290}
291
292/// Represents the types known to a [`crate::Validator`] once validation has completed.
293///
294/// The type information is returned via the [`crate::Validator::end`] method.
295pub struct Types {
296    id: ValidatorId,
297    pub(super) list: TypeList,
298    pub(super) kind: TypesKind,
299}
300
301#[derive(Clone, Copy)]
302pub(super) enum TypesRefKind<'a> {
303    Module(&'a Module),
304    #[cfg(feature = "component-model")]
305    Component(&'a ComponentState),
306}
307
308/// Represents the types known to a [`crate::Validator`] during validation.
309///
310/// Retrieved via the [`crate::Validator::types`] method.
311#[derive(Clone, Copy)]
312pub struct TypesRef<'a> {
313    id: ValidatorId,
314    pub(super) list: &'a TypeList,
315    pub(super) kind: TypesRefKind<'a>,
316}
317
318impl<'a> TypesRef<'a> {
319    pub(crate) fn from_module(id: ValidatorId, types: &'a TypeList, module: &'a Module) -> Self {
320        Self {
321            id,
322            list: types,
323            kind: TypesRefKind::Module(module),
324        }
325    }
326
327    #[cfg(feature = "component-model")]
328    pub(crate) fn from_component(
329        id: ValidatorId,
330        types: &'a TypeList,
331        component: &'a ComponentState,
332    ) -> Self {
333        Self {
334            id,
335            list: types,
336            kind: TypesRefKind::Component(component),
337        }
338    }
339
340    /// Get the id of the validator that these types are associated with.
341    #[inline]
342    pub fn id(&self) -> ValidatorId {
343        self.id
344    }
345
346    /// Gets a type based on its type id.
347    ///
348    /// Returns `None` if the type id is unknown.
349    pub fn get<T>(&self, id: T) -> Option<&'a T::Data>
350    where
351        T: TypeIdentifier,
352    {
353        self.list.get(id)
354    }
355
356    /// Get the id of the rec group that the given type id was defined within.
357    pub fn rec_group_id_of(&self, id: CoreTypeId) -> RecGroupId {
358        self.list.rec_group_id_of(id)
359    }
360
361    /// Get the types within a rec group.
362    pub fn rec_group_elements(&self, id: RecGroupId) -> impl ExactSizeIterator<Item = CoreTypeId> {
363        let range = &self.list.rec_group_elements[id];
364        (range.start.index..range.end.index).map(|index| CoreTypeId { index })
365    }
366
367    /// Get the super type of the given type id, if any.
368    pub fn supertype_of(&self, id: CoreTypeId) -> Option<CoreTypeId> {
369        self.list.supertype_of(id)
370    }
371
372    /// Gets a core WebAssembly type id from a type index.
373    ///
374    /// Note that this is not to be confused with
375    /// [`TypesRef::component_type_at`] which gets a component type from its
376    /// index, nor [`TypesRef::core_type_at_in_component`] which is for
377    /// learning about core types in components.
378    ///
379    /// # Panics
380    ///
381    /// This will panic if the `index` provided is out of bounds.
382    pub fn core_type_at_in_module(&self, index: u32) -> CoreTypeId {
383        match &self.kind {
384            TypesRefKind::Module(module) => module.types[index as usize].into(),
385            #[cfg(feature = "component-model")]
386            TypesRefKind::Component(_) => panic!("use `core_type_at_in_component` instead"),
387        }
388    }
389
390    /// Returns the number of core types defined so far.
391    ///
392    /// Note that this is only for core modules, for components you should use
393    /// [`TypesRef::core_type_count_in_component`] instead.
394    pub fn core_type_count_in_module(&self) -> u32 {
395        match &self.kind {
396            TypesRefKind::Module(module) => module.types.len() as u32,
397            #[cfg(feature = "component-model")]
398            TypesRefKind::Component(_) => 0,
399        }
400    }
401
402    /// Gets the type of a table at the given table index.
403    ///
404    /// # Panics
405    ///
406    /// This will panic if the `index` provided is out of bounds.
407    pub fn table_at(&self, index: u32) -> TableType {
408        let tables = match &self.kind {
409            TypesRefKind::Module(module) => &module.tables,
410            #[cfg(feature = "component-model")]
411            TypesRefKind::Component(component) => &component.core_tables,
412        };
413        tables[index as usize]
414    }
415
416    /// Returns the number of tables defined so far.
417    pub fn table_count(&self) -> u32 {
418        match &self.kind {
419            TypesRefKind::Module(module) => module.tables.len() as u32,
420            #[cfg(feature = "component-model")]
421            TypesRefKind::Component(component) => component.core_tables.len() as u32,
422        }
423    }
424
425    /// Gets the type of a memory at the given memory index.
426    ///
427    /// # Panics
428    ///
429    /// This will panic if the `index` provided is out of bounds.
430    pub fn memory_at(&self, index: u32) -> MemoryType {
431        let memories = match &self.kind {
432            TypesRefKind::Module(module) => &module.memories,
433            #[cfg(feature = "component-model")]
434            TypesRefKind::Component(component) => &component.core_memories,
435        };
436
437        memories[index as usize]
438    }
439
440    /// Returns the number of memories defined so far.
441    pub fn memory_count(&self) -> u32 {
442        match &self.kind {
443            TypesRefKind::Module(module) => module.memories.len() as u32,
444            #[cfg(feature = "component-model")]
445            TypesRefKind::Component(component) => component.core_memories.len() as u32,
446        }
447    }
448
449    /// Gets the type of a global at the given global index.
450    ///
451    /// # Panics
452    ///
453    /// This will panic if the `index` provided is out of bounds.
454    pub fn global_at(&self, index: u32) -> GlobalType {
455        let globals = match &self.kind {
456            TypesRefKind::Module(module) => &module.globals,
457            #[cfg(feature = "component-model")]
458            TypesRefKind::Component(component) => &component.core_globals,
459        };
460
461        globals[index as usize]
462    }
463
464    /// Returns the number of globals defined so far.
465    pub fn global_count(&self) -> u32 {
466        match &self.kind {
467            TypesRefKind::Module(module) => module.globals.len() as u32,
468            #[cfg(feature = "component-model")]
469            TypesRefKind::Component(component) => component.core_globals.len() as u32,
470        }
471    }
472
473    /// Gets the type of a tag at the given tag index.
474    ///
475    /// # Panics
476    ///
477    /// This will panic if the `index` provided is out of bounds.
478    pub fn tag_at(&self, index: u32) -> CoreTypeId {
479        let tags = match &self.kind {
480            TypesRefKind::Module(module) => &module.tags,
481            #[cfg(feature = "component-model")]
482            TypesRefKind::Component(component) => &component.core_tags,
483        };
484        tags[index as usize]
485    }
486
487    /// Returns the number of tags defined so far.
488    pub fn tag_count(&self) -> u32 {
489        match &self.kind {
490            TypesRefKind::Module(module) => module.tags.len() as u32,
491            #[cfg(feature = "component-model")]
492            TypesRefKind::Component(component) => component.core_tags.len() as u32,
493        }
494    }
495
496    /// Gets the type of a core function at the given function index.
497    ///
498    /// # Panics
499    ///
500    /// This will panic if the `index` provided is out of bounds.
501    pub fn core_function_at(&self, index: u32) -> CoreTypeId {
502        match &self.kind {
503            TypesRefKind::Module(module) => module.types[module.functions[index as usize] as usize],
504            #[cfg(feature = "component-model")]
505            TypesRefKind::Component(component) => component.core_funcs[index as usize],
506        }
507    }
508
509    /// Gets the count of core functions defined so far.
510    ///
511    /// Note that this includes imported functions, defined functions, and for
512    /// components lowered/aliased functions.
513    pub fn function_count(&self) -> u32 {
514        match &self.kind {
515            TypesRefKind::Module(module) => module.functions.len() as u32,
516            #[cfg(feature = "component-model")]
517            TypesRefKind::Component(component) => component.core_funcs.len() as u32,
518        }
519    }
520
521    /// Gets the type of an element segment at the given element segment index.
522    ///
523    /// # Panics
524    ///
525    /// This will panic if the `index` provided is out of bounds.
526    pub fn element_at(&self, index: u32) -> RefType {
527        match &self.kind {
528            TypesRefKind::Module(module) => module.element_types[index as usize],
529            #[cfg(feature = "component-model")]
530            TypesRefKind::Component(_) => {
531                panic!("no elements on a component")
532            }
533        }
534    }
535
536    /// Returns the number of elements defined so far.
537    pub fn element_count(&self) -> u32 {
538        match &self.kind {
539            TypesRefKind::Module(module) => module.element_types.len() as u32,
540            #[cfg(feature = "component-model")]
541            TypesRefKind::Component(_) => 0,
542        }
543    }
544
545    /// Gets the entity type for the given import.
546    pub fn entity_type_from_import(&self, import: &Import) -> Option<EntityType> {
547        match &self.kind {
548            TypesRefKind::Module(module) => Some(match import.ty {
549                TypeRef::Func(idx) => EntityType::Func(*module.types.get(idx as usize)?),
550                TypeRef::Table(ty) => EntityType::Table(ty),
551                TypeRef::Memory(ty) => EntityType::Memory(ty),
552                TypeRef::Global(ty) => EntityType::Global(ty),
553                TypeRef::Tag(ty) => EntityType::Tag(*module.types.get(ty.func_type_idx as usize)?),
554            }),
555            #[cfg(feature = "component-model")]
556            TypesRefKind::Component(_) => None,
557        }
558    }
559
560    /// Gets the entity type from the given export.
561    pub fn entity_type_from_export(&self, export: &Export) -> Option<EntityType> {
562        match &self.kind {
563            TypesRefKind::Module(module) => Some(match export.kind {
564                ExternalKind::Func => EntityType::Func(
565                    module.types[*module.functions.get(export.index as usize)? as usize],
566                ),
567                ExternalKind::Table => {
568                    EntityType::Table(*module.tables.get(export.index as usize)?)
569                }
570                ExternalKind::Memory => {
571                    EntityType::Memory(*module.memories.get(export.index as usize)?)
572                }
573                ExternalKind::Global => {
574                    EntityType::Global(*module.globals.get(export.index as usize)?)
575                }
576                ExternalKind::Tag => EntityType::Tag(*module.tags.get(export.index as usize)?),
577            }),
578            #[cfg(feature = "component-model")]
579            TypesRefKind::Component(_) => None,
580        }
581    }
582
583    /// Returns an iterator over the core wasm imports found.
584    ///
585    /// Returns `None` if this type information is for a component.
586    pub fn core_imports(
587        &self,
588    ) -> Option<impl Iterator<Item = (&'a str, &'a str, EntityType)> + 'a> {
589        match &self.kind {
590            TypesRefKind::Module(module) => Some(
591                module
592                    .imports
593                    .iter()
594                    .flat_map(|((m, n), t)| t.iter().map(move |t| (m.as_str(), n.as_str(), *t))),
595            ),
596            #[cfg(feature = "component-model")]
597            TypesRefKind::Component(_) => None,
598        }
599    }
600
601    /// Returns an iterator over the core wasm exports found.
602    ///
603    /// Returns `None` if this type information is for a component.
604    pub fn core_exports(&self) -> Option<impl Iterator<Item = (&'a str, EntityType)> + 'a> {
605        match &self.kind {
606            TypesRefKind::Module(module) => {
607                Some(module.exports.iter().map(|(n, t)| (n.as_str(), *t)))
608            }
609            #[cfg(feature = "component-model")]
610            TypesRefKind::Component(_) => None,
611        }
612    }
613}
614
615impl<T> Index<T> for TypesRef<'_>
616where
617    T: TypeIdentifier,
618{
619    type Output = T::Data;
620
621    fn index(&self, index: T) -> &Self::Output {
622        &self.list[index]
623    }
624}
625
626impl Types {
627    pub(crate) fn from_module(id: ValidatorId, types: TypeList, module: Arc<Module>) -> Self {
628        Self {
629            id,
630            list: types,
631            kind: TypesKind::Module(module),
632        }
633    }
634
635    #[cfg(feature = "component-model")]
636    pub(crate) fn from_component(
637        id: ValidatorId,
638        types: TypeList,
639        component: ComponentState,
640    ) -> Self {
641        Self {
642            id,
643            list: types,
644            kind: TypesKind::Component(component),
645        }
646    }
647
648    /// Return a [`TypesRef`] through which types can be inspected.
649    pub fn as_ref(&self) -> TypesRef<'_> {
650        TypesRef {
651            id: self.id,
652            list: &self.list,
653            kind: match &self.kind {
654                TypesKind::Module(module) => TypesRefKind::Module(module),
655                #[cfg(feature = "component-model")]
656                TypesKind::Component(component) => TypesRefKind::Component(component),
657            },
658        }
659    }
660}
661
662impl<T> Index<T> for Types
663where
664    T: TypeIdentifier,
665{
666    type Output = T::Data;
667
668    fn index(&self, id: T) -> &Self::Output {
669        &self.list[id]
670    }
671}
672
673/// This is a type which mirrors a subset of the `Vec<T>` API, but is intended
674/// to be able to be cheaply snapshotted and cloned.
675///
676/// When each module's code sections start we "commit" the current list of types
677/// in the global list of types. This means that the temporary `cur` vec here is
678/// pushed onto `snapshots` and wrapped up in an `Arc`. At that point we clone
679/// this entire list (which is then O(modules), not O(types in all modules)) and
680/// pass out as a context to each function validator.
681///
682/// Otherwise, though, this type behaves as if it were a large `Vec<T>`, but
683/// it's represented by lists of contiguous chunks.
684//
685// Only public because it shows up in a public trait's `doc(hidden)` method.
686#[doc(hidden)]
687#[derive(Debug)]
688pub struct SnapshotList<T> {
689    // All previous snapshots, the "head" of the list that this type represents.
690    // The first entry in this pair is the starting index for all elements
691    // contained in the list, and the second element is the list itself. Note
692    // the `Arc` wrapper around sub-lists, which makes cloning time for this
693    // `SnapshotList` O(snapshots) rather than O(snapshots_total), which for
694    // us in this context means the number of modules, not types.
695    //
696    // Note that this list is sorted least-to-greatest in order of the index for
697    // binary searching.
698    snapshots: Vec<Arc<Snapshot<T>>>,
699
700    // This is the total length of all lists in the `snapshots` array.
701    snapshots_total: usize,
702
703    // The current list of types for the current snapshot that are being built.
704    cur: Vec<T>,
705}
706
707#[derive(Debug)]
708struct Snapshot<T> {
709    prior_types: usize,
710    items: Vec<T>,
711}
712
713impl<T> SnapshotList<T> {
714    /// Same as `<&[T]>::get`
715    pub(crate) fn get(&self, index: usize) -> Option<&T> {
716        // Check to see if this index falls on our local list
717        if index >= self.snapshots_total {
718            return self.cur.get(index - self.snapshots_total);
719        }
720        // ... and failing that we do a binary search to figure out which bucket
721        // it's in. Note the `i-1` in the `Err` case because if we don't find an
722        // exact match the type is located in the previous bucket.
723        let i = match self
724            .snapshots
725            .binary_search_by_key(&index, |snapshot| snapshot.prior_types)
726        {
727            Ok(i) => i,
728            Err(i) => i - 1,
729        };
730        let snapshot = &self.snapshots[i];
731        Some(&snapshot.items[index - snapshot.prior_types])
732    }
733
734    /// Same as `Vec::push`
735    pub(crate) fn push(&mut self, val: T) {
736        self.cur.push(val);
737    }
738
739    /// Same as `<[T]>::len`
740    pub(crate) fn len(&self) -> usize {
741        self.cur.len() + self.snapshots_total
742    }
743
744    /// Same as `Vec::truncate` but can only truncate uncommitted elements.
745    #[cfg(feature = "component-model")]
746    pub(crate) fn truncate(&mut self, len: usize) {
747        assert!(len >= self.snapshots_total);
748        self.cur.truncate(len - self.snapshots_total);
749    }
750
751    /// Commits previously pushed types into this snapshot vector, and returns a
752    /// clone of this list.
753    ///
754    /// The returned `SnapshotList` can be used to access all the same types as
755    /// this list itself. This list also is not changed (from an external
756    /// perspective) and can continue to access all the same types.
757    pub(crate) fn commit(&mut self) -> SnapshotList<T> {
758        // If the current chunk has new elements, commit them in to an
759        // `Arc`-wrapped vector in the snapshots list. Note the `shrink_to_fit`
760        // ahead of time to hopefully keep memory usage lower than it would
761        // otherwise be.
762        let len = self.cur.len();
763        if len > 0 {
764            self.cur.shrink_to_fit();
765            self.snapshots.push(Arc::new(Snapshot {
766                prior_types: self.snapshots_total,
767                items: mem::take(&mut self.cur),
768            }));
769            self.snapshots_total += len;
770        }
771        SnapshotList {
772            snapshots: self.snapshots.clone(),
773            snapshots_total: self.snapshots_total,
774            cur: Vec::new(),
775        }
776    }
777}
778
779impl<T> Index<usize> for SnapshotList<T> {
780    type Output = T;
781
782    #[inline]
783    fn index(&self, index: usize) -> &T {
784        match self.get(index) {
785            Some(x) => x,
786            None => panic!(
787                "out-of-bounds indexing into `SnapshotList`: index is {index}, but length is {}",
788                self.len()
789            ),
790        }
791    }
792}
793
794impl<T, U> Index<U> for SnapshotList<T>
795where
796    U: TypeIdentifier<Data = T>,
797{
798    type Output = T;
799
800    #[inline]
801    fn index(&self, id: U) -> &T {
802        self.get(id.index()).unwrap()
803    }
804}
805
806impl<T> Default for SnapshotList<T> {
807    fn default() -> SnapshotList<T> {
808        SnapshotList {
809            snapshots: Vec::new(),
810            snapshots_total: 0,
811            cur: Vec::new(),
812        }
813    }
814}
815
816/// A snapshot list of types.
817///
818/// Note that the snapshot lists below do not correspond with index spaces. Many
819/// different kinds of types are in the same index space (e.g. all of the
820/// component model's {component, instance, defined, func} types are in the same
821/// index space). However, we store each of them in their own type-specific
822/// snapshot list and give each of them their own identifier type.
823#[derive(Default, Debug)]
824// Only public because it shows up in a public trait's `doc(hidden)` method.
825#[doc(hidden)]
826pub struct TypeList {
827    // Core Wasm types.
828    //
829    // A primary map from `CoreTypeId` to `SubType`.
830    pub(super) core_types: SnapshotList<SubType>,
831    // The id of each core Wasm type's rec group.
832    //
833    // A secondary map from `CoreTypeId` to `RecGroupId`.
834    pub(super) core_type_to_rec_group: SnapshotList<RecGroupId>,
835    // The supertype of each core type.
836    //
837    // A secondary map from `CoreTypeId` to `Option<CoreTypeId>`.
838    pub(super) core_type_to_supertype: SnapshotList<Option<CoreTypeId>>,
839    // The subtyping depth of each core type. We use `u8::MAX` as a sentinel for
840    // an uninitialized entry.
841    //
842    // A secondary map from `CoreTypeId` to `u8`.
843    pub(super) core_type_to_depth: Option<IndexMap<CoreTypeId, u8>>,
844    // A primary map from `RecGroupId` to the range of the rec group's elements
845    // within `core_types`.
846    pub(super) rec_group_elements: SnapshotList<Range<CoreTypeId>>,
847    // A hash map from rec group elements to their canonical `RecGroupId`.
848    //
849    // This is `None` when a list is "committed" meaning that no more insertions
850    // can happen.
851    pub(super) canonical_rec_groups: Option<Map<RecGroup, RecGroupId>>,
852
853    #[cfg(feature = "component-model")]
854    pub(super) component: ComponentTypeList,
855}
856
857impl TypeList {
858    pub fn get<T>(&self, id: T) -> Option<&T::Data>
859    where
860        T: TypeIdentifier,
861    {
862        T::list(self).get(id.index())
863    }
864
865    pub fn push<T>(&mut self, ty: T) -> T::Id
866    where
867        T: TypeData,
868    {
869        let index = u32::try_from(T::Id::list(self).len()).unwrap();
870        let id = T::Id::from_index(index);
871        T::Id::list_mut(self).push(ty);
872        id
873    }
874
875    /// Intern the given recursion group (that has already been canonicalized)
876    /// and return its associated id and whether this was a new recursion group
877    /// or not.
878    ///
879    /// If the `needs_type_canonicalization` flag is provided then the type will
880    /// be intern'd here and its indices will be canonicalized to `CoreTypeId`
881    /// from the previous `RecGroup`-based indices.
882    ///
883    /// If the `needs_type_canonicalization` flag is `false` then it must be
884    /// required that `RecGroup` doesn't have any rec-group-relative references
885    /// and it will additionally not be intern'd.
886    pub fn intern_canonical_rec_group(
887        &mut self,
888        needs_type_canonicalization: bool,
889        mut rec_group: RecGroup,
890    ) -> (bool, RecGroupId) {
891        let rec_group_id = self.rec_group_elements.len();
892        let rec_group_id = u32::try_from(rec_group_id).unwrap();
893        let rec_group_id = RecGroupId::from_index(rec_group_id);
894
895        if needs_type_canonicalization {
896            let canonical_rec_groups = self
897                .canonical_rec_groups
898                .as_mut()
899                .expect("cannot intern into a committed list");
900            let entry = match canonical_rec_groups.entry(rec_group) {
901                Entry::Occupied(e) => return (false, *e.get()),
902                Entry::Vacant(e) => e,
903            };
904            rec_group = entry.key().clone();
905            entry.insert(rec_group_id);
906        }
907
908        let start = self.core_types.len();
909        let start = u32::try_from(start).unwrap();
910        let start = CoreTypeId::from_index(start);
911
912        for mut ty in rec_group.into_types() {
913            debug_assert_eq!(self.core_types.len(), self.core_type_to_supertype.len());
914            debug_assert_eq!(self.core_types.len(), self.core_type_to_rec_group.len());
915
916            self.core_type_to_supertype
917                .push(ty.supertype_idx.and_then(|idx| match idx.unpack() {
918                    UnpackedIndex::RecGroup(offset) => {
919                        Some(CoreTypeId::from_index(start.index + offset))
920                    }
921                    UnpackedIndex::Id(id) => Some(id),
922                    // Only invalid wasm has this, at this point, so defer the
923                    // error to later.
924                    UnpackedIndex::Module(_) => None,
925                }));
926            ty.remap_indices(&mut |index| {
927                // Note that `UnpackedIndex::Id` is unmodified and
928                // `UnpackedIndex::Module` means that this is invalid wasm which
929                // will get an error returned later.
930                if let UnpackedIndex::RecGroup(offset) = index.unpack() {
931                    *index = UnpackedIndex::Id(CoreTypeId::from_index(start.index + offset))
932                        .pack()
933                        .unwrap();
934                }
935                Ok(())
936            })
937            .expect("cannot fail");
938            self.core_types.push(ty);
939            self.core_type_to_rec_group.push(rec_group_id);
940        }
941
942        let end = self.core_types.len();
943        let end = u32::try_from(end).unwrap();
944        let end = CoreTypeId::from_index(end);
945
946        let range = start..end;
947
948        self.rec_group_elements.push(range.clone());
949
950        return (true, rec_group_id);
951    }
952
953    /// Helper for interning a sub type as a rec group; see
954    /// [`Self::intern_canonical_rec_group`].
955    pub fn intern_sub_type(&mut self, sub_ty: SubType, offset: usize) -> CoreTypeId {
956        let (_is_new, group_id) =
957            self.intern_canonical_rec_group(true, RecGroup::implicit(offset, sub_ty));
958        self[group_id].start
959    }
960
961    /// Helper for interning a function type as a rec group; see
962    /// [`Self::intern_sub_type`].
963    pub fn intern_func_type(&mut self, ty: FuncType, offset: usize) -> CoreTypeId {
964        self.intern_sub_type(SubType::func(ty, false), offset)
965    }
966
967    /// Get the `CoreTypeId` for a local index into a rec group.
968    pub fn rec_group_local_id(
969        &self,
970        rec_group: RecGroupId,
971        index: u32,
972        offset: usize,
973    ) -> Result<CoreTypeId> {
974        let elems = &self[rec_group];
975        let len = elems.end.index() - elems.start.index();
976        let len = u32::try_from(len).unwrap();
977        if index < len {
978            let id = u32::try_from(elems.start.index()).unwrap() + index;
979            let id = CoreTypeId::from_index(id);
980            Ok(id)
981        } else {
982            bail!(
983                offset,
984                "unknown type {index}: type index out of rec group bounds"
985            )
986        }
987    }
988
989    /// Get the id of the rec group that the given type id was defined within.
990    pub fn rec_group_id_of(&self, id: CoreTypeId) -> RecGroupId {
991        self.core_type_to_rec_group[id.index()]
992    }
993
994    /// Get the super type of the given type id, if any.
995    pub fn supertype_of(&self, id: CoreTypeId) -> Option<CoreTypeId> {
996        self.core_type_to_supertype[id.index()]
997    }
998
999    /// Get the subtyping depth of the given type. A type without any supertype
1000    /// has depth 0.
1001    pub fn get_subtyping_depth(&self, id: CoreTypeId) -> u8 {
1002        let depth = self
1003            .core_type_to_depth
1004            .as_ref()
1005            .expect("cannot get subtype depth from a committed list")[&id];
1006        debug_assert!(usize::from(depth) <= crate::limits::MAX_WASM_SUBTYPING_DEPTH);
1007        depth
1008    }
1009
1010    /// Set the subtyping depth of the given type. This may only be done once
1011    /// per type.
1012    pub fn set_subtyping_depth(&mut self, id: CoreTypeId, depth: u8) {
1013        debug_assert!(usize::from(depth) <= crate::limits::MAX_WASM_SUBTYPING_DEPTH);
1014        let map = self
1015            .core_type_to_depth
1016            .as_mut()
1017            .expect("cannot set a subtype depth in a committed list");
1018        debug_assert!(!map.contains_key(&id));
1019        map.insert(id, depth);
1020    }
1021
1022    /// Get the `CoreTypeId` for a canonicalized `PackedIndex`.
1023    ///
1024    /// Panics when given a non-canonicalized `PackedIndex`.
1025    pub fn at_canonicalized_packed_index(
1026        &self,
1027        rec_group: RecGroupId,
1028        index: PackedIndex,
1029        offset: usize,
1030    ) -> Result<CoreTypeId> {
1031        self.at_canonicalized_unpacked_index(rec_group, index.unpack(), offset)
1032    }
1033
1034    /// Get the `CoreTypeId` for a canonicalized `UnpackedIndex`.
1035    ///
1036    /// Panics when given a non-canonicalized `PackedIndex`.
1037    pub fn at_canonicalized_unpacked_index(
1038        &self,
1039        rec_group: RecGroupId,
1040        index: UnpackedIndex,
1041        offset: usize,
1042    ) -> Result<CoreTypeId> {
1043        match index {
1044            UnpackedIndex::Module(_) => panic!("not canonicalized"),
1045            UnpackedIndex::Id(id) => Ok(id),
1046            UnpackedIndex::RecGroup(idx) => self.rec_group_local_id(rec_group, idx, offset),
1047        }
1048    }
1049
1050    /// Does `a` structurally match `b`?
1051    pub fn matches(&self, a: CoreTypeId, b: CoreTypeId) -> bool {
1052        let a = WithRecGroup::new(self, a);
1053        let a = WithRecGroup::map(a, |a| &self[a]);
1054
1055        let b = WithRecGroup::new(self, b);
1056        let b = WithRecGroup::map(b, |b| &self[b]);
1057
1058        Matches::matches(self, a, b)
1059    }
1060
1061    /// Is `a == b` or was `a` declared (potentially transitively) to be a
1062    /// subtype of `b`?
1063    pub fn id_is_subtype(&self, mut a: CoreTypeId, b: CoreTypeId) -> bool {
1064        loop {
1065            if a == b {
1066                return true;
1067            }
1068
1069            // TODO: maintain supertype vectors and implement this check in O(1)
1070            // instead of O(n) time.
1071            a = match self.supertype_of(a) {
1072                Some(a) => a,
1073                None => return false,
1074            };
1075        }
1076    }
1077
1078    /// Like `id_is_subtype` but for `RefType`s.
1079    ///
1080    /// Both `a` and `b` must be canonicalized already.
1081    pub fn reftype_is_subtype(&self, a: RefType, b: RefType) -> bool {
1082        // NB: Don't need `RecGroupId`s since we are calling from outside of the
1083        // rec group, and so any `PackedIndex`es we encounter have already been
1084        // canonicalized to `CoreTypeId`s directly.
1085        self.reftype_is_subtype_impl(a, None, b, None)
1086    }
1087
1088    /// Implementation of `RefType` and `HeapType` subtyping.
1089    ///
1090    /// Panics if we need rec groups but aren't given them. Rec groups only need
1091    /// to be passed in when checking subtyping of `RefType`s that we encounter
1092    /// while validating a rec group itself.
1093    pub(crate) fn reftype_is_subtype_impl(
1094        &self,
1095        a: RefType,
1096        a_group: Option<RecGroupId>,
1097        b: RefType,
1098        b_group: Option<RecGroupId>,
1099    ) -> bool {
1100        if a == b && a_group == b_group {
1101            return true;
1102        }
1103
1104        if a.is_nullable() && !b.is_nullable() {
1105            return false;
1106        }
1107
1108        let core_type_id = |group: Option<RecGroupId>, index: UnpackedIndex| -> CoreTypeId {
1109            if let Some(id) = index.as_core_type_id() {
1110                id
1111            } else {
1112                self.at_canonicalized_unpacked_index(group.unwrap(), index, usize::MAX)
1113                    .expect("type references are checked during canonicalization")
1114            }
1115        };
1116
1117        let subtype = |group, index| -> &SubType {
1118            let id = core_type_id(group, index);
1119            &self[id]
1120        };
1121
1122        use AbstractHeapType::*;
1123        use CompositeInnerType as CT;
1124        use HeapType as HT;
1125        match (a.heap_type(), b.heap_type()) {
1126            (a, b) if a == b => true,
1127
1128            (
1129                HT::Abstract {
1130                    shared: a_shared,
1131                    ty: a_ty,
1132                },
1133                HT::Abstract {
1134                    shared: b_shared,
1135                    ty: b_ty,
1136                },
1137            ) => a_shared == b_shared && a_ty.is_subtype_of(b_ty),
1138
1139            (HT::Concrete(a), HT::Abstract { shared, ty }) => {
1140                let a_ty = &subtype(a_group, a).composite_type;
1141                if a_ty.shared != shared {
1142                    return false;
1143                }
1144                match ty {
1145                    Any | Eq => matches!(a_ty.inner, CT::Array(_) | CT::Struct(_)),
1146                    Struct => matches!(a_ty.inner, CT::Struct(_)),
1147                    Array => matches!(a_ty.inner, CT::Array(_)),
1148                    Func => matches!(a_ty.inner, CT::Func(_)),
1149                    Cont => matches!(a_ty.inner, CT::Cont(_)),
1150                    // Nothing else matches. (Avoid full wildcard matches so
1151                    // that adding/modifying variants is easier in the future.)
1152                    Extern | Exn | I31 | None | NoFunc | NoExtern | NoExn | NoCont => false,
1153                }
1154            }
1155
1156            (HT::Abstract { shared, ty }, HT::Concrete(b)) => {
1157                let b_ty = &subtype(b_group, b).composite_type;
1158                if shared != b_ty.shared {
1159                    return false;
1160                }
1161                match ty {
1162                    None => matches!(b_ty.inner, CT::Array(_) | CT::Struct(_)),
1163                    NoFunc => matches!(b_ty.inner, CT::Func(_)),
1164                    NoCont => matches!(b_ty.inner, CT::Cont(_)),
1165                    // Nothing else matches. (Avoid full wildcard matches so
1166                    // that adding/modifying variants is easier in the future.)
1167                    Cont | Func | Extern | Exn | Any | Eq | Array | I31 | Struct | NoExtern
1168                    | NoExn => false,
1169                }
1170            }
1171
1172            (HT::Concrete(a), HT::Concrete(b)) => {
1173                self.id_is_subtype(core_type_id(a_group, a), core_type_id(b_group, b))
1174            }
1175        }
1176    }
1177
1178    /// Like `id_is_subtype` but for `RefType`s.
1179    ///
1180    /// Both `a` and `b` must be canonicalized already.
1181    pub fn valtype_is_subtype(&self, a: ValType, b: ValType) -> bool {
1182        match (a, b) {
1183            (a, b) if a == b => true,
1184            (ValType::Ref(a), ValType::Ref(b)) => self.reftype_is_subtype(a, b),
1185            (ValType::Ref(_), _)
1186            | (ValType::I32, _)
1187            | (ValType::I64, _)
1188            | (ValType::F32, _)
1189            | (ValType::F64, _)
1190            | (ValType::V128, _) => false,
1191        }
1192    }
1193
1194    /// Is `ty` shared?
1195    pub fn valtype_is_shared(&self, ty: ValType) -> bool {
1196        match ty {
1197            ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => true,
1198            ValType::Ref(rt) => self.reftype_is_shared(rt),
1199        }
1200    }
1201
1202    /// Is the reference type `ty` shared?
1203    ///
1204    /// This is complicated by concrete heap types whose shared-ness must be
1205    /// checked by looking at the type they point to.
1206    pub fn reftype_is_shared(&self, ty: RefType) -> bool {
1207        match ty.heap_type() {
1208            HeapType::Abstract { shared, .. } => shared,
1209            HeapType::Concrete(index) => {
1210                self[index.as_core_type_id().unwrap()].composite_type.shared
1211            }
1212        }
1213    }
1214
1215    /// Get the top type of the given heap type.
1216    ///
1217    /// Concrete types must have had their indices canonicalized to core type
1218    /// ids, otherwise this method will panic.
1219    pub fn top_type(&self, heap_type: &HeapType) -> HeapType {
1220        use AbstractHeapType::*;
1221        match *heap_type {
1222            HeapType::Concrete(idx) => {
1223                let ty = &self[idx.as_core_type_id().unwrap()].composite_type;
1224                let shared = ty.shared;
1225                match ty.inner {
1226                    CompositeInnerType::Func(_) => HeapType::Abstract { shared, ty: Func },
1227                    CompositeInnerType::Array(_) | CompositeInnerType::Struct(_) => {
1228                        HeapType::Abstract { shared, ty: Any }
1229                    }
1230                    CompositeInnerType::Cont(_) => HeapType::Abstract { shared, ty: Cont },
1231                }
1232            }
1233            HeapType::Abstract { shared, ty } => {
1234                let ty = match ty {
1235                    Func | NoFunc => Func,
1236                    Extern | NoExtern => Extern,
1237                    Any | Eq | Struct | Array | I31 | None => Any,
1238                    Exn | NoExn => Exn,
1239                    Cont | NoCont => Cont,
1240                };
1241                HeapType::Abstract { shared, ty }
1242            }
1243        }
1244    }
1245
1246    pub fn commit(&mut self) -> TypeList {
1247        TypeList {
1248            core_types: self.core_types.commit(),
1249            core_type_to_rec_group: self.core_type_to_rec_group.commit(),
1250            core_type_to_supertype: self.core_type_to_supertype.commit(),
1251            core_type_to_depth: None,
1252            rec_group_elements: self.rec_group_elements.commit(),
1253            canonical_rec_groups: None,
1254            #[cfg(feature = "component-model")]
1255            component: self.component.commit(),
1256        }
1257    }
1258}
1259
1260impl<T> Index<T> for TypeList
1261where
1262    T: TypeIdentifier,
1263{
1264    type Output = T::Data;
1265
1266    fn index(&self, id: T) -> &Self::Output {
1267        let arena = T::list(self);
1268        &arena[id.index()]
1269    }
1270}
1271
1272/// Thin wrapper around `TypeList` which provides an allocator of unique ids for
1273/// types contained within this list.
1274pub(crate) struct TypeAlloc {
1275    list: TypeList,
1276    #[cfg(feature = "component-model")]
1277    pub(super) component_alloc: ComponentTypeAlloc,
1278}
1279
1280impl Default for TypeAlloc {
1281    fn default() -> TypeAlloc {
1282        let mut ret = TypeAlloc {
1283            list: TypeList::default(),
1284            #[cfg(feature = "component-model")]
1285            component_alloc: ComponentTypeAlloc::default(),
1286        };
1287        ret.list.core_type_to_depth = Some(Default::default());
1288        ret.list.canonical_rec_groups = Some(Default::default());
1289        ret
1290    }
1291}
1292
1293impl Deref for TypeAlloc {
1294    type Target = TypeList;
1295    fn deref(&self) -> &TypeList {
1296        &self.list
1297    }
1298}
1299
1300impl DerefMut for TypeAlloc {
1301    fn deref_mut(&mut self) -> &mut TypeList {
1302        &mut self.list
1303    }
1304}
1305
1306impl<T> Index<T> for TypeAlloc
1307where
1308    T: TypeIdentifier,
1309{
1310    type Output = T::Data;
1311
1312    #[inline]
1313    fn index(&self, id: T) -> &T::Data {
1314        &self.list[id]
1315    }
1316}