wasmtime_environ/component/
types_builder.rs

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