Skip to main content

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