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
25const MAX_TYPE_DEPTH: u32 = 100;
33
34pub 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 type_info: TypeInformationCache,
61
62 resources: ResourcesBuilder,
63
64 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 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 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 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 pub fn module_types_builder(&self) -> &ModuleTypesBuilder {
186 &self.module_types
187 }
188
189 pub fn module_types_builder_mut(&mut self) -> &mut ModuleTypesBuilder {
191 &mut self.module_types
192 }
193
194 pub(super) fn component_types(&self) -> &ComponentTypes {
196 &self.component_types
197 }
198
199 pub fn num_resource_tables(&self) -> usize {
202 self.component_types.resource_tables.len()
203 }
204
205 pub fn num_future_tables(&self) -> usize {
208 self.component_types.future_tables.len()
209 }
210
211 pub fn num_stream_tables(&self) -> usize {
214 self.component_types.stream_tables.len()
215 }
216
217 pub fn num_error_context_tables(&self) -> usize {
220 self.component_types.error_context_tables.len()
221 }
222
223 pub fn resources_mut(&mut self) -> &mut ResourcesBuilder {
225 &mut self.resources
226 }
227
228 pub fn resources_mut_and_types(&mut self) -> (&mut ResourcesBuilder, &ComponentTypes) {
231 (&mut self.resources, &self.component_types)
232 }
233
234 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 param_names,
258 params,
259 results,
260 };
261 Ok(self.add_func_type(ty))
262 }
263
264 pub fn convert_component_entity_type(
267 &mut self,
268 types: TypesRef<'_>,
269 ty: ComponentEntityType,
270 ) -> Result<TypeDef> {
271 assert_eq!(types.id(), self.module_types.validator_id());
272 Ok(match ty {
273 ComponentEntityType::Module(id) => TypeDef::Module(self.convert_module(types, id)?),
274 ComponentEntityType::Component(id) => {
275 TypeDef::Component(self.convert_component(types, id)?)
276 }
277 ComponentEntityType::Instance(id) => {
278 TypeDef::ComponentInstance(self.convert_instance(types, id)?)
279 }
280 ComponentEntityType::Func(id) => {
281 TypeDef::ComponentFunc(self.convert_component_func_type(types, id)?)
282 }
283 ComponentEntityType::Type { created, .. } => match created {
284 ComponentAnyTypeId::Defined(id) => {
285 TypeDef::Interface(self.defined_type(types, id)?)
286 }
287 ComponentAnyTypeId::Resource(id) => {
288 TypeDef::Resource(self.resource_id(id.resource()))
289 }
290 _ => bail!("unsupported type export"),
291 },
292 ComponentEntityType::Value(_) => bail!("values not supported"),
293 })
294 }
295
296 pub fn convert_type(&mut self, types: TypesRef<'_>, id: ComponentAnyTypeId) -> Result<TypeDef> {
298 assert_eq!(types.id(), self.module_types.validator_id());
299 Ok(match id {
300 ComponentAnyTypeId::Defined(id) => TypeDef::Interface(self.defined_type(types, id)?),
301 ComponentAnyTypeId::Component(id) => {
302 TypeDef::Component(self.convert_component(types, id)?)
303 }
304 ComponentAnyTypeId::Instance(id) => {
305 TypeDef::ComponentInstance(self.convert_instance(types, id)?)
306 }
307 ComponentAnyTypeId::Func(id) => {
308 TypeDef::ComponentFunc(self.convert_component_func_type(types, id)?)
309 }
310 ComponentAnyTypeId::Resource(id) => TypeDef::Resource(self.resource_id(id.resource())),
311 })
312 }
313
314 fn convert_component(
315 &mut self,
316 types: TypesRef<'_>,
317 id: ComponentTypeId,
318 ) -> Result<TypeComponentIndex> {
319 assert_eq!(types.id(), self.module_types.validator_id());
320 let ty = &types[id];
321 let mut result = TypeComponent::default();
322 for (name, ty) in ty.imports.iter() {
323 self.register_abstract_component_entity_type(types, *ty);
324 result.imports.insert(
325 name.clone(),
326 self.convert_component_entity_type(types, *ty)?,
327 );
328 }
329 for (name, ty) in ty.exports.iter() {
330 self.register_abstract_component_entity_type(types, *ty);
331 result.exports.insert(
332 name.clone(),
333 self.convert_component_entity_type(types, *ty)?,
334 );
335 }
336 Ok(self.component_types.components.push(result))
337 }
338
339 pub(crate) fn convert_instance(
340 &mut self,
341 types: TypesRef<'_>,
342 id: ComponentInstanceTypeId,
343 ) -> Result<TypeComponentInstanceIndex> {
344 assert_eq!(types.id(), self.module_types.validator_id());
345 let ty = &types[id];
346 let mut result = TypeComponentInstance::default();
347 for (name, ty) in ty.exports.iter() {
348 self.register_abstract_component_entity_type(types, *ty);
349 result.exports.insert(
350 name.clone(),
351 self.convert_component_entity_type(types, *ty)?,
352 );
353 }
354 Ok(self.component_types.component_instances.push(result))
355 }
356
357 fn register_abstract_component_entity_type(
358 &mut self,
359 types: TypesRef<'_>,
360 ty: ComponentEntityType,
361 ) {
362 let mut path = Vec::new();
363 self.resources.register_abstract_component_entity_type(
364 &types,
365 ty,
366 &mut path,
367 &mut |_path| {
368 self.abstract_resources += 1;
369 AbstractResourceIndex::from_u32(self.abstract_resources)
370 },
371 );
372 }
373
374 pub(crate) fn convert_module(
375 &mut self,
376 types: TypesRef<'_>,
377 id: ComponentCoreModuleTypeId,
378 ) -> Result<TypeModuleIndex> {
379 assert_eq!(types.id(), self.module_types.validator_id());
380 let ty = &types[id];
381 let mut result = TypeModule::default();
382 for ((module, field), ty) in ty.imports.iter() {
383 result.imports.insert(
384 (module.clone(), field.clone()),
385 self.entity_type(types, ty)?,
386 );
387 }
388 for (name, ty) in ty.exports.iter() {
389 result
390 .exports
391 .insert(name.clone(), self.entity_type(types, ty)?);
392 }
393 Ok(self.component_types.modules.push(result))
394 }
395
396 fn entity_type(
397 &mut self,
398 types: TypesRef<'_>,
399 ty: &wasmparser::types::EntityType,
400 ) -> Result<EntityType> {
401 use wasmparser::types::EntityType::*;
402
403 assert_eq!(types.id(), self.module_types.validator_id());
404 Ok(match ty {
405 Func(id) => EntityType::Function({
406 self.module_types_builder_mut()
407 .intern_type(types, *id)?
408 .into()
409 }),
410 Table(ty) => EntityType::Table(self.convert_table_type(ty)?),
411 Memory(ty) => EntityType::Memory((*ty).into()),
412 Global(ty) => EntityType::Global(self.convert_global_type(ty)?),
413 Tag(_) => bail!("exceptions proposal not implemented"),
414 })
415 }
416
417 pub fn defined_type(
419 &mut self,
420 types: TypesRef<'_>,
421 id: ComponentDefinedTypeId,
422 ) -> Result<InterfaceType> {
423 assert_eq!(types.id(), self.module_types.validator_id());
424 let ret = match &types[id] {
425 ComponentDefinedType::Primitive(ty) => self.primitive_type(ty)?,
426 ComponentDefinedType::Record(e) => InterfaceType::Record(self.record_type(types, e)?),
427 ComponentDefinedType::Variant(e) => {
428 InterfaceType::Variant(self.variant_type(types, e)?)
429 }
430 ComponentDefinedType::List(e) => InterfaceType::List(self.list_type(types, e)?),
431 ComponentDefinedType::Tuple(e) => InterfaceType::Tuple(self.tuple_type(types, e)?),
432 ComponentDefinedType::Flags(e) => InterfaceType::Flags(self.flags_type(e)),
433 ComponentDefinedType::Enum(e) => InterfaceType::Enum(self.enum_type(e)),
434 ComponentDefinedType::Option(e) => InterfaceType::Option(self.option_type(types, e)?),
435 ComponentDefinedType::Result { ok, err } => {
436 InterfaceType::Result(self.result_type(types, ok, err)?)
437 }
438 ComponentDefinedType::Own(r) => InterfaceType::Own(self.resource_id(r.resource())),
439 ComponentDefinedType::Borrow(r) => {
440 InterfaceType::Borrow(self.resource_id(r.resource()))
441 }
442 ComponentDefinedType::Future(ty) => {
443 InterfaceType::Future(self.future_table_type(types, ty)?)
444 }
445 ComponentDefinedType::Stream(ty) => {
446 InterfaceType::Stream(self.stream_table_type(types, ty)?)
447 }
448 ComponentDefinedType::FixedSizeList(..) => {
449 bail!("support not implemented for fixed-size-lists");
450 }
451 };
452 let info = self.type_information(&ret);
453 if info.depth > MAX_TYPE_DEPTH {
454 bail!("type nesting is too deep");
455 }
456 Ok(ret)
457 }
458
459 pub fn error_context_type(&mut self) -> Result<TypeComponentLocalErrorContextTableIndex> {
461 self.error_context_table_type()
462 }
463
464 pub(crate) fn valtype(
465 &mut self,
466 types: TypesRef<'_>,
467 ty: &ComponentValType,
468 ) -> Result<InterfaceType> {
469 assert_eq!(types.id(), self.module_types.validator_id());
470 match ty {
471 ComponentValType::Primitive(p) => self.primitive_type(p),
472 ComponentValType::Type(id) => self.defined_type(types, *id),
473 }
474 }
475
476 fn primitive_type(&mut self, ty: &PrimitiveValType) -> Result<InterfaceType> {
477 match ty {
478 wasmparser::PrimitiveValType::Bool => Ok(InterfaceType::Bool),
479 wasmparser::PrimitiveValType::S8 => Ok(InterfaceType::S8),
480 wasmparser::PrimitiveValType::U8 => Ok(InterfaceType::U8),
481 wasmparser::PrimitiveValType::S16 => Ok(InterfaceType::S16),
482 wasmparser::PrimitiveValType::U16 => Ok(InterfaceType::U16),
483 wasmparser::PrimitiveValType::S32 => Ok(InterfaceType::S32),
484 wasmparser::PrimitiveValType::U32 => Ok(InterfaceType::U32),
485 wasmparser::PrimitiveValType::S64 => Ok(InterfaceType::S64),
486 wasmparser::PrimitiveValType::U64 => Ok(InterfaceType::U64),
487 wasmparser::PrimitiveValType::F32 => Ok(InterfaceType::Float32),
488 wasmparser::PrimitiveValType::F64 => Ok(InterfaceType::Float64),
489 wasmparser::PrimitiveValType::Char => Ok(InterfaceType::Char),
490 wasmparser::PrimitiveValType::String => Ok(InterfaceType::String),
491 wasmparser::PrimitiveValType::ErrorContext => Ok(InterfaceType::ErrorContext(
492 self.error_context_table_type()?,
493 )),
494 }
495 }
496
497 fn record_type(&mut self, types: TypesRef<'_>, ty: &RecordType) -> Result<TypeRecordIndex> {
498 assert_eq!(types.id(), self.module_types.validator_id());
499 let fields = ty
500 .fields
501 .iter()
502 .map(|(name, ty)| {
503 Ok(RecordField {
504 name: name.to_string(),
505 ty: self.valtype(types, ty)?,
506 })
507 })
508 .collect::<Result<Box<[_]>>>()?;
509 let abi = CanonicalAbiInfo::record(
510 fields
511 .iter()
512 .map(|field| self.component_types.canonical_abi(&field.ty)),
513 );
514 Ok(self.add_record_type(TypeRecord { fields, abi }))
515 }
516
517 fn variant_type(&mut self, types: TypesRef<'_>, ty: &VariantType) -> Result<TypeVariantIndex> {
518 assert_eq!(types.id(), self.module_types.validator_id());
519 let cases = ty
520 .cases
521 .iter()
522 .map(|(name, case)| {
523 if case.refines.is_some() {
526 bail!("refines is not supported at this time");
527 }
528 Ok((
529 name.to_string(),
530 match &case.ty.as_ref() {
531 Some(ty) => Some(self.valtype(types, ty)?),
532 None => None,
533 },
534 ))
535 })
536 .collect::<Result<IndexMap<_, _>>>()?;
537 let (info, abi) = VariantInfo::new(
538 cases
539 .iter()
540 .map(|(_, c)| c.as_ref().map(|ty| self.component_types.canonical_abi(ty))),
541 );
542 Ok(self.add_variant_type(TypeVariant { cases, abi, info }))
543 }
544
545 fn tuple_type(&mut self, types: TypesRef<'_>, ty: &TupleType) -> Result<TypeTupleIndex> {
546 assert_eq!(types.id(), self.module_types.validator_id());
547 let types = ty
548 .types
549 .iter()
550 .map(|ty| self.valtype(types, ty))
551 .collect::<Result<Box<[_]>>>()?;
552 Ok(self.new_tuple_type(types))
553 }
554
555 pub(crate) fn new_tuple_type(&mut self, types: Box<[InterfaceType]>) -> TypeTupleIndex {
556 let abi = CanonicalAbiInfo::record(
557 types
558 .iter()
559 .map(|ty| self.component_types.canonical_abi(ty)),
560 );
561 self.add_tuple_type(TypeTuple { types, abi })
562 }
563
564 fn flags_type(&mut self, flags: &IndexSet<KebabString>) -> TypeFlagsIndex {
565 let flags = TypeFlags {
566 names: flags.iter().map(|s| s.to_string()).collect(),
567 abi: CanonicalAbiInfo::flags(flags.len()),
568 };
569 self.add_flags_type(flags)
570 }
571
572 fn enum_type(&mut self, variants: &IndexSet<KebabString>) -> TypeEnumIndex {
573 let names = variants
574 .iter()
575 .map(|s| s.to_string())
576 .collect::<IndexSet<_>>();
577 let (info, abi) = VariantInfo::new(names.iter().map(|_| None));
578 self.add_enum_type(TypeEnum { names, abi, info })
579 }
580
581 fn option_type(
582 &mut self,
583 types: TypesRef<'_>,
584 ty: &ComponentValType,
585 ) -> Result<TypeOptionIndex> {
586 assert_eq!(types.id(), self.module_types.validator_id());
587 let ty = self.valtype(types, ty)?;
588 let (info, abi) = VariantInfo::new([None, Some(self.component_types.canonical_abi(&ty))]);
589 Ok(self.add_option_type(TypeOption { ty, abi, info }))
590 }
591
592 fn result_type(
593 &mut self,
594 types: TypesRef<'_>,
595 ok: &Option<ComponentValType>,
596 err: &Option<ComponentValType>,
597 ) -> Result<TypeResultIndex> {
598 assert_eq!(types.id(), self.module_types.validator_id());
599 let ok = match ok {
600 Some(ty) => Some(self.valtype(types, ty)?),
601 None => None,
602 };
603 let err = match err {
604 Some(ty) => Some(self.valtype(types, ty)?),
605 None => None,
606 };
607 let (info, abi) = VariantInfo::new([
608 ok.as_ref().map(|t| self.component_types.canonical_abi(t)),
609 err.as_ref().map(|t| self.component_types.canonical_abi(t)),
610 ]);
611 Ok(self.add_result_type(TypeResult { ok, err, abi, info }))
612 }
613
614 fn future_table_type(
615 &mut self,
616 types: TypesRef<'_>,
617 ty: &Option<ComponentValType>,
618 ) -> Result<TypeFutureTableIndex> {
619 let payload = ty.as_ref().map(|ty| self.valtype(types, ty)).transpose()?;
620 let ty = self.add_future_type(TypeFuture { payload });
621 Ok(self.add_future_table_type(TypeFutureTable {
622 ty,
623 instance: self.resources.get_current_instance().unwrap(),
624 }))
625 }
626
627 fn stream_table_type(
628 &mut self,
629 types: TypesRef<'_>,
630 ty: &Option<ComponentValType>,
631 ) -> Result<TypeStreamTableIndex> {
632 let payload = ty.as_ref().map(|ty| self.valtype(types, ty)).transpose()?;
633 let ty = self.add_stream_type(TypeStream { payload });
634 Ok(self.add_stream_table_type(TypeStreamTable {
635 ty,
636 instance: self.resources.get_current_instance().unwrap(),
637 }))
638 }
639
640 pub fn error_context_table_type(&mut self) -> Result<TypeComponentLocalErrorContextTableIndex> {
643 Ok(self.add_error_context_table_type(TypeErrorContextTable {
644 instance: self.resources.get_current_instance().unwrap(),
645 }))
646 }
647
648 fn list_type(&mut self, types: TypesRef<'_>, ty: &ComponentValType) -> Result<TypeListIndex> {
649 assert_eq!(types.id(), self.module_types.validator_id());
650 let element = self.valtype(types, ty)?;
651 Ok(self.add_list_type(TypeList { element }))
652 }
653
654 pub fn resource_id(&mut self, id: ResourceId) -> TypeResourceTableIndex {
657 self.resources.convert(id, &mut self.component_types)
658 }
659
660 pub fn add_func_type(&mut self, ty: TypeFunc) -> TypeFuncIndex {
662 intern(&mut self.functions, &mut self.component_types.functions, ty)
663 }
664
665 pub fn add_record_type(&mut self, ty: TypeRecord) -> TypeRecordIndex {
667 intern_and_fill_flat_types!(self, records, ty)
668 }
669
670 pub fn add_flags_type(&mut self, ty: TypeFlags) -> TypeFlagsIndex {
672 intern_and_fill_flat_types!(self, flags, ty)
673 }
674
675 pub fn add_tuple_type(&mut self, ty: TypeTuple) -> TypeTupleIndex {
677 intern_and_fill_flat_types!(self, tuples, ty)
678 }
679
680 pub fn add_variant_type(&mut self, ty: TypeVariant) -> TypeVariantIndex {
682 intern_and_fill_flat_types!(self, variants, ty)
683 }
684
685 pub fn add_enum_type(&mut self, ty: TypeEnum) -> TypeEnumIndex {
687 intern_and_fill_flat_types!(self, enums, ty)
688 }
689
690 pub fn add_option_type(&mut self, ty: TypeOption) -> TypeOptionIndex {
692 intern_and_fill_flat_types!(self, options, ty)
693 }
694
695 pub fn add_result_type(&mut self, ty: TypeResult) -> TypeResultIndex {
697 intern_and_fill_flat_types!(self, results, ty)
698 }
699
700 pub fn add_list_type(&mut self, ty: TypeList) -> TypeListIndex {
702 intern_and_fill_flat_types!(self, lists, ty)
703 }
704
705 pub fn add_future_type(&mut self, ty: TypeFuture) -> TypeFutureIndex {
707 intern(&mut self.futures, &mut self.component_types.futures, ty)
708 }
709
710 pub fn add_future_table_type(&mut self, ty: TypeFutureTable) -> TypeFutureTableIndex {
712 intern(
713 &mut self.future_tables,
714 &mut self.component_types.future_tables,
715 ty,
716 )
717 }
718
719 pub fn add_stream_type(&mut self, ty: TypeStream) -> TypeStreamIndex {
721 intern(&mut self.streams, &mut self.component_types.streams, ty)
722 }
723
724 pub fn add_stream_table_type(&mut self, ty: TypeStreamTable) -> TypeStreamTableIndex {
726 intern(
727 &mut self.stream_tables,
728 &mut self.component_types.stream_tables,
729 ty,
730 )
731 }
732
733 pub fn add_error_context_table_type(
735 &mut self,
736 ty: TypeErrorContextTable,
737 ) -> TypeComponentLocalErrorContextTableIndex {
738 intern(
739 &mut self.error_context_tables,
740 &mut self.component_types.error_context_tables,
741 ty,
742 )
743 }
744
745 pub fn canonical_abi(&self, ty: &InterfaceType) -> &CanonicalAbiInfo {
747 self.component_types.canonical_abi(ty)
748 }
749
750 pub fn flat_types(&self, ty: &InterfaceType) -> Option<FlatTypes<'_>> {
756 self.type_information(ty).flat.as_flat_types()
757 }
758
759 pub fn ty_contains_borrow_resource(&self, ty: &InterfaceType) -> bool {
762 self.type_information(ty).has_borrow
763 }
764
765 fn type_information(&self, ty: &InterfaceType) -> &TypeInformation {
766 match ty {
767 InterfaceType::U8
768 | InterfaceType::S8
769 | InterfaceType::Bool
770 | InterfaceType::U16
771 | InterfaceType::S16
772 | InterfaceType::U32
773 | InterfaceType::S32
774 | InterfaceType::Char
775 | InterfaceType::Own(_)
776 | InterfaceType::Future(_)
777 | InterfaceType::Stream(_)
778 | InterfaceType::ErrorContext(_) => {
779 static INFO: TypeInformation = TypeInformation::primitive(FlatType::I32);
780 &INFO
781 }
782 InterfaceType::Borrow(_) => {
783 static INFO: TypeInformation = {
784 let mut info = TypeInformation::primitive(FlatType::I32);
785 info.has_borrow = true;
786 info
787 };
788 &INFO
789 }
790 InterfaceType::U64 | InterfaceType::S64 => {
791 static INFO: TypeInformation = TypeInformation::primitive(FlatType::I64);
792 &INFO
793 }
794 InterfaceType::Float32 => {
795 static INFO: TypeInformation = TypeInformation::primitive(FlatType::F32);
796 &INFO
797 }
798 InterfaceType::Float64 => {
799 static INFO: TypeInformation = TypeInformation::primitive(FlatType::F64);
800 &INFO
801 }
802 InterfaceType::String => {
803 static INFO: TypeInformation = TypeInformation::string();
804 &INFO
805 }
806
807 InterfaceType::List(i) => &self.type_info.lists[*i],
808 InterfaceType::Record(i) => &self.type_info.records[*i],
809 InterfaceType::Variant(i) => &self.type_info.variants[*i],
810 InterfaceType::Tuple(i) => &self.type_info.tuples[*i],
811 InterfaceType::Flags(i) => &self.type_info.flags[*i],
812 InterfaceType::Enum(i) => &self.type_info.enums[*i],
813 InterfaceType::Option(i) => &self.type_info.options[*i],
814 InterfaceType::Result(i) => &self.type_info.results[*i],
815 }
816 }
817}
818
819impl TypeConvert for ComponentTypesBuilder {
820 fn lookup_heap_type(&self, _index: wasmparser::UnpackedIndex) -> WasmHeapType {
821 panic!("heap types are not supported yet")
822 }
823
824 fn lookup_type_index(&self, _index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex {
825 panic!("typed references are not supported yet")
826 }
827}
828
829fn intern<T, U>(map: &mut HashMap<T, U>, list: &mut PrimaryMap<U, T>, item: T) -> U
830where
831 T: Hash + Clone + Eq,
832 U: Copy + EntityRef,
833{
834 if let Some(idx) = map.get(&item) {
835 return *idx;
836 }
837 let idx = list.push(item.clone());
838 map.insert(item, idx);
839 return idx;
840}
841
842struct FlatTypesStorage {
843 memory32: [FlatType; MAX_FLAT_TYPES],
848 memory64: [FlatType; MAX_FLAT_TYPES],
849
850 len: u8,
854}
855
856impl FlatTypesStorage {
857 const fn new() -> FlatTypesStorage {
858 FlatTypesStorage {
859 memory32: [FlatType::I32; MAX_FLAT_TYPES],
860 memory64: [FlatType::I32; MAX_FLAT_TYPES],
861 len: 0,
862 }
863 }
864
865 fn as_flat_types(&self) -> Option<FlatTypes<'_>> {
866 let len = usize::from(self.len);
867 if len > MAX_FLAT_TYPES {
868 assert_eq!(len, MAX_FLAT_TYPES + 1);
869 None
870 } else {
871 Some(FlatTypes {
872 memory32: &self.memory32[..len],
873 memory64: &self.memory64[..len],
874 })
875 }
876 }
877
878 fn push(&mut self, t32: FlatType, t64: FlatType) -> bool {
885 let len = usize::from(self.len);
886 if len < MAX_FLAT_TYPES {
887 self.memory32[len] = t32;
888 self.memory64[len] = t64;
889 self.len += 1;
890 true
891 } else {
892 if len == MAX_FLAT_TYPES {
895 self.len += 1;
896 }
897 false
898 }
899 }
900}
901
902impl FlatType {
903 fn join(&mut self, other: FlatType) {
904 if *self == other {
905 return;
906 }
907 *self = match (*self, other) {
908 (FlatType::I32, FlatType::F32) | (FlatType::F32, FlatType::I32) => FlatType::I32,
909 _ => FlatType::I64,
910 };
911 }
912}
913
914#[derive(Default)]
915struct TypeInformationCache {
916 records: PrimaryMap<TypeRecordIndex, TypeInformation>,
917 variants: PrimaryMap<TypeVariantIndex, TypeInformation>,
918 tuples: PrimaryMap<TypeTupleIndex, TypeInformation>,
919 enums: PrimaryMap<TypeEnumIndex, TypeInformation>,
920 flags: PrimaryMap<TypeFlagsIndex, TypeInformation>,
921 options: PrimaryMap<TypeOptionIndex, TypeInformation>,
922 results: PrimaryMap<TypeResultIndex, TypeInformation>,
923 lists: PrimaryMap<TypeListIndex, TypeInformation>,
924}
925
926struct TypeInformation {
927 depth: u32,
928 flat: FlatTypesStorage,
929 has_borrow: bool,
930}
931
932impl TypeInformation {
933 const fn new() -> TypeInformation {
934 TypeInformation {
935 depth: 0,
936 flat: FlatTypesStorage::new(),
937 has_borrow: false,
938 }
939 }
940
941 const fn primitive(flat: FlatType) -> TypeInformation {
942 let mut info = TypeInformation::new();
943 info.depth = 1;
944 info.flat.memory32[0] = flat;
945 info.flat.memory64[0] = flat;
946 info.flat.len = 1;
947 info
948 }
949
950 const fn string() -> TypeInformation {
951 let mut info = TypeInformation::new();
952 info.depth = 1;
953 info.flat.memory32[0] = FlatType::I32;
954 info.flat.memory32[1] = FlatType::I32;
955 info.flat.memory64[0] = FlatType::I64;
956 info.flat.memory64[1] = FlatType::I64;
957 info.flat.len = 2;
958 info
959 }
960
961 fn build_record<'a>(&mut self, types: impl Iterator<Item = &'a TypeInformation>) {
964 self.depth = 1;
965 for info in types {
966 self.depth = self.depth.max(1 + info.depth);
967 self.has_borrow = self.has_borrow || info.has_borrow;
968 match info.flat.as_flat_types() {
969 Some(types) => {
970 for (t32, t64) in types.memory32.iter().zip(types.memory64) {
971 if !self.flat.push(*t32, *t64) {
972 break;
973 }
974 }
975 }
976 None => {
977 self.flat.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap();
978 }
979 }
980 }
981 }
982
983 fn build_variant<'a, I>(&mut self, cases: I)
995 where
996 I: IntoIterator<Item = Option<&'a TypeInformation>>,
997 {
998 let cases = cases.into_iter();
999 self.flat.push(FlatType::I32, FlatType::I32);
1000 self.depth = 1;
1001
1002 for info in cases {
1003 let info = match info {
1004 Some(info) => info,
1005 None => continue,
1008 };
1009 self.depth = self.depth.max(1 + info.depth);
1010 self.has_borrow = self.has_borrow || info.has_borrow;
1011
1012 if usize::from(self.flat.len) > MAX_FLAT_TYPES {
1015 continue;
1016 }
1017
1018 let types = match info.flat.as_flat_types() {
1019 Some(types) => types,
1020 None => {
1023 self.flat.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap();
1024 continue;
1025 }
1026 };
1027 if types.memory32.len() >= MAX_FLAT_TYPES {
1031 self.flat.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap();
1032 continue;
1033 }
1034 let dst = self
1035 .flat
1036 .memory32
1037 .iter_mut()
1038 .zip(&mut self.flat.memory64)
1039 .skip(1);
1040 for (i, ((t32, t64), (dst32, dst64))) in types
1041 .memory32
1042 .iter()
1043 .zip(types.memory64)
1044 .zip(dst)
1045 .enumerate()
1046 {
1047 if i + 1 < usize::from(self.flat.len) {
1048 dst32.join(*t32);
1051 dst64.join(*t64);
1052 } else {
1053 self.flat.len += 1;
1058 *dst32 = *t32;
1059 *dst64 = *t64;
1060 }
1061 }
1062 }
1063 }
1064
1065 fn records(&mut self, types: &ComponentTypesBuilder, ty: &TypeRecord) {
1066 self.build_record(ty.fields.iter().map(|f| types.type_information(&f.ty)));
1067 }
1068
1069 fn tuples(&mut self, types: &ComponentTypesBuilder, ty: &TypeTuple) {
1070 self.build_record(ty.types.iter().map(|t| types.type_information(t)));
1071 }
1072
1073 fn enums(&mut self, _types: &ComponentTypesBuilder, _ty: &TypeEnum) {
1074 self.depth = 1;
1075 self.flat.push(FlatType::I32, FlatType::I32);
1076 }
1077
1078 fn flags(&mut self, _types: &ComponentTypesBuilder, ty: &TypeFlags) {
1079 self.depth = 1;
1080 match FlagsSize::from_count(ty.names.len()) {
1081 FlagsSize::Size0 => {}
1082 FlagsSize::Size1 | FlagsSize::Size2 => {
1083 self.flat.push(FlatType::I32, FlatType::I32);
1084 }
1085 FlagsSize::Size4Plus(n) => {
1086 for _ in 0..n {
1087 self.flat.push(FlatType::I32, FlatType::I32);
1088 }
1089 }
1090 }
1091 }
1092
1093 fn variants(&mut self, types: &ComponentTypesBuilder, ty: &TypeVariant) {
1094 self.build_variant(
1095 ty.cases
1096 .iter()
1097 .map(|(_, c)| c.as_ref().map(|ty| types.type_information(ty))),
1098 )
1099 }
1100
1101 fn results(&mut self, types: &ComponentTypesBuilder, ty: &TypeResult) {
1102 self.build_variant([
1103 ty.ok.as_ref().map(|ty| types.type_information(ty)),
1104 ty.err.as_ref().map(|ty| types.type_information(ty)),
1105 ])
1106 }
1107
1108 fn options(&mut self, types: &ComponentTypesBuilder, ty: &TypeOption) {
1109 self.build_variant([None, Some(types.type_information(&ty.ty))]);
1110 }
1111
1112 fn lists(&mut self, types: &ComponentTypesBuilder, ty: &TypeList) {
1113 *self = TypeInformation::string();
1114 let info = types.type_information(&ty.element);
1115 self.depth += info.depth;
1116 self.has_borrow = info.has_borrow;
1117 }
1118}