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