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