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