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