Skip to main content

wasmtime_environ/component/
types_builder.rs

1use crate::component::*;
2use crate::error::{Result, bail};
3use crate::prelude::*;
4use crate::{
5    EngineOrModuleTypeIndex, EntityType, ModuleTypes, ModuleTypesBuilder, PrimaryMap, TypeConvert,
6    WasmHeapType,
7};
8use cranelift_entity::EntityRef;
9use std::collections::HashMap;
10use std::hash::Hash;
11use std::ops::Index;
12use wasmparser::component_types::{
13    ComponentAnyTypeId, ComponentCoreModuleTypeId, ComponentDefinedType, ComponentDefinedTypeId,
14    ComponentEntityType, ComponentFuncTypeId, ComponentInstanceTypeId, ComponentTypeId,
15    ComponentValType, RecordType, ResourceId, TupleType, VariantType,
16};
17use wasmparser::names::KebabString;
18use wasmparser::types::TypesRef;
19use wasmparser::{PrimitiveValType, Validator};
20use wasmtime_component_util::FlagsSize;
21
22mod resources;
23pub use resources::ResourcesBuilder;
24
25/// Maximum nesting depth of a type allowed in Wasmtime.
26///
27/// This constant isn't chosen via any scientific means and its main purpose is
28/// to enable most of Wasmtime to handle types via recursion without worrying
29/// about stack overflow.
30///
31/// Some more information about this can be found in #4814
32const MAX_TYPE_DEPTH: u32 = 100;
33
34/// Structure used to build a [`ComponentTypes`] during translation.
35///
36/// This contains tables to intern any component types found as well as
37/// managing building up core wasm [`ModuleTypes`] as well.
38pub struct ComponentTypesBuilder {
39    functions: HashMap<TypeFunc, TypeFuncIndex>,
40    lists: HashMap<TypeList, TypeListIndex>,
41    maps: HashMap<TypeMap, TypeMapIndex>,
42    records: HashMap<TypeRecord, TypeRecordIndex>,
43    variants: HashMap<TypeVariant, TypeVariantIndex>,
44    tuples: HashMap<TypeTuple, TypeTupleIndex>,
45    enums: HashMap<TypeEnum, TypeEnumIndex>,
46    flags: HashMap<TypeFlags, TypeFlagsIndex>,
47    options: HashMap<TypeOption, TypeOptionIndex>,
48    results: HashMap<TypeResult, TypeResultIndex>,
49    futures: HashMap<TypeFuture, TypeFutureIndex>,
50    streams: HashMap<TypeStream, TypeStreamIndex>,
51    future_tables: HashMap<TypeFutureTable, TypeFutureTableIndex>,
52    stream_tables: HashMap<TypeStreamTable, TypeStreamTableIndex>,
53    error_context_tables: HashMap<TypeErrorContextTable, TypeComponentLocalErrorContextTableIndex>,
54    fixed_length_lists: HashMap<TypeFixedLengthList, TypeFixedLengthListIndex>,
55
56    component_types: ComponentTypes,
57    module_types: ModuleTypesBuilder,
58
59    // Cache of what the "flat" representation of all types are which is only
60    // used at compile-time and not used at runtime, hence the location here
61    // as opposed to `ComponentTypes`.
62    type_info: TypeInformationCache,
63
64    resources: ResourcesBuilder,
65
66    // Total number of abstract resources allocated.
67    //
68    // These are only allocated within component and instance types when
69    // translating them.
70    abstract_resources: u32,
71}
72
73impl<T> Index<T> for ComponentTypesBuilder
74where
75    ModuleTypes: Index<T>,
76{
77    type Output = <ModuleTypes as Index<T>>::Output;
78    fn index(&self, idx: T) -> &Self::Output {
79        self.module_types.index(idx)
80    }
81}
82
83macro_rules! intern_and_fill_flat_types {
84    ($me:ident, $name:ident, $val:ident) => {{
85        if let Some(idx) = $me.$name.get(&$val) {
86            *idx
87        } else {
88            let idx = $me.component_types.$name.push($val.clone());
89            let mut info = TypeInformation::new();
90            info.$name($me, &$val);
91            let idx2 = $me.type_info.$name.push(info);
92            assert_eq!(idx, idx2);
93            $me.$name.insert($val, idx);
94            idx
95        }
96    }};
97}
98
99impl ComponentTypesBuilder {
100    /// Construct a new `ComponentTypesBuilder` for use with the given validator.
101    pub fn new(validator: &Validator) -> Self {
102        Self {
103            module_types: ModuleTypesBuilder::new(validator),
104
105            functions: HashMap::default(),
106            lists: HashMap::default(),
107            maps: HashMap::default(),
108            records: HashMap::default(),
109            variants: HashMap::default(),
110            tuples: HashMap::default(),
111            enums: HashMap::default(),
112            flags: HashMap::default(),
113            options: HashMap::default(),
114            results: HashMap::default(),
115            futures: HashMap::default(),
116            streams: HashMap::default(),
117            future_tables: HashMap::default(),
118            stream_tables: HashMap::default(),
119            error_context_tables: HashMap::default(),
120            component_types: ComponentTypes::default(),
121            type_info: TypeInformationCache::default(),
122            resources: ResourcesBuilder::default(),
123            abstract_resources: 0,
124            fixed_length_lists: HashMap::default(),
125        }
126    }
127
128    fn export_type_def(
129        &mut self,
130        export_items: &PrimaryMap<ExportIndex, Export>,
131        idx: ExportIndex,
132    ) -> TypeDef {
133        match &export_items[idx] {
134            Export::LiftedFunction { ty, .. } => TypeDef::ComponentFunc(*ty),
135            Export::ModuleStatic { ty, .. } | Export::ModuleImport { ty, .. } => {
136                TypeDef::Module(*ty)
137            }
138            Export::Instance { ty, .. } => TypeDef::ComponentInstance(*ty),
139            Export::Type(ty) => *ty,
140        }
141    }
142
143    /// Finishes this list of component types and returns the finished
144    /// structure and the [`TypeComponentIndex`] corresponding to top-level component
145    /// with `imports` and `exports` specified.
146    pub fn finish(mut self, component: &Component) -> (ComponentTypes, TypeComponentIndex) {
147        let mut component_ty = TypeComponent::default();
148        for (_, (name, ty)) in component.import_types.iter() {
149            component_ty.imports.insert(name.clone(), ty.clone());
150        }
151        for (name, (ty, data)) in component.exports.raw_iter() {
152            component_ty.exports.insert(
153                name.clone_panic_on_oom().into(),
154                ComponentExtern {
155                    data: data.clone(),
156                    ty: self.export_type_def(&component.export_items, *ty),
157                },
158            );
159        }
160        let ty = self.component_types.components.push(component_ty);
161
162        self.component_types.module_types = Some(self.module_types.finish());
163        (self.component_types, ty)
164    }
165
166    /// Returns the underlying builder used to build up core wasm module types.
167    ///
168    /// Note that this is shared across all modules found within a component to
169    /// improve the wins from deduplicating function signatures.
170    pub fn module_types_builder(&self) -> &ModuleTypesBuilder {
171        &self.module_types
172    }
173
174    /// Same as `module_types_builder`, but `mut`.
175    pub fn module_types_builder_mut(&mut self) -> &mut ModuleTypesBuilder {
176        &mut self.module_types
177    }
178
179    /// Returns the internal reference to the in-progress `&ComponentTypes`.
180    pub(super) fn component_types(&self) -> &ComponentTypes {
181        &self.component_types
182    }
183
184    /// Returns the number of resource tables allocated so far, or the maximum
185    /// `TypeResourceTableIndex`.
186    pub fn num_resource_tables(&self) -> usize {
187        self.component_types.resource_tables.len()
188    }
189
190    /// Returns the number of future tables allocated so far, or the maximum
191    /// `TypeFutureTableIndex`.
192    pub fn num_future_tables(&self) -> usize {
193        self.component_types.future_tables.len()
194    }
195
196    /// Returns the number of stream tables allocated so far, or the maximum
197    /// `TypeStreamTableIndex`.
198    pub fn num_stream_tables(&self) -> usize {
199        self.component_types.stream_tables.len()
200    }
201
202    /// Returns the number of error-context tables allocated so far, or the maximum
203    /// `TypeComponentLocalErrorContextTableIndex`.
204    pub fn num_error_context_tables(&self) -> usize {
205        self.component_types.error_context_tables.len()
206    }
207
208    /// Returns a mutable reference to the underlying `ResourcesBuilder`.
209    pub fn resources_mut(&mut self) -> &mut ResourcesBuilder {
210        &mut self.resources
211    }
212
213    /// Work around the borrow checker to borrow two sub-fields simultaneously
214    /// externally.
215    pub fn resources_mut_and_types(&mut self) -> (&mut ResourcesBuilder, &ComponentTypes) {
216        (&mut self.resources, &self.component_types)
217    }
218
219    /// Converts a wasmparser `ComponentFuncType` into Wasmtime's type
220    /// representation.
221    pub fn convert_component_func_type(
222        &mut self,
223        types: TypesRef<'_>,
224        id: ComponentFuncTypeId,
225    ) -> Result<TypeFuncIndex> {
226        assert_eq!(types.id(), self.module_types.validator_id());
227        let ty = &types[id];
228        let param_names = ty.params.iter().map(|(name, _)| name.to_string()).collect();
229        let params = ty
230            .params
231            .iter()
232            .map(|(_name, ty)| self.valtype(types, ty))
233            .collect::<Result<_>>()?;
234        let results = ty
235            .result
236            .iter()
237            .map(|ty| self.valtype(types, ty))
238            .collect::<Result<_>>()?;
239        let params = self.new_tuple_type(params);
240        let results = self.new_tuple_type(results);
241        let ty = TypeFunc {
242            async_: ty.async_,
243            param_names,
244            params,
245            results,
246        };
247        Ok(self.add_func_type(ty))
248    }
249
250    /// Converts a wasmparser `wasmparser::ComponentItem` into Wasmtime's type
251    /// representation.
252    pub fn convert_component_item(
253        &mut self,
254        types: TypesRef<'_>,
255        ty: &wasmparser::component_types::ComponentItem,
256    ) -> Result<ComponentExtern> {
257        Ok(ComponentExtern {
258            ty: self.convert_component_entity_type(types, ty.ty)?,
259            data: ComponentExternData {
260                implements: ty.implements.clone(),
261            },
262        })
263    }
264
265    /// Converts a wasmparser `ComponentEntityType` into Wasmtime's type
266    /// representation.
267    pub fn convert_component_entity_type(
268        &mut self,
269        types: TypesRef<'_>,
270        ty: ComponentEntityType,
271    ) -> Result<TypeDef> {
272        assert_eq!(types.id(), self.module_types.validator_id());
273        Ok(match ty {
274            ComponentEntityType::Module(id) => TypeDef::Module(self.convert_module(types, id)?),
275            ComponentEntityType::Component(id) => {
276                TypeDef::Component(self.convert_component(types, id)?)
277            }
278            ComponentEntityType::Instance(id) => {
279                TypeDef::ComponentInstance(self.convert_instance(types, id)?)
280            }
281            ComponentEntityType::Func(id) => {
282                TypeDef::ComponentFunc(self.convert_component_func_type(types, id)?)
283            }
284            ComponentEntityType::Type { created, .. } => match created {
285                ComponentAnyTypeId::Defined(id) => {
286                    TypeDef::Interface(self.defined_type(types, id)?)
287                }
288                ComponentAnyTypeId::Resource(id) => {
289                    TypeDef::Resource(self.resource_id(id.resource()))
290                }
291                _ => bail!("unsupported type export"),
292            },
293            ComponentEntityType::Value(_) => bail!("values not supported"),
294        })
295    }
296
297    /// Converts a wasmparser `Type` into Wasmtime's type representation.
298    pub fn convert_type(&mut self, types: TypesRef<'_>, id: ComponentAnyTypeId) -> Result<TypeDef> {
299        assert_eq!(types.id(), self.module_types.validator_id());
300        Ok(match id {
301            ComponentAnyTypeId::Defined(id) => TypeDef::Interface(self.defined_type(types, id)?),
302            ComponentAnyTypeId::Component(id) => {
303                TypeDef::Component(self.convert_component(types, id)?)
304            }
305            ComponentAnyTypeId::Instance(id) => {
306                TypeDef::ComponentInstance(self.convert_instance(types, id)?)
307            }
308            ComponentAnyTypeId::Func(id) => {
309                TypeDef::ComponentFunc(self.convert_component_func_type(types, id)?)
310            }
311            ComponentAnyTypeId::Resource(id) => TypeDef::Resource(self.resource_id(id.resource())),
312        })
313    }
314
315    fn convert_component(
316        &mut self,
317        types: TypesRef<'_>,
318        id: ComponentTypeId,
319    ) -> Result<TypeComponentIndex> {
320        assert_eq!(types.id(), self.module_types.validator_id());
321        let ty = &types[id];
322        let mut result = TypeComponent::default();
323        for (name, ty) in ty.imports.iter() {
324            self.register_abstract_component_entity_type(types, ty.ty);
325            result
326                .imports
327                .insert(name.clone(), self.convert_component_item(types, ty)?);
328        }
329        for (name, ty) in ty.exports.iter() {
330            self.register_abstract_component_entity_type(types, ty.ty);
331            result
332                .exports
333                .insert(name.clone(), self.convert_component_item(types, ty)?);
334        }
335        Ok(self.component_types.components.push(result))
336    }
337
338    pub(crate) fn convert_instance(
339        &mut self,
340        types: TypesRef<'_>,
341        id: ComponentInstanceTypeId,
342    ) -> Result<TypeComponentInstanceIndex> {
343        assert_eq!(types.id(), self.module_types.validator_id());
344        let ty = &types[id];
345        let mut result = TypeComponentInstance::default();
346        for (name, ty) in ty.exports.iter() {
347            self.register_abstract_component_entity_type(types, ty.ty);
348            result
349                .exports
350                .insert(name.clone(), self.convert_component_item(types, ty)?);
351        }
352        Ok(self.component_types.component_instances.push(result))
353    }
354
355    fn register_abstract_component_entity_type(
356        &mut self,
357        types: TypesRef<'_>,
358        ty: ComponentEntityType,
359    ) {
360        let mut path = Vec::new();
361        self.resources.register_abstract_component_entity_type(
362            &types,
363            ty,
364            &mut path,
365            &mut |_path| {
366                self.abstract_resources += 1;
367                AbstractResourceIndex::from_u32(self.abstract_resources)
368            },
369        );
370    }
371
372    pub(crate) fn convert_module(
373        &mut self,
374        types: TypesRef<'_>,
375        id: ComponentCoreModuleTypeId,
376    ) -> Result<TypeModuleIndex> {
377        assert_eq!(types.id(), self.module_types.validator_id());
378        let ty = &types[id];
379        let mut result = TypeModule::default();
380        for ((module, field), ty) in ty.imports.iter() {
381            result.imports.insert(
382                (module.clone(), field.clone()),
383                self.entity_type(types, ty)?,
384            );
385        }
386        for (name, ty) in ty.exports.iter() {
387            result
388                .exports
389                .insert(name.clone(), self.entity_type(types, ty)?);
390        }
391        Ok(self.component_types.modules.push(result))
392    }
393
394    fn entity_type(
395        &mut self,
396        types: TypesRef<'_>,
397        ty: &wasmparser::types::EntityType,
398    ) -> Result<EntityType> {
399        use wasmparser::types::EntityType::*;
400
401        assert_eq!(types.id(), self.module_types.validator_id());
402        Ok(match ty {
403            Func(id) => EntityType::Function({
404                self.module_types_builder_mut()
405                    .intern_type(types, *id)?
406                    .into()
407            }),
408            Table(ty) => EntityType::Table(self.convert_table_type(ty)?),
409            Memory(ty) => EntityType::Memory((*ty).into()),
410            Global(ty) => EntityType::Global(self.convert_global_type(ty)?),
411            Tag(id) => {
412                let func = self.module_types_builder_mut().intern_type(types, *id)?;
413                let exc = self
414                    .module_types_builder_mut()
415                    .define_exception_type_for_tag(func);
416                EntityType::Tag(crate::types::Tag {
417                    signature: func.into(),
418                    exception: exc.into(),
419                })
420            }
421            FuncExact(_) => bail!("custom-descriptors proposal not implemented"),
422        })
423    }
424
425    /// Convert a wasmparser `ComponentDefinedTypeId` into Wasmtime's type representation.
426    pub fn defined_type(
427        &mut self,
428        types: TypesRef<'_>,
429        id: ComponentDefinedTypeId,
430    ) -> Result<InterfaceType> {
431        assert_eq!(types.id(), self.module_types.validator_id());
432        let ret = match &types[id] {
433            ComponentDefinedType::Primitive(ty) => self.primitive_type(ty)?,
434            ComponentDefinedType::Record(e) => InterfaceType::Record(self.record_type(types, e)?),
435            ComponentDefinedType::Variant(e) => {
436                InterfaceType::Variant(self.variant_type(types, e)?)
437            }
438            ComponentDefinedType::List(e) => InterfaceType::List(self.list_type(types, e)?),
439            ComponentDefinedType::Map(key, value) => {
440                InterfaceType::Map(self.map_type(types, key, value)?)
441            }
442            ComponentDefinedType::Tuple(e) => InterfaceType::Tuple(self.tuple_type(types, e)?),
443            ComponentDefinedType::Flags(e) => InterfaceType::Flags(self.flags_type(e)),
444            ComponentDefinedType::Enum(e) => InterfaceType::Enum(self.enum_type(e)),
445            ComponentDefinedType::Option(e) => InterfaceType::Option(self.option_type(types, e)?),
446            ComponentDefinedType::Result { ok, err } => {
447                InterfaceType::Result(self.result_type(types, ok, err)?)
448            }
449            ComponentDefinedType::Own(r) => InterfaceType::Own(self.resource_id(r.resource())),
450            ComponentDefinedType::Borrow(r) => {
451                InterfaceType::Borrow(self.resource_id(r.resource()))
452            }
453            ComponentDefinedType::Future(ty) => {
454                InterfaceType::Future(self.future_table_type(types, ty)?)
455            }
456            ComponentDefinedType::Stream(ty) => {
457                InterfaceType::Stream(self.stream_table_type(types, ty)?)
458            }
459            ComponentDefinedType::FixedLengthList(ty, size) => {
460                InterfaceType::FixedLengthList(self.fixed_length_list_type(types, ty, *size)?)
461            }
462        };
463        let info = self.type_information(&ret);
464        if info.depth > MAX_TYPE_DEPTH {
465            bail!("type nesting is too deep");
466        }
467        Ok(ret)
468    }
469
470    /// Retrieve Wasmtime's type representation of the `error-context` type.
471    pub fn error_context_type(&mut self) -> Result<TypeComponentLocalErrorContextTableIndex> {
472        self.error_context_table_type()
473    }
474
475    pub(crate) fn valtype(
476        &mut self,
477        types: TypesRef<'_>,
478        ty: &ComponentValType,
479    ) -> Result<InterfaceType> {
480        assert_eq!(types.id(), self.module_types.validator_id());
481        match ty {
482            ComponentValType::Primitive(p) => self.primitive_type(p),
483            ComponentValType::Type(id) => self.defined_type(types, *id),
484        }
485    }
486
487    fn primitive_type(&mut self, ty: &PrimitiveValType) -> Result<InterfaceType> {
488        match ty {
489            wasmparser::PrimitiveValType::Bool => Ok(InterfaceType::Bool),
490            wasmparser::PrimitiveValType::S8 => Ok(InterfaceType::S8),
491            wasmparser::PrimitiveValType::U8 => Ok(InterfaceType::U8),
492            wasmparser::PrimitiveValType::S16 => Ok(InterfaceType::S16),
493            wasmparser::PrimitiveValType::U16 => Ok(InterfaceType::U16),
494            wasmparser::PrimitiveValType::S32 => Ok(InterfaceType::S32),
495            wasmparser::PrimitiveValType::U32 => Ok(InterfaceType::U32),
496            wasmparser::PrimitiveValType::S64 => Ok(InterfaceType::S64),
497            wasmparser::PrimitiveValType::U64 => Ok(InterfaceType::U64),
498            wasmparser::PrimitiveValType::F32 => Ok(InterfaceType::Float32),
499            wasmparser::PrimitiveValType::F64 => Ok(InterfaceType::Float64),
500            wasmparser::PrimitiveValType::Char => Ok(InterfaceType::Char),
501            wasmparser::PrimitiveValType::String => Ok(InterfaceType::String),
502            wasmparser::PrimitiveValType::ErrorContext => Ok(InterfaceType::ErrorContext(
503                self.error_context_table_type()?,
504            )),
505        }
506    }
507
508    fn record_type(&mut self, types: TypesRef<'_>, ty: &RecordType) -> Result<TypeRecordIndex> {
509        assert_eq!(types.id(), self.module_types.validator_id());
510        let fields = ty
511            .fields
512            .iter()
513            .map(|(name, ty)| {
514                Ok(RecordField {
515                    name: name.to_string(),
516                    ty: self.valtype(types, ty)?,
517                })
518            })
519            .collect::<Result<Box<[_]>>>()?;
520        let abi = CanonicalAbiInfo::record(
521            fields
522                .iter()
523                .map(|field| self.component_types.canonical_abi(&field.ty)),
524        );
525        Ok(self.add_record_type(TypeRecord { fields, abi }))
526    }
527
528    fn variant_type(&mut self, types: TypesRef<'_>, ty: &VariantType) -> Result<TypeVariantIndex> {
529        assert_eq!(types.id(), self.module_types.validator_id());
530        let cases = ty
531            .cases
532            .iter()
533            .map(|(name, case)| {
534                Ok((
535                    name.to_string(),
536                    match &case.ty.as_ref() {
537                        Some(ty) => Some(self.valtype(types, ty)?),
538                        None => None,
539                    },
540                ))
541            })
542            .collect::<Result<IndexMap<_, _>>>()?;
543        let (info, abi) = VariantInfo::new(
544            cases
545                .iter()
546                .map(|(_, c)| c.as_ref().map(|ty| self.component_types.canonical_abi(ty))),
547        );
548        Ok(self.add_variant_type(TypeVariant { cases, abi, info }))
549    }
550
551    fn tuple_type(&mut self, types: TypesRef<'_>, ty: &TupleType) -> Result<TypeTupleIndex> {
552        assert_eq!(types.id(), self.module_types.validator_id());
553        let types = ty
554            .types
555            .iter()
556            .map(|ty| self.valtype(types, ty))
557            .collect::<Result<Box<[_]>>>()?;
558        Ok(self.new_tuple_type(types))
559    }
560
561    pub(crate) fn new_tuple_type(&mut self, types: Box<[InterfaceType]>) -> TypeTupleIndex {
562        let abi = CanonicalAbiInfo::record(
563            types
564                .iter()
565                .map(|ty| self.component_types.canonical_abi(ty)),
566        );
567        self.add_tuple_type(TypeTuple { types, abi })
568    }
569
570    fn fixed_length_list_type(
571        &mut self,
572        types: TypesRef<'_>,
573        ty: &ComponentValType,
574        size: u32,
575    ) -> Result<TypeFixedLengthListIndex> {
576        assert_eq!(types.id(), self.module_types.validator_id());
577        let element = self.valtype(types, ty)?;
578        Ok(self.new_fixed_length_list_type(element, size))
579    }
580
581    pub(crate) fn new_fixed_length_list_type(
582        &mut self,
583        element: InterfaceType,
584        size: u32,
585    ) -> TypeFixedLengthListIndex {
586        let element_abi = self.component_types.canonical_abi(&element);
587        let mut abi = element_abi.clone();
588        // this assumes that size32 is already rounded up to alignment
589        abi.size32 = element_abi.size32.saturating_mul(size);
590        abi.size64 = element_abi.size64.saturating_mul(size);
591        abi.flat_count = element_abi
592            .flat_count
593            .zip(u8::try_from(size).ok())
594            .and_then(|(flat_count, size)| flat_count.checked_mul(size));
595        self.add_fixed_length_list_type(TypeFixedLengthList { element, size, abi })
596    }
597
598    fn flags_type(&mut self, flags: &IndexSet<KebabString>) -> TypeFlagsIndex {
599        let flags = TypeFlags {
600            names: flags.iter().map(|s| s.to_string()).collect(),
601            abi: CanonicalAbiInfo::flags(flags.len()),
602        };
603        self.add_flags_type(flags)
604    }
605
606    fn enum_type(&mut self, variants: &IndexSet<KebabString>) -> TypeEnumIndex {
607        let names = variants
608            .iter()
609            .map(|s| s.to_string())
610            .collect::<IndexSet<_>>();
611        let (info, abi) = VariantInfo::new(names.iter().map(|_| None));
612        self.add_enum_type(TypeEnum { names, abi, info })
613    }
614
615    fn option_type(
616        &mut self,
617        types: TypesRef<'_>,
618        ty: &ComponentValType,
619    ) -> Result<TypeOptionIndex> {
620        assert_eq!(types.id(), self.module_types.validator_id());
621        let ty = self.valtype(types, ty)?;
622        let (info, abi) = VariantInfo::new([None, Some(self.component_types.canonical_abi(&ty))]);
623        Ok(self.add_option_type(TypeOption { ty, abi, info }))
624    }
625
626    fn result_type(
627        &mut self,
628        types: TypesRef<'_>,
629        ok: &Option<ComponentValType>,
630        err: &Option<ComponentValType>,
631    ) -> Result<TypeResultIndex> {
632        assert_eq!(types.id(), self.module_types.validator_id());
633        let ok = match ok {
634            Some(ty) => Some(self.valtype(types, ty)?),
635            None => None,
636        };
637        let err = match err {
638            Some(ty) => Some(self.valtype(types, ty)?),
639            None => None,
640        };
641        let (info, abi) = VariantInfo::new([
642            ok.as_ref().map(|t| self.component_types.canonical_abi(t)),
643            err.as_ref().map(|t| self.component_types.canonical_abi(t)),
644        ]);
645        Ok(self.add_result_type(TypeResult { ok, err, abi, info }))
646    }
647
648    fn future_table_type(
649        &mut self,
650        types: TypesRef<'_>,
651        ty: &Option<ComponentValType>,
652    ) -> Result<TypeFutureTableIndex> {
653        let payload = ty.as_ref().map(|ty| self.valtype(types, ty)).transpose()?;
654        let ty = self.add_future_type(TypeFuture { payload });
655        Ok(self.add_future_table_type(TypeFutureTable {
656            ty,
657            instance: self.resources.get_current_instance().unwrap(),
658        }))
659    }
660
661    fn stream_table_type(
662        &mut self,
663        types: TypesRef<'_>,
664        ty: &Option<ComponentValType>,
665    ) -> Result<TypeStreamTableIndex> {
666        let payload = ty.as_ref().map(|ty| self.valtype(types, ty)).transpose()?;
667        let ty = self.add_stream_type(TypeStream { payload });
668        Ok(self.add_stream_table_type(TypeStreamTable {
669            ty,
670            instance: self.resources.get_current_instance().unwrap(),
671        }))
672    }
673
674    /// Retrieve Wasmtime's type representation of the `error-context` type from
675    /// the point of view of the current component instance.
676    pub fn error_context_table_type(&mut self) -> Result<TypeComponentLocalErrorContextTableIndex> {
677        Ok(self.add_error_context_table_type(TypeErrorContextTable {
678            instance: self.resources.get_current_instance().unwrap(),
679        }))
680    }
681
682    fn list_type(&mut self, types: TypesRef<'_>, ty: &ComponentValType) -> Result<TypeListIndex> {
683        assert_eq!(types.id(), self.module_types.validator_id());
684        let element = self.valtype(types, ty)?;
685        Ok(self.add_list_type(TypeList { element }))
686    }
687
688    fn map_type(
689        &mut self,
690        types: TypesRef<'_>,
691        key: &ComponentValType,
692        value: &ComponentValType,
693    ) -> Result<TypeMapIndex> {
694        assert_eq!(types.id(), self.module_types.validator_id());
695        let key_ty = self.valtype(types, key)?;
696        let value_ty = self.valtype(types, value)?;
697        let key_abi = self.component_types.canonical_abi(&key_ty);
698        let value_abi = self.component_types.canonical_abi(&value_ty);
699        let entry_abi = CanonicalAbiInfo::record([key_abi, value_abi].into_iter());
700
701        let mut offset32 = 0;
702        key_abi.next_field32(&mut offset32);
703        let value_offset32 = value_abi.next_field32(&mut offset32);
704
705        let mut offset64 = 0;
706        key_abi.next_field64(&mut offset64);
707        let value_offset64 = value_abi.next_field64(&mut offset64);
708
709        Ok(self.add_map_type(TypeMap {
710            key: key_ty,
711            value: value_ty,
712            entry_abi,
713            value_offset32,
714            value_offset64,
715        }))
716    }
717
718    /// Converts a wasmparser `id`, which must point to a resource, to its
719    /// corresponding `TypeResourceTableIndex`.
720    pub fn resource_id(&mut self, id: ResourceId) -> TypeResourceTableIndex {
721        self.resources.convert(id, &mut self.component_types)
722    }
723
724    /// Interns a new function type within this type information.
725    pub fn add_func_type(&mut self, ty: TypeFunc) -> TypeFuncIndex {
726        intern(&mut self.functions, &mut self.component_types.functions, ty)
727    }
728
729    /// Interns a new record type within this type information.
730    pub fn add_record_type(&mut self, ty: TypeRecord) -> TypeRecordIndex {
731        intern_and_fill_flat_types!(self, records, ty)
732    }
733
734    /// Interns a new flags type within this type information.
735    pub fn add_flags_type(&mut self, ty: TypeFlags) -> TypeFlagsIndex {
736        intern_and_fill_flat_types!(self, flags, ty)
737    }
738
739    /// Interns a new tuple type within this type information.
740    pub fn add_tuple_type(&mut self, ty: TypeTuple) -> TypeTupleIndex {
741        intern_and_fill_flat_types!(self, tuples, ty)
742    }
743
744    /// Interns a new tuple type within this type information.
745    pub fn add_fixed_length_list_type(
746        &mut self,
747        ty: TypeFixedLengthList,
748    ) -> TypeFixedLengthListIndex {
749        intern_and_fill_flat_types!(self, fixed_length_lists, ty)
750    }
751
752    /// Interns a new variant type within this type information.
753    pub fn add_variant_type(&mut self, ty: TypeVariant) -> TypeVariantIndex {
754        intern_and_fill_flat_types!(self, variants, ty)
755    }
756
757    /// Interns a new enum type within this type information.
758    pub fn add_enum_type(&mut self, ty: TypeEnum) -> TypeEnumIndex {
759        intern_and_fill_flat_types!(self, enums, ty)
760    }
761
762    /// Interns a new option type within this type information.
763    pub fn add_option_type(&mut self, ty: TypeOption) -> TypeOptionIndex {
764        intern_and_fill_flat_types!(self, options, ty)
765    }
766
767    /// Interns a new result type within this type information.
768    pub fn add_result_type(&mut self, ty: TypeResult) -> TypeResultIndex {
769        intern_and_fill_flat_types!(self, results, ty)
770    }
771
772    /// Interns a new list type within this type information.
773    pub fn add_list_type(&mut self, ty: TypeList) -> TypeListIndex {
774        intern_and_fill_flat_types!(self, lists, ty)
775    }
776
777    /// Interns a new map type within this type information.
778    pub fn add_map_type(&mut self, ty: TypeMap) -> TypeMapIndex {
779        intern_and_fill_flat_types!(self, maps, ty)
780    }
781
782    /// Interns a new future type within this type information.
783    pub fn add_future_type(&mut self, ty: TypeFuture) -> TypeFutureIndex {
784        intern(&mut self.futures, &mut self.component_types.futures, ty)
785    }
786
787    /// Interns a new future table type within this type information.
788    pub fn add_future_table_type(&mut self, ty: TypeFutureTable) -> TypeFutureTableIndex {
789        intern(
790            &mut self.future_tables,
791            &mut self.component_types.future_tables,
792            ty,
793        )
794    }
795
796    /// Interns a new stream type within this type information.
797    pub fn add_stream_type(&mut self, ty: TypeStream) -> TypeStreamIndex {
798        intern(&mut self.streams, &mut self.component_types.streams, ty)
799    }
800
801    /// Interns a new stream table type within this type information.
802    pub fn add_stream_table_type(&mut self, ty: TypeStreamTable) -> TypeStreamTableIndex {
803        intern(
804            &mut self.stream_tables,
805            &mut self.component_types.stream_tables,
806            ty,
807        )
808    }
809
810    /// Interns a new error context table type within this type information.
811    pub fn add_error_context_table_type(
812        &mut self,
813        ty: TypeErrorContextTable,
814    ) -> TypeComponentLocalErrorContextTableIndex {
815        intern(
816            &mut self.error_context_tables,
817            &mut self.component_types.error_context_tables,
818            ty,
819        )
820    }
821
822    /// Returns the canonical ABI information about the specified type.
823    pub fn canonical_abi(&self, ty: &InterfaceType) -> &CanonicalAbiInfo {
824        self.component_types.canonical_abi(ty)
825    }
826
827    /// Returns the "flat types" for the given interface type used in the
828    /// canonical ABI.
829    ///
830    /// Returns `None` if the type is too large to be represented via flat types
831    /// in the canonical abi.
832    pub fn flat_types(&self, ty: &InterfaceType) -> Option<FlatTypes<'_>> {
833        self.type_information(ty).flat.as_flat_types()
834    }
835
836    /// Returns whether the type specified contains any borrowed resources
837    /// within it.
838    pub fn ty_contains_borrow_resource(&self, ty: &InterfaceType) -> bool {
839        self.type_information(ty).has_borrow
840    }
841
842    fn type_information(&self, ty: &InterfaceType) -> &TypeInformation {
843        match ty {
844            InterfaceType::U8
845            | InterfaceType::S8
846            | InterfaceType::Bool
847            | InterfaceType::U16
848            | InterfaceType::S16
849            | InterfaceType::U32
850            | InterfaceType::S32
851            | InterfaceType::Char
852            | InterfaceType::Own(_)
853            | InterfaceType::Future(_)
854            | InterfaceType::Stream(_)
855            | InterfaceType::ErrorContext(_) => {
856                static INFO: TypeInformation = TypeInformation::primitive(FlatType::I32);
857                &INFO
858            }
859            InterfaceType::Borrow(_) => {
860                static INFO: TypeInformation = {
861                    let mut info = TypeInformation::primitive(FlatType::I32);
862                    info.has_borrow = true;
863                    info
864                };
865                &INFO
866            }
867            InterfaceType::U64 | InterfaceType::S64 => {
868                static INFO: TypeInformation = TypeInformation::primitive(FlatType::I64);
869                &INFO
870            }
871            InterfaceType::Float32 => {
872                static INFO: TypeInformation = TypeInformation::primitive(FlatType::F32);
873                &INFO
874            }
875            InterfaceType::Float64 => {
876                static INFO: TypeInformation = TypeInformation::primitive(FlatType::F64);
877                &INFO
878            }
879            InterfaceType::String => {
880                static INFO: TypeInformation = TypeInformation::string();
881                &INFO
882            }
883
884            InterfaceType::List(i) => &self.type_info.lists[*i],
885            InterfaceType::Map(i) => &self.type_info.maps[*i],
886            InterfaceType::Record(i) => &self.type_info.records[*i],
887            InterfaceType::Variant(i) => &self.type_info.variants[*i],
888            InterfaceType::Tuple(i) => &self.type_info.tuples[*i],
889            InterfaceType::Flags(i) => &self.type_info.flags[*i],
890            InterfaceType::Enum(i) => &self.type_info.enums[*i],
891            InterfaceType::Option(i) => &self.type_info.options[*i],
892            InterfaceType::Result(i) => &self.type_info.results[*i],
893            InterfaceType::FixedLengthList(i) => &self.type_info.fixed_length_lists[*i],
894        }
895    }
896}
897
898impl TypeConvert for ComponentTypesBuilder {
899    fn lookup_heap_type(&self, _index: wasmparser::UnpackedIndex) -> WasmHeapType {
900        panic!("heap types are not supported yet")
901    }
902
903    fn lookup_type_index(&self, _index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex {
904        panic!("typed references are not supported yet")
905    }
906}
907
908fn intern<T, U>(map: &mut HashMap<T, U>, list: &mut PrimaryMap<U, T>, item: T) -> U
909where
910    T: Hash + Clone + Eq,
911    U: Copy + EntityRef,
912{
913    if let Some(idx) = map.get(&item) {
914        return *idx;
915    }
916    let idx = list.push(item.clone());
917    map.insert(item, idx);
918    return idx;
919}
920
921struct FlatTypesStorage {
922    // This could be represented as `Vec<FlatType>` but on 64-bit architectures
923    // that's 24 bytes. Otherwise `FlatType` is 1 byte large and
924    // `MAX_FLAT_TYPES` is 16, so it should ideally be more space-efficient to
925    // use a flat array instead of a heap-based vector.
926    memory32: [FlatType; MAX_FLAT_TYPES],
927    memory64: [FlatType; MAX_FLAT_TYPES],
928
929    // Tracks the number of flat types pushed into this storage. If this is
930    // `MAX_FLAT_TYPES + 1` then this storage represents an un-reprsentable
931    // type in flat types.
932    len: u8,
933}
934
935impl FlatTypesStorage {
936    const fn new() -> FlatTypesStorage {
937        FlatTypesStorage {
938            memory32: [FlatType::I32; MAX_FLAT_TYPES],
939            memory64: [FlatType::I32; MAX_FLAT_TYPES],
940            len: 0,
941        }
942    }
943
944    fn as_flat_types(&self) -> Option<FlatTypes<'_>> {
945        let len = usize::from(self.len);
946        if len > MAX_FLAT_TYPES {
947            assert_eq!(len, MAX_FLAT_TYPES + 1);
948            None
949        } else {
950            Some(FlatTypes {
951                memory32: &self.memory32[..len],
952                memory64: &self.memory64[..len],
953            })
954        }
955    }
956
957    /// Pushes a new flat type into this list using `t32` for 32-bit memories
958    /// and `t64` for 64-bit memories.
959    ///
960    /// Returns whether the type was actually pushed or whether this list of
961    /// flat types just exceeded the maximum meaning that it is now
962    /// unrepresentable with a flat list of types.
963    fn push(&mut self, t32: FlatType, t64: FlatType) -> bool {
964        let len = usize::from(self.len);
965        if len < MAX_FLAT_TYPES {
966            self.memory32[len] = t32;
967            self.memory64[len] = t64;
968            self.len += 1;
969            true
970        } else {
971            // If this was the first one to go over then flag the length as
972            // being incompatible with a flat representation.
973            if len == MAX_FLAT_TYPES {
974                self.len += 1;
975            }
976            false
977        }
978    }
979}
980
981impl FlatType {
982    fn join(&mut self, other: FlatType) {
983        if *self == other {
984            return;
985        }
986        *self = match (*self, other) {
987            (FlatType::I32, FlatType::F32) | (FlatType::F32, FlatType::I32) => FlatType::I32,
988            _ => FlatType::I64,
989        };
990    }
991}
992
993#[derive(Default)]
994struct TypeInformationCache {
995    records: PrimaryMap<TypeRecordIndex, TypeInformation>,
996    variants: PrimaryMap<TypeVariantIndex, TypeInformation>,
997    tuples: PrimaryMap<TypeTupleIndex, TypeInformation>,
998    enums: PrimaryMap<TypeEnumIndex, TypeInformation>,
999    flags: PrimaryMap<TypeFlagsIndex, TypeInformation>,
1000    options: PrimaryMap<TypeOptionIndex, TypeInformation>,
1001    results: PrimaryMap<TypeResultIndex, TypeInformation>,
1002    lists: PrimaryMap<TypeListIndex, TypeInformation>,
1003    maps: PrimaryMap<TypeMapIndex, TypeInformation>,
1004    fixed_length_lists: PrimaryMap<TypeFixedLengthListIndex, TypeInformation>,
1005}
1006
1007struct TypeInformation {
1008    depth: u32,
1009    flat: FlatTypesStorage,
1010    has_borrow: bool,
1011}
1012
1013impl TypeInformation {
1014    const fn new() -> TypeInformation {
1015        TypeInformation {
1016            depth: 0,
1017            flat: FlatTypesStorage::new(),
1018            has_borrow: false,
1019        }
1020    }
1021
1022    const fn primitive(flat: FlatType) -> TypeInformation {
1023        let mut info = TypeInformation::new();
1024        info.depth = 1;
1025        info.flat.memory32[0] = flat;
1026        info.flat.memory64[0] = flat;
1027        info.flat.len = 1;
1028        info
1029    }
1030
1031    const fn string() -> TypeInformation {
1032        let mut info = TypeInformation::new();
1033        info.depth = 1;
1034        info.flat.memory32[0] = FlatType::I32;
1035        info.flat.memory32[1] = FlatType::I32;
1036        info.flat.memory64[0] = FlatType::I64;
1037        info.flat.memory64[1] = FlatType::I64;
1038        info.flat.len = 2;
1039        info
1040    }
1041
1042    /// Builds up all flat types internally using the specified representation
1043    /// for all of the component fields of the record.
1044    fn build_record<'a>(&mut self, types: impl Iterator<Item = &'a TypeInformation>) {
1045        self.depth = 1;
1046        for info in types {
1047            self.depth = self.depth.max(1 + info.depth);
1048            self.has_borrow = self.has_borrow || info.has_borrow;
1049            match info.flat.as_flat_types() {
1050                Some(types) => {
1051                    for (t32, t64) in types.memory32.iter().zip(types.memory64) {
1052                        if !self.flat.push(*t32, *t64) {
1053                            break;
1054                        }
1055                    }
1056                }
1057                None => {
1058                    self.flat.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap();
1059                }
1060            }
1061        }
1062    }
1063
1064    /// Builds up the flat types used to represent a `variant` which notably
1065    /// handles "join"ing types together so each case is representable as a
1066    /// single flat list of types.
1067    ///
1068    /// The iterator item is:
1069    ///
1070    /// * `None` - no payload for this case
1071    /// * `Some(None)` - this case has a payload but can't be represented with
1072    ///   flat types
1073    /// * `Some(Some(types))` - this case has a payload and is represented with
1074    ///   the types specified in the flat representation.
1075    fn build_variant<'a, I>(&mut self, cases: I)
1076    where
1077        I: IntoIterator<Item = Option<&'a TypeInformation>>,
1078    {
1079        let cases = cases.into_iter();
1080        self.flat.push(FlatType::I32, FlatType::I32);
1081        self.depth = 1;
1082
1083        for info in cases {
1084            let info = match info {
1085                Some(info) => info,
1086                // If this case doesn't have a payload then it doesn't change
1087                // the depth/flat representation
1088                None => continue,
1089            };
1090            self.depth = self.depth.max(1 + info.depth);
1091            self.has_borrow = self.has_borrow || info.has_borrow;
1092
1093            // If this variant is already unrepresentable in a flat
1094            // representation then this can be skipped.
1095            if usize::from(self.flat.len) > MAX_FLAT_TYPES {
1096                continue;
1097            }
1098
1099            let types = match info.flat.as_flat_types() {
1100                Some(types) => types,
1101                // If this case isn't representable with a flat list of types
1102                // then this variant also isn't representable.
1103                None => {
1104                    self.flat.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap();
1105                    continue;
1106                }
1107            };
1108            // If the case used all of the flat types then the discriminant
1109            // added for this variant means that this variant is no longer
1110            // representable.
1111            if types.memory32.len() >= MAX_FLAT_TYPES {
1112                self.flat.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap();
1113                continue;
1114            }
1115            let dst = self
1116                .flat
1117                .memory32
1118                .iter_mut()
1119                .zip(&mut self.flat.memory64)
1120                .skip(1);
1121            for (i, ((t32, t64), (dst32, dst64))) in types
1122                .memory32
1123                .iter()
1124                .zip(types.memory64)
1125                .zip(dst)
1126                .enumerate()
1127            {
1128                if i + 1 < usize::from(self.flat.len) {
1129                    // If this index hs already been set by some previous case
1130                    // then the types are joined together.
1131                    dst32.join(*t32);
1132                    dst64.join(*t64);
1133                } else {
1134                    // Otherwise if this is the first time that the
1135                    // representation has gotten this large then the destination
1136                    // is simply whatever the type is. The length is also
1137                    // increased here to indicate this.
1138                    self.flat.len += 1;
1139                    *dst32 = *t32;
1140                    *dst64 = *t64;
1141                }
1142            }
1143        }
1144    }
1145
1146    fn records(&mut self, types: &ComponentTypesBuilder, ty: &TypeRecord) {
1147        self.build_record(ty.fields.iter().map(|f| types.type_information(&f.ty)));
1148    }
1149
1150    fn tuples(&mut self, types: &ComponentTypesBuilder, ty: &TypeTuple) {
1151        self.build_record(ty.types.iter().map(|t| types.type_information(t)));
1152    }
1153
1154    fn fixed_length_lists(&mut self, types: &ComponentTypesBuilder, ty: &TypeFixedLengthList) {
1155        let element_info = types.type_information(&ty.element);
1156        self.depth = 1 + element_info.depth;
1157        self.has_borrow = element_info.has_borrow;
1158        match element_info.flat.as_flat_types() {
1159            Some(types) => {
1160                'outer: for _ in 0..ty.size {
1161                    for (t32, t64) in types.memory32.iter().zip(types.memory64) {
1162                        if !self.flat.push(*t32, *t64) {
1163                            break 'outer;
1164                        }
1165                    }
1166                }
1167            }
1168            None => self.flat.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap(),
1169        }
1170    }
1171
1172    fn enums(&mut self, _types: &ComponentTypesBuilder, _ty: &TypeEnum) {
1173        self.depth = 1;
1174        self.flat.push(FlatType::I32, FlatType::I32);
1175    }
1176
1177    fn flags(&mut self, _types: &ComponentTypesBuilder, ty: &TypeFlags) {
1178        self.depth = 1;
1179        match FlagsSize::from_count(ty.names.len()) {
1180            FlagsSize::Size0 => {}
1181            FlagsSize::Size1 | FlagsSize::Size2 => {
1182                self.flat.push(FlatType::I32, FlatType::I32);
1183            }
1184            FlagsSize::Size4Plus(n) => {
1185                for _ in 0..n {
1186                    self.flat.push(FlatType::I32, FlatType::I32);
1187                }
1188            }
1189        }
1190    }
1191
1192    fn variants(&mut self, types: &ComponentTypesBuilder, ty: &TypeVariant) {
1193        self.build_variant(
1194            ty.cases
1195                .iter()
1196                .map(|(_, c)| c.as_ref().map(|ty| types.type_information(ty))),
1197        )
1198    }
1199
1200    fn results(&mut self, types: &ComponentTypesBuilder, ty: &TypeResult) {
1201        self.build_variant([
1202            ty.ok.as_ref().map(|ty| types.type_information(ty)),
1203            ty.err.as_ref().map(|ty| types.type_information(ty)),
1204        ])
1205    }
1206
1207    fn options(&mut self, types: &ComponentTypesBuilder, ty: &TypeOption) {
1208        self.build_variant([None, Some(types.type_information(&ty.ty))]);
1209    }
1210
1211    fn lists(&mut self, types: &ComponentTypesBuilder, ty: &TypeList) {
1212        *self = TypeInformation::string();
1213        let info = types.type_information(&ty.element);
1214        self.depth += info.depth;
1215        self.has_borrow = info.has_borrow;
1216    }
1217
1218    fn maps(&mut self, types: &ComponentTypesBuilder, ty: &TypeMap) {
1219        // Maps are represented as list<tuple<k, v>> in canonical ABI
1220        // So we use POINTER_PAIR like lists, and calculate depth/borrow from key and value
1221        *self = TypeInformation::string();
1222        let key_info = types.type_information(&ty.key);
1223        let value_info = types.type_information(&ty.value);
1224        // Depth is max of key/value depths, plus 1 for the extra map layer.
1225        self.depth = key_info.depth.max(value_info.depth) + 1;
1226        self.has_borrow = key_info.has_borrow || value_info.has_borrow;
1227    }
1228}