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