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