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