wasmtime_environ/component/
types_builder.rs

1use crate::component::*;
2use crate::prelude::*;
3use crate::{
4    EntityType, Module, ModuleTypes, ModuleTypesBuilder, PrimaryMap, TypeConvert, WasmHeapType,
5    WasmValType,
6};
7use anyhow::{bail, Result};
8use cranelift_entity::EntityRef;
9use std::collections::HashMap;
10use std::hash::Hash;
11use std::ops::Index;
12use wasmparser::names::KebabString;
13use wasmparser::{types, Validator};
14use wasmtime_component_util::FlagsSize;
15use wasmtime_types::ModuleInternedTypeIndex;
16
17mod resources;
18pub use resources::ResourcesBuilder;
19
20/// Maximum nesting depth of a type allowed in Wasmtime.
21///
22/// This constant isn't chosen via any scientific means and its main purpose is
23/// to enable most of Wasmtime to handle types via recursion without worrying
24/// about stack overflow.
25///
26/// Some more information about this can be found in #4814
27const MAX_TYPE_DEPTH: u32 = 100;
28
29/// Structured used to build a [`ComponentTypes`] during translation.
30///
31/// This contains tables to intern any component types found as well as
32/// managing building up core wasm [`ModuleTypes`] as well.
33pub struct ComponentTypesBuilder {
34    functions: HashMap<TypeFunc, TypeFuncIndex>,
35    lists: HashMap<TypeList, TypeListIndex>,
36    records: HashMap<TypeRecord, TypeRecordIndex>,
37    variants: HashMap<TypeVariant, TypeVariantIndex>,
38    tuples: HashMap<TypeTuple, TypeTupleIndex>,
39    enums: HashMap<TypeEnum, TypeEnumIndex>,
40    flags: HashMap<TypeFlags, TypeFlagsIndex>,
41    options: HashMap<TypeOption, TypeOptionIndex>,
42    results: HashMap<TypeResult, TypeResultIndex>,
43
44    component_types: ComponentTypes,
45    module_types: ModuleTypesBuilder,
46
47    // Cache of what the "flat" representation of all types are which is only
48    // used at compile-time and not used at runtime, hence the location here
49    // as opposed to `ComponentTypes`.
50    type_info: TypeInformationCache,
51
52    resources: ResourcesBuilder,
53}
54
55impl<T> Index<T> for ComponentTypesBuilder
56where
57    ModuleTypes: Index<T>,
58{
59    type Output = <ModuleTypes as Index<T>>::Output;
60    fn index(&self, idx: T) -> &Self::Output {
61        self.module_types.index(idx)
62    }
63}
64
65macro_rules! intern_and_fill_flat_types {
66    ($me:ident, $name:ident, $val:ident) => {{
67        if let Some(idx) = $me.$name.get(&$val) {
68            return *idx;
69        }
70        let idx = $me.component_types.$name.push($val.clone());
71        let mut info = TypeInformation::new();
72        info.$name($me, &$val);
73        let idx2 = $me.type_info.$name.push(info);
74        assert_eq!(idx, idx2);
75        $me.$name.insert($val, idx);
76        return idx;
77    }};
78}
79
80impl ComponentTypesBuilder {
81    /// Construct a new `ComponentTypesBuilder` for use with the given validator.
82    pub fn new(validator: &Validator) -> Self {
83        Self {
84            module_types: ModuleTypesBuilder::new(validator),
85
86            functions: HashMap::default(),
87            lists: HashMap::default(),
88            records: HashMap::default(),
89            variants: HashMap::default(),
90            tuples: HashMap::default(),
91            enums: HashMap::default(),
92            flags: HashMap::default(),
93            options: HashMap::default(),
94            results: HashMap::default(),
95            component_types: ComponentTypes::default(),
96            type_info: TypeInformationCache::default(),
97            resources: ResourcesBuilder::default(),
98        }
99    }
100
101    fn export_type_def(
102        &mut self,
103        export_items: &PrimaryMap<ExportIndex, Export>,
104        idx: ExportIndex,
105    ) -> TypeDef {
106        match &export_items[idx] {
107            Export::LiftedFunction { ty, .. } => TypeDef::ComponentFunc(*ty),
108            Export::ModuleStatic { ty, .. } | Export::ModuleImport { ty, .. } => {
109                TypeDef::Module(*ty)
110            }
111            Export::Instance { ty, .. } => TypeDef::ComponentInstance(*ty),
112            Export::Type(ty) => *ty,
113        }
114    }
115
116    /// Finishes this list of component types and returns the finished
117    /// structure and the [`TypeComponentIndex`] corresponding to top-level component
118    /// with `imports` and `exports` specified.
119    pub fn finish(mut self, component: &Component) -> (ComponentTypes, TypeComponentIndex) {
120        let mut component_ty = TypeComponent::default();
121        for (_, (name, ty)) in component.import_types.iter() {
122            component_ty.imports.insert(name.clone(), *ty);
123        }
124        for (name, ty) in component.exports.raw_iter() {
125            component_ty.exports.insert(
126                name.clone(),
127                self.export_type_def(&component.export_items, *ty),
128            );
129        }
130        let ty = self.component_types.components.push(component_ty);
131
132        self.component_types.module_types = Some(self.module_types.finish());
133        (self.component_types, ty)
134    }
135
136    /// Smaller helper method to find a `ModuleInternedTypeIndex` which
137    /// corresponds to the `resource.drop` intrinsic in components, namely a
138    /// core wasm function type which takes one `i32` argument and has no
139    /// results.
140    ///
141    /// This is a bit of a hack right now as ideally this find operation
142    /// wouldn't be needed and instead the `ModuleInternedTypeIndex` itself
143    /// would be threaded through appropriately, but that's left for a future
144    /// refactoring. Try not to lean too hard on this method though.
145    pub fn find_resource_drop_signature(&self) -> Option<ModuleInternedTypeIndex> {
146        self.module_types
147            .wasm_types()
148            .find(|(_, ty)| {
149                ty.as_func().map_or(false, |sig| {
150                    sig.params().len() == 1
151                        && sig.returns().len() == 0
152                        && sig.params()[0] == WasmValType::I32
153                })
154            })
155            .map(|(i, _)| i)
156    }
157
158    /// Returns the underlying builder used to build up core wasm module types.
159    ///
160    /// Note that this is shared across all modules found within a component to
161    /// improve the wins from deduplicating function signatures.
162    pub fn module_types_builder(&self) -> &ModuleTypesBuilder {
163        &self.module_types
164    }
165
166    /// Same as `module_types_builder`, but `mut`.
167    pub fn module_types_builder_mut(&mut self) -> &mut ModuleTypesBuilder {
168        &mut self.module_types
169    }
170
171    /// Returns the internal reference to the in-progress `&ComponentTypes`.
172    pub(super) fn component_types(&self) -> &ComponentTypes {
173        &self.component_types
174    }
175
176    /// Returns the number of resource tables allocated so far, or the maximum
177    /// `TypeResourceTableIndex`.
178    pub fn num_resource_tables(&self) -> usize {
179        self.component_types.resource_tables.len()
180    }
181
182    /// Returns a mutable reference to the underlying `ResourcesBuilder`.
183    pub fn resources_mut(&mut self) -> &mut ResourcesBuilder {
184        &mut self.resources
185    }
186
187    /// Work around the borrow checker to borrow two sub-fields simultaneously
188    /// externally.
189    pub fn resources_mut_and_types(&mut self) -> (&mut ResourcesBuilder, &ComponentTypes) {
190        (&mut self.resources, &self.component_types)
191    }
192
193    /// Converts a wasmparser `ComponentFuncType` into Wasmtime's type
194    /// representation.
195    pub fn convert_component_func_type(
196        &mut self,
197        types: types::TypesRef<'_>,
198        id: types::ComponentFuncTypeId,
199    ) -> Result<TypeFuncIndex> {
200        assert_eq!(types.id(), self.module_types.validator_id());
201        let ty = &types[id];
202        let params = ty
203            .params
204            .iter()
205            .map(|(_name, ty)| self.valtype(types, ty))
206            .collect::<Result<_>>()?;
207        let results = ty
208            .results
209            .iter()
210            .map(|(_name, ty)| self.valtype(types, ty))
211            .collect::<Result<_>>()?;
212        let ty = TypeFunc {
213            params: self.new_tuple_type(params),
214            results: self.new_tuple_type(results),
215        };
216        Ok(self.add_func_type(ty))
217    }
218
219    /// Converts a wasmparser `ComponentEntityType` into Wasmtime's type
220    /// representation.
221    pub fn convert_component_entity_type(
222        &mut self,
223        types: types::TypesRef<'_>,
224        ty: types::ComponentEntityType,
225    ) -> Result<TypeDef> {
226        assert_eq!(types.id(), self.module_types.validator_id());
227        Ok(match ty {
228            types::ComponentEntityType::Module(id) => {
229                TypeDef::Module(self.convert_module(types, id)?)
230            }
231            types::ComponentEntityType::Component(id) => {
232                TypeDef::Component(self.convert_component(types, id)?)
233            }
234            types::ComponentEntityType::Instance(id) => {
235                TypeDef::ComponentInstance(self.convert_instance(types, id)?)
236            }
237            types::ComponentEntityType::Func(id) => {
238                TypeDef::ComponentFunc(self.convert_component_func_type(types, id)?)
239            }
240            types::ComponentEntityType::Type { created, .. } => match created {
241                types::ComponentAnyTypeId::Defined(id) => {
242                    TypeDef::Interface(self.defined_type(types, id)?)
243                }
244                types::ComponentAnyTypeId::Resource(id) => {
245                    TypeDef::Resource(self.resource_id(id.resource()))
246                }
247                _ => bail!("unsupported type export"),
248            },
249            types::ComponentEntityType::Value(_) => bail!("values not supported"),
250        })
251    }
252
253    /// Converts a wasmparser `Type` into Wasmtime's type representation.
254    pub fn convert_type(
255        &mut self,
256        types: types::TypesRef<'_>,
257        id: types::ComponentAnyTypeId,
258    ) -> Result<TypeDef> {
259        assert_eq!(types.id(), self.module_types.validator_id());
260        Ok(match id {
261            types::ComponentAnyTypeId::Defined(id) => {
262                TypeDef::Interface(self.defined_type(types, id)?)
263            }
264            types::ComponentAnyTypeId::Component(id) => {
265                TypeDef::Component(self.convert_component(types, id)?)
266            }
267            types::ComponentAnyTypeId::Instance(id) => {
268                TypeDef::ComponentInstance(self.convert_instance(types, id)?)
269            }
270            types::ComponentAnyTypeId::Func(id) => {
271                TypeDef::ComponentFunc(self.convert_component_func_type(types, id)?)
272            }
273            types::ComponentAnyTypeId::Resource(id) => {
274                TypeDef::Resource(self.resource_id(id.resource()))
275            }
276        })
277    }
278
279    fn convert_component(
280        &mut self,
281        types: types::TypesRef<'_>,
282        id: types::ComponentTypeId,
283    ) -> Result<TypeComponentIndex> {
284        assert_eq!(types.id(), self.module_types.validator_id());
285        let ty = &types[id];
286        let mut result = TypeComponent::default();
287        for (name, ty) in ty.imports.iter() {
288            result.imports.insert(
289                name.clone(),
290                self.convert_component_entity_type(types, *ty)?,
291            );
292        }
293        for (name, ty) in ty.exports.iter() {
294            result.exports.insert(
295                name.clone(),
296                self.convert_component_entity_type(types, *ty)?,
297            );
298        }
299        Ok(self.component_types.components.push(result))
300    }
301
302    pub(crate) fn convert_instance(
303        &mut self,
304        types: types::TypesRef<'_>,
305        id: types::ComponentInstanceTypeId,
306    ) -> Result<TypeComponentInstanceIndex> {
307        assert_eq!(types.id(), self.module_types.validator_id());
308        let ty = &types[id];
309        let mut result = TypeComponentInstance::default();
310        for (name, ty) in ty.exports.iter() {
311            result.exports.insert(
312                name.clone(),
313                self.convert_component_entity_type(types, *ty)?,
314            );
315        }
316        Ok(self.component_types.component_instances.push(result))
317    }
318
319    pub(crate) fn convert_module(
320        &mut self,
321        types: types::TypesRef<'_>,
322        id: types::ComponentCoreModuleTypeId,
323    ) -> Result<TypeModuleIndex> {
324        assert_eq!(types.id(), self.module_types.validator_id());
325        let ty = &types[id];
326        let mut result = TypeModule::default();
327        for ((module, field), ty) in ty.imports.iter() {
328            result.imports.insert(
329                (module.clone(), field.clone()),
330                self.entity_type(types, ty)?,
331            );
332        }
333        for (name, ty) in ty.exports.iter() {
334            result
335                .exports
336                .insert(name.clone(), self.entity_type(types, ty)?);
337        }
338        Ok(self.component_types.modules.push(result))
339    }
340
341    fn entity_type(
342        &mut self,
343        types: types::TypesRef<'_>,
344        ty: &types::EntityType,
345    ) -> Result<EntityType> {
346        assert_eq!(types.id(), self.module_types.validator_id());
347        Ok(match ty {
348            types::EntityType::Func(id) => EntityType::Function({
349                let module = Module::default();
350                self.module_types_builder_mut()
351                    .intern_type(&module, types, *id)?
352                    .into()
353            }),
354            types::EntityType::Table(ty) => EntityType::Table(self.convert_table_type(ty)?),
355            types::EntityType::Memory(ty) => EntityType::Memory((*ty).into()),
356            types::EntityType::Global(ty) => EntityType::Global(self.convert_global_type(ty)),
357            types::EntityType::Tag(_) => bail!("exceptions proposal not implemented"),
358        })
359    }
360
361    fn defined_type(
362        &mut self,
363        types: types::TypesRef<'_>,
364        id: types::ComponentDefinedTypeId,
365    ) -> Result<InterfaceType> {
366        assert_eq!(types.id(), self.module_types.validator_id());
367        let ret = match &types[id] {
368            types::ComponentDefinedType::Primitive(ty) => ty.into(),
369            types::ComponentDefinedType::Record(e) => {
370                InterfaceType::Record(self.record_type(types, e)?)
371            }
372            types::ComponentDefinedType::Variant(e) => {
373                InterfaceType::Variant(self.variant_type(types, e)?)
374            }
375            types::ComponentDefinedType::List(e) => InterfaceType::List(self.list_type(types, e)?),
376            types::ComponentDefinedType::Tuple(e) => {
377                InterfaceType::Tuple(self.tuple_type(types, e)?)
378            }
379            types::ComponentDefinedType::Flags(e) => InterfaceType::Flags(self.flags_type(e)),
380            types::ComponentDefinedType::Enum(e) => InterfaceType::Enum(self.enum_type(e)),
381            types::ComponentDefinedType::Option(e) => {
382                InterfaceType::Option(self.option_type(types, e)?)
383            }
384            types::ComponentDefinedType::Result { ok, err } => {
385                InterfaceType::Result(self.result_type(types, ok, err)?)
386            }
387            types::ComponentDefinedType::Own(r) => {
388                InterfaceType::Own(self.resource_id(r.resource()))
389            }
390            types::ComponentDefinedType::Borrow(r) => {
391                InterfaceType::Borrow(self.resource_id(r.resource()))
392            }
393        };
394        let info = self.type_information(&ret);
395        if info.depth > MAX_TYPE_DEPTH {
396            bail!("type nesting is too deep");
397        }
398        Ok(ret)
399    }
400
401    fn valtype(
402        &mut self,
403        types: types::TypesRef<'_>,
404        ty: &types::ComponentValType,
405    ) -> Result<InterfaceType> {
406        assert_eq!(types.id(), self.module_types.validator_id());
407        match ty {
408            types::ComponentValType::Primitive(p) => Ok(p.into()),
409            types::ComponentValType::Type(id) => self.defined_type(types, *id),
410        }
411    }
412
413    fn record_type(
414        &mut self,
415        types: types::TypesRef<'_>,
416        ty: &types::RecordType,
417    ) -> Result<TypeRecordIndex> {
418        assert_eq!(types.id(), self.module_types.validator_id());
419        let fields = ty
420            .fields
421            .iter()
422            .map(|(name, ty)| {
423                Ok(RecordField {
424                    name: name.to_string(),
425                    ty: self.valtype(types, ty)?,
426                })
427            })
428            .collect::<Result<Box<[_]>>>()?;
429        let abi = CanonicalAbiInfo::record(
430            fields
431                .iter()
432                .map(|field| self.component_types.canonical_abi(&field.ty)),
433        );
434        Ok(self.add_record_type(TypeRecord { fields, abi }))
435    }
436
437    fn variant_type(
438        &mut self,
439        types: types::TypesRef<'_>,
440        ty: &types::VariantType,
441    ) -> Result<TypeVariantIndex> {
442        assert_eq!(types.id(), self.module_types.validator_id());
443        let cases = ty
444            .cases
445            .iter()
446            .map(|(name, case)| {
447                // FIXME: need to implement `refines`, not sure what that
448                // is at this time.
449                if case.refines.is_some() {
450                    bail!("refines is not supported at this time");
451                }
452                Ok((
453                    name.to_string(),
454                    match &case.ty.as_ref() {
455                        Some(ty) => Some(self.valtype(types, ty)?),
456                        None => None,
457                    },
458                ))
459            })
460            .collect::<Result<IndexMap<_, _>>>()?;
461        let (info, abi) = VariantInfo::new(
462            cases
463                .iter()
464                .map(|(_, c)| c.as_ref().map(|ty| self.component_types.canonical_abi(ty))),
465        );
466        Ok(self.add_variant_type(TypeVariant { cases, abi, info }))
467    }
468
469    fn tuple_type(
470        &mut self,
471        types: types::TypesRef<'_>,
472        ty: &types::TupleType,
473    ) -> Result<TypeTupleIndex> {
474        assert_eq!(types.id(), self.module_types.validator_id());
475        let types = ty
476            .types
477            .iter()
478            .map(|ty| self.valtype(types, ty))
479            .collect::<Result<Box<[_]>>>()?;
480        Ok(self.new_tuple_type(types))
481    }
482
483    fn new_tuple_type(&mut self, types: Box<[InterfaceType]>) -> TypeTupleIndex {
484        let abi = CanonicalAbiInfo::record(
485            types
486                .iter()
487                .map(|ty| self.component_types.canonical_abi(ty)),
488        );
489        self.add_tuple_type(TypeTuple { types, abi })
490    }
491
492    fn flags_type(&mut self, flags: &IndexSet<KebabString>) -> TypeFlagsIndex {
493        let flags = TypeFlags {
494            names: flags.iter().map(|s| s.to_string()).collect(),
495            abi: CanonicalAbiInfo::flags(flags.len()),
496        };
497        self.add_flags_type(flags)
498    }
499
500    fn enum_type(&mut self, variants: &IndexSet<KebabString>) -> TypeEnumIndex {
501        let names = variants
502            .iter()
503            .map(|s| s.to_string())
504            .collect::<IndexSet<_>>();
505        let (info, abi) = VariantInfo::new(names.iter().map(|_| None));
506        self.add_enum_type(TypeEnum { names, abi, info })
507    }
508
509    fn option_type(
510        &mut self,
511        types: types::TypesRef<'_>,
512        ty: &types::ComponentValType,
513    ) -> Result<TypeOptionIndex> {
514        assert_eq!(types.id(), self.module_types.validator_id());
515        let ty = self.valtype(types, ty)?;
516        let (info, abi) = VariantInfo::new([None, Some(self.component_types.canonical_abi(&ty))]);
517        Ok(self.add_option_type(TypeOption { ty, abi, info }))
518    }
519
520    fn result_type(
521        &mut self,
522        types: types::TypesRef<'_>,
523        ok: &Option<types::ComponentValType>,
524        err: &Option<types::ComponentValType>,
525    ) -> Result<TypeResultIndex> {
526        assert_eq!(types.id(), self.module_types.validator_id());
527        let ok = match ok {
528            Some(ty) => Some(self.valtype(types, ty)?),
529            None => None,
530        };
531        let err = match err {
532            Some(ty) => Some(self.valtype(types, ty)?),
533            None => None,
534        };
535        let (info, abi) = VariantInfo::new([
536            ok.as_ref().map(|t| self.component_types.canonical_abi(t)),
537            err.as_ref().map(|t| self.component_types.canonical_abi(t)),
538        ]);
539        Ok(self.add_result_type(TypeResult { ok, err, abi, info }))
540    }
541
542    fn list_type(
543        &mut self,
544        types: types::TypesRef<'_>,
545        ty: &types::ComponentValType,
546    ) -> Result<TypeListIndex> {
547        assert_eq!(types.id(), self.module_types.validator_id());
548        let element = self.valtype(types, ty)?;
549        Ok(self.add_list_type(TypeList { element }))
550    }
551
552    /// Converts a wasmparser `id`, which must point to a resource, to its
553    /// corresponding `TypeResourceTableIndex`.
554    pub fn resource_id(&mut self, id: types::ResourceId) -> TypeResourceTableIndex {
555        self.resources.convert(id, &mut self.component_types)
556    }
557
558    /// Interns a new function type within this type information.
559    pub fn add_func_type(&mut self, ty: TypeFunc) -> TypeFuncIndex {
560        intern(&mut self.functions, &mut self.component_types.functions, ty)
561    }
562
563    /// Interns a new record type within this type information.
564    pub fn add_record_type(&mut self, ty: TypeRecord) -> TypeRecordIndex {
565        intern_and_fill_flat_types!(self, records, ty)
566    }
567
568    /// Interns a new flags type within this type information.
569    pub fn add_flags_type(&mut self, ty: TypeFlags) -> TypeFlagsIndex {
570        intern_and_fill_flat_types!(self, flags, ty)
571    }
572
573    /// Interns a new tuple type within this type information.
574    pub fn add_tuple_type(&mut self, ty: TypeTuple) -> TypeTupleIndex {
575        intern_and_fill_flat_types!(self, tuples, ty)
576    }
577
578    /// Interns a new variant type within this type information.
579    pub fn add_variant_type(&mut self, ty: TypeVariant) -> TypeVariantIndex {
580        intern_and_fill_flat_types!(self, variants, ty)
581    }
582
583    /// Interns a new enum type within this type information.
584    pub fn add_enum_type(&mut self, ty: TypeEnum) -> TypeEnumIndex {
585        intern_and_fill_flat_types!(self, enums, ty)
586    }
587
588    /// Interns a new option type within this type information.
589    pub fn add_option_type(&mut self, ty: TypeOption) -> TypeOptionIndex {
590        intern_and_fill_flat_types!(self, options, ty)
591    }
592
593    /// Interns a new result type within this type information.
594    pub fn add_result_type(&mut self, ty: TypeResult) -> TypeResultIndex {
595        intern_and_fill_flat_types!(self, results, ty)
596    }
597
598    /// Interns a new type within this type information.
599    pub fn add_list_type(&mut self, ty: TypeList) -> TypeListIndex {
600        intern_and_fill_flat_types!(self, lists, ty)
601    }
602
603    /// Returns the canonical ABI information about the specified type.
604    pub fn canonical_abi(&self, ty: &InterfaceType) -> &CanonicalAbiInfo {
605        self.component_types.canonical_abi(ty)
606    }
607
608    /// Returns the "flat types" for the given interface type used in the
609    /// canonical ABI.
610    ///
611    /// Returns `None` if the type is too large to be represented via flat types
612    /// in the canonical abi.
613    pub fn flat_types(&self, ty: &InterfaceType) -> Option<FlatTypes<'_>> {
614        self.type_information(ty).flat.as_flat_types()
615    }
616
617    /// Returns whether the type specified contains any borrowed resources
618    /// within it.
619    pub fn ty_contains_borrow_resource(&self, ty: &InterfaceType) -> bool {
620        self.type_information(ty).has_borrow
621    }
622
623    fn type_information(&self, ty: &InterfaceType) -> &TypeInformation {
624        match ty {
625            InterfaceType::U8
626            | InterfaceType::S8
627            | InterfaceType::Bool
628            | InterfaceType::U16
629            | InterfaceType::S16
630            | InterfaceType::U32
631            | InterfaceType::S32
632            | InterfaceType::Char
633            | InterfaceType::Own(_) => {
634                static INFO: TypeInformation = TypeInformation::primitive(FlatType::I32);
635                &INFO
636            }
637            InterfaceType::Borrow(_) => {
638                static INFO: TypeInformation = {
639                    let mut info = TypeInformation::primitive(FlatType::I32);
640                    info.has_borrow = true;
641                    info
642                };
643                &INFO
644            }
645            InterfaceType::U64 | InterfaceType::S64 => {
646                static INFO: TypeInformation = TypeInformation::primitive(FlatType::I64);
647                &INFO
648            }
649            InterfaceType::Float32 => {
650                static INFO: TypeInformation = TypeInformation::primitive(FlatType::F32);
651                &INFO
652            }
653            InterfaceType::Float64 => {
654                static INFO: TypeInformation = TypeInformation::primitive(FlatType::F64);
655                &INFO
656            }
657            InterfaceType::String => {
658                static INFO: TypeInformation = TypeInformation::string();
659                &INFO
660            }
661
662            InterfaceType::List(i) => &self.type_info.lists[*i],
663            InterfaceType::Record(i) => &self.type_info.records[*i],
664            InterfaceType::Variant(i) => &self.type_info.variants[*i],
665            InterfaceType::Tuple(i) => &self.type_info.tuples[*i],
666            InterfaceType::Flags(i) => &self.type_info.flags[*i],
667            InterfaceType::Enum(i) => &self.type_info.enums[*i],
668            InterfaceType::Option(i) => &self.type_info.options[*i],
669            InterfaceType::Result(i) => &self.type_info.results[*i],
670        }
671    }
672}
673
674impl TypeConvert for ComponentTypesBuilder {
675    fn lookup_heap_type(&self, _index: wasmparser::UnpackedIndex) -> WasmHeapType {
676        panic!("heap types are not supported yet")
677    }
678
679    fn lookup_type_index(
680        &self,
681        _index: wasmparser::UnpackedIndex,
682    ) -> wasmtime_types::EngineOrModuleTypeIndex {
683        panic!("typed references are not supported yet")
684    }
685}
686
687fn intern<T, U>(map: &mut HashMap<T, U>, list: &mut PrimaryMap<U, T>, item: T) -> U
688where
689    T: Hash + Clone + Eq,
690    U: Copy + EntityRef,
691{
692    if let Some(idx) = map.get(&item) {
693        return *idx;
694    }
695    let idx = list.push(item.clone());
696    map.insert(item, idx);
697    return idx;
698}
699
700struct FlatTypesStorage {
701    // This could be represented as `Vec<FlatType>` but on 64-bit architectures
702    // that's 24 bytes. Otherwise `FlatType` is 1 byte large and
703    // `MAX_FLAT_TYPES` is 16, so it should ideally be more space-efficient to
704    // use a flat array instead of a heap-based vector.
705    memory32: [FlatType; MAX_FLAT_TYPES],
706    memory64: [FlatType; MAX_FLAT_TYPES],
707
708    // Tracks the number of flat types pushed into this storage. If this is
709    // `MAX_FLAT_TYPES + 1` then this storage represents an un-reprsentable
710    // type in flat types.
711    len: u8,
712}
713
714impl FlatTypesStorage {
715    const fn new() -> FlatTypesStorage {
716        FlatTypesStorage {
717            memory32: [FlatType::I32; MAX_FLAT_TYPES],
718            memory64: [FlatType::I32; MAX_FLAT_TYPES],
719            len: 0,
720        }
721    }
722
723    fn as_flat_types(&self) -> Option<FlatTypes<'_>> {
724        let len = usize::from(self.len);
725        if len > MAX_FLAT_TYPES {
726            assert_eq!(len, MAX_FLAT_TYPES + 1);
727            None
728        } else {
729            Some(FlatTypes {
730                memory32: &self.memory32[..len],
731                memory64: &self.memory64[..len],
732            })
733        }
734    }
735
736    /// Pushes a new flat type into this list using `t32` for 32-bit memories
737    /// and `t64` for 64-bit memories.
738    ///
739    /// Returns whether the type was actually pushed or whether this list of
740    /// flat types just exceeded the maximum meaning that it is now
741    /// unrepresentable with a flat list of types.
742    fn push(&mut self, t32: FlatType, t64: FlatType) -> bool {
743        let len = usize::from(self.len);
744        if len < MAX_FLAT_TYPES {
745            self.memory32[len] = t32;
746            self.memory64[len] = t64;
747            self.len += 1;
748            true
749        } else {
750            // If this was the first one to go over then flag the length as
751            // being incompatible with a flat representation.
752            if len == MAX_FLAT_TYPES {
753                self.len += 1;
754            }
755            false
756        }
757    }
758}
759
760impl FlatType {
761    fn join(&mut self, other: FlatType) {
762        if *self == other {
763            return;
764        }
765        *self = match (*self, other) {
766            (FlatType::I32, FlatType::F32) | (FlatType::F32, FlatType::I32) => FlatType::I32,
767            _ => FlatType::I64,
768        };
769    }
770}
771
772#[derive(Default)]
773struct TypeInformationCache {
774    records: PrimaryMap<TypeRecordIndex, TypeInformation>,
775    variants: PrimaryMap<TypeVariantIndex, TypeInformation>,
776    tuples: PrimaryMap<TypeTupleIndex, TypeInformation>,
777    enums: PrimaryMap<TypeEnumIndex, TypeInformation>,
778    flags: PrimaryMap<TypeFlagsIndex, TypeInformation>,
779    options: PrimaryMap<TypeOptionIndex, TypeInformation>,
780    results: PrimaryMap<TypeResultIndex, TypeInformation>,
781    lists: PrimaryMap<TypeListIndex, TypeInformation>,
782}
783
784struct TypeInformation {
785    depth: u32,
786    flat: FlatTypesStorage,
787    has_borrow: bool,
788}
789
790impl TypeInformation {
791    const fn new() -> TypeInformation {
792        TypeInformation {
793            depth: 0,
794            flat: FlatTypesStorage::new(),
795            has_borrow: false,
796        }
797    }
798
799    const fn primitive(flat: FlatType) -> TypeInformation {
800        let mut info = TypeInformation::new();
801        info.depth = 1;
802        info.flat.memory32[0] = flat;
803        info.flat.memory64[0] = flat;
804        info.flat.len = 1;
805        info
806    }
807
808    const fn string() -> TypeInformation {
809        let mut info = TypeInformation::new();
810        info.depth = 1;
811        info.flat.memory32[0] = FlatType::I32;
812        info.flat.memory32[1] = FlatType::I32;
813        info.flat.memory64[0] = FlatType::I64;
814        info.flat.memory64[1] = FlatType::I64;
815        info.flat.len = 2;
816        info
817    }
818
819    /// Builds up all flat types internally using the specified representation
820    /// for all of the component fields of the record.
821    fn build_record<'a>(&mut self, types: impl Iterator<Item = &'a TypeInformation>) {
822        self.depth = 1;
823        for info in types {
824            self.depth = self.depth.max(1 + info.depth);
825            self.has_borrow = self.has_borrow || info.has_borrow;
826            match info.flat.as_flat_types() {
827                Some(types) => {
828                    for (t32, t64) in types.memory32.iter().zip(types.memory64) {
829                        if !self.flat.push(*t32, *t64) {
830                            break;
831                        }
832                    }
833                }
834                None => {
835                    self.flat.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap();
836                }
837            }
838        }
839    }
840
841    /// Builds up the flat types used to represent a `variant` which notably
842    /// handles "join"ing types together so each case is representable as a
843    /// single flat list of types.
844    ///
845    /// The iterator item is:
846    ///
847    /// * `None` - no payload for this case
848    /// * `Some(None)` - this case has a payload but can't be represented with
849    ///   flat types
850    /// * `Some(Some(types))` - this case has a payload and is represented with
851    ///   the types specified in the flat representation.
852    fn build_variant<'a, I>(&mut self, cases: I)
853    where
854        I: IntoIterator<Item = Option<&'a TypeInformation>>,
855    {
856        let cases = cases.into_iter();
857        self.flat.push(FlatType::I32, FlatType::I32);
858        self.depth = 1;
859
860        for info in cases {
861            let info = match info {
862                Some(info) => info,
863                // If this case doesn't have a payload then it doesn't change
864                // the depth/flat representation
865                None => continue,
866            };
867            self.depth = self.depth.max(1 + info.depth);
868            self.has_borrow = self.has_borrow || info.has_borrow;
869
870            // If this variant is already unrepresentable in a flat
871            // representation then this can be skipped.
872            if usize::from(self.flat.len) > MAX_FLAT_TYPES {
873                continue;
874            }
875
876            let types = match info.flat.as_flat_types() {
877                Some(types) => types,
878                // If this case isn't representable with a flat list of types
879                // then this variant also isn't representable.
880                None => {
881                    self.flat.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap();
882                    continue;
883                }
884            };
885            // If the case used all of the flat types then the discriminant
886            // added for this variant means that this variant is no longer
887            // representable.
888            if types.memory32.len() >= MAX_FLAT_TYPES {
889                self.flat.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap();
890                continue;
891            }
892            let dst = self
893                .flat
894                .memory32
895                .iter_mut()
896                .zip(&mut self.flat.memory64)
897                .skip(1);
898            for (i, ((t32, t64), (dst32, dst64))) in types
899                .memory32
900                .iter()
901                .zip(types.memory64)
902                .zip(dst)
903                .enumerate()
904            {
905                if i + 1 < usize::from(self.flat.len) {
906                    // If this index hs already been set by some previous case
907                    // then the types are joined together.
908                    dst32.join(*t32);
909                    dst64.join(*t64);
910                } else {
911                    // Otherwise if this is the first time that the
912                    // representation has gotten this large then the destination
913                    // is simply whatever the type is. The length is also
914                    // increased here to indicate this.
915                    self.flat.len += 1;
916                    *dst32 = *t32;
917                    *dst64 = *t64;
918                }
919            }
920        }
921    }
922
923    fn records(&mut self, types: &ComponentTypesBuilder, ty: &TypeRecord) {
924        self.build_record(ty.fields.iter().map(|f| types.type_information(&f.ty)));
925    }
926
927    fn tuples(&mut self, types: &ComponentTypesBuilder, ty: &TypeTuple) {
928        self.build_record(ty.types.iter().map(|t| types.type_information(t)));
929    }
930
931    fn enums(&mut self, _types: &ComponentTypesBuilder, _ty: &TypeEnum) {
932        self.depth = 1;
933        self.flat.push(FlatType::I32, FlatType::I32);
934    }
935
936    fn flags(&mut self, _types: &ComponentTypesBuilder, ty: &TypeFlags) {
937        self.depth = 1;
938        match FlagsSize::from_count(ty.names.len()) {
939            FlagsSize::Size0 => {}
940            FlagsSize::Size1 | FlagsSize::Size2 => {
941                self.flat.push(FlatType::I32, FlatType::I32);
942            }
943            FlagsSize::Size4Plus(n) => {
944                for _ in 0..n {
945                    self.flat.push(FlatType::I32, FlatType::I32);
946                }
947            }
948        }
949    }
950
951    fn variants(&mut self, types: &ComponentTypesBuilder, ty: &TypeVariant) {
952        self.build_variant(
953            ty.cases
954                .iter()
955                .map(|(_, c)| c.as_ref().map(|ty| types.type_information(ty))),
956        )
957    }
958
959    fn results(&mut self, types: &ComponentTypesBuilder, ty: &TypeResult) {
960        self.build_variant([
961            ty.ok.as_ref().map(|ty| types.type_information(ty)),
962            ty.err.as_ref().map(|ty| types.type_information(ty)),
963        ])
964    }
965
966    fn options(&mut self, types: &ComponentTypesBuilder, ty: &TypeOption) {
967        self.build_variant([None, Some(types.type_information(&ty.ty))]);
968    }
969
970    fn lists(&mut self, types: &ComponentTypesBuilder, ty: &TypeList) {
971        *self = TypeInformation::string();
972        let info = types.type_information(&ty.element);
973        self.depth += info.depth;
974        self.has_borrow = info.has_borrow;
975    }
976}