1 use crate::{
2     EngineOrModuleTypeIndex, EntityRef, ModuleInternedRecGroupIndex, ModuleInternedTypeIndex,
3     ModuleTypes, PanicOnOom as _, TypeConvert, TypeIndex, WasmArrayType, WasmCompositeInnerType,
4     WasmCompositeType, WasmExnType, WasmFieldType, WasmFuncType, WasmHeapType, WasmResult,
5     WasmStorageType, WasmStructType, WasmSubType,
6     collections::{TryClone as _, TryCow},
7     wasm_unsupported,
8 };
9 use std::{
10     collections::{HashMap, hash_map::Entry},
11     ops::Index,
12 };
13 use wasmparser::{UnpackedIndex, Validator, ValidatorId};
14 
15 /// A type marking the start of a recursion group's definition.
16 ///
17 /// This is initialized by `ModuleTypesBuilder::start_rec_group` and then
18 /// finished in `ModuleTypes::end_rec_group` after all of the types in the rec
19 /// group have been defined.
20 struct RecGroupStart {
21     rec_group_index: ModuleInternedRecGroupIndex,
22     start: ModuleInternedTypeIndex,
23     end: ModuleInternedTypeIndex,
24 }
25 
26 /// A builder for [`ModuleTypes`].
27 pub struct ModuleTypesBuilder {
28     /// The ID of the validator that this builder is configured for. Using a
29     /// different validator, or multiple validators, with this builder would
30     /// result in silliness because our `wasmparser::types::*Id`s are only
31     /// unique within the context of a particular validator. Getting this wrong
32     /// could result in generating calls to functions of the wrong type, for
33     /// example. So therefore we always assert that a builder instances is only
34     /// ever paired with a particular validator context.
35     validator_id: ValidatorId,
36 
37     /// The canonicalized and deduplicated set of types we are building.
38     types: ModuleTypes,
39 
40     /// The set of trampoline-compatible function types we have already added to
41     /// `self.types`. We do this additional level of deduping, on top of what
42     /// `wasmparser` already does, so we can quickly and easily get the
43     /// trampoline type for a given function type if we've already interned one.
44     trampoline_types: HashMap<WasmFuncType, ModuleInternedTypeIndex>,
45 
46     /// An interning map for exception types corresponding to function
47     /// types used by tags. Tags are nominal, but the underlying
48     /// Wasmtime types describe only the object layout and so are
49     /// structural.
50     exception_types: HashMap<ModuleInternedTypeIndex, ModuleInternedTypeIndex>,
51 
52     /// A map from already-interned `wasmparser` types to their corresponding
53     /// Wasmtime type.
54     wasmparser_to_wasmtime: HashMap<wasmparser::types::CoreTypeId, ModuleInternedTypeIndex>,
55 
56     /// The set of recursion groups we have already seen and interned.
57     already_seen: HashMap<wasmparser::types::RecGroupId, ModuleInternedRecGroupIndex>,
58 
59     /// If we are in the middle of defining a recursion group, this is the
60     /// metadata about the recursion group we started defining.
61     defining_rec_group: Option<RecGroupStart>,
62 }
63 
64 impl ModuleTypesBuilder {
65     /// Construct a new `ModuleTypesBuilder` using the given validator.
new(validator: &Validator) -> Self66     pub fn new(validator: &Validator) -> Self {
67         Self {
68             validator_id: validator.id(),
69             types: ModuleTypes::default(),
70             trampoline_types: HashMap::default(),
71             exception_types: HashMap::default(),
72             wasmparser_to_wasmtime: HashMap::default(),
73             already_seen: HashMap::default(),
74             defining_rec_group: None,
75         }
76     }
77 
78     /// Reserves space for `amt` more type signatures.
reserve_wasm_signatures(&mut self, amt: usize)79     pub fn reserve_wasm_signatures(&mut self, amt: usize) {
80         self.types.reserve(amt);
81         self.wasmparser_to_wasmtime.reserve(amt);
82         self.already_seen.reserve(amt);
83     }
84 
85     /// Get the id of the validator that this builder is configured for.
validator_id(&self) -> ValidatorId86     pub fn validator_id(&self) -> ValidatorId {
87         self.validator_id
88     }
89 
90     /// Intern a recursion group and all of its types into this builder.
91     ///
92     /// If the recursion group has already been interned, then it is reused.
93     ///
94     /// Panics if given types from a different validator than the one that this
95     /// builder is associated with.
intern_rec_group( &mut self, validator_types: wasmparser::types::TypesRef<'_>, rec_group_id: wasmparser::types::RecGroupId, ) -> WasmResult<ModuleInternedRecGroupIndex>96     pub fn intern_rec_group(
97         &mut self,
98         validator_types: wasmparser::types::TypesRef<'_>,
99         rec_group_id: wasmparser::types::RecGroupId,
100     ) -> WasmResult<ModuleInternedRecGroupIndex> {
101         assert_eq!(validator_types.id(), self.validator_id);
102 
103         if let Some(interned) = self.already_seen.get(&rec_group_id) {
104             return Ok(*interned);
105         }
106 
107         self.define_new_rec_group(validator_types, rec_group_id)
108     }
109 
110     /// Define a new recursion group that we haven't already interned.
define_new_rec_group( &mut self, validator_types: wasmparser::types::TypesRef<'_>, rec_group_id: wasmparser::types::RecGroupId, ) -> WasmResult<ModuleInternedRecGroupIndex>111     fn define_new_rec_group(
112         &mut self,
113         validator_types: wasmparser::types::TypesRef<'_>,
114         rec_group_id: wasmparser::types::RecGroupId,
115     ) -> WasmResult<ModuleInternedRecGroupIndex> {
116         assert_eq!(validator_types.id(), self.validator_id);
117 
118         self.start_rec_group(
119             validator_types,
120             validator_types.rec_group_elements(rec_group_id),
121         );
122 
123         for id in validator_types.rec_group_elements(rec_group_id) {
124             let ty = &validator_types[id];
125             let wasm_ty = WasmparserTypeConverter::new(self, |_| {
126                 unreachable!("no need to lookup indexes; we already have core type IDs")
127             })
128             .with_rec_group(validator_types, rec_group_id)
129             .convert_sub_type(ty)?;
130             self.wasm_sub_type_in_rec_group(id, wasm_ty);
131         }
132 
133         let rec_group_index = self.end_rec_group(rec_group_id);
134 
135         // Iterate over all the types we just defined and make sure that every
136         // function type has an associated trampoline type. This needs to happen
137         // *after* we finish defining the rec group because we may need to
138         // intern new function types, which would conflict with the contiguous
139         // range of type indices we pre-reserved for the rec group elements.
140         for ty in self.rec_group_elements(rec_group_index) {
141             if self.types[ty].is_func() {
142                 let trampoline = self.intern_trampoline_type(ty);
143                 self.types.set_trampoline_type(ty, trampoline);
144             }
145         }
146 
147         Ok(rec_group_index)
148     }
149 
150     /// Get or create the trampoline function type for the given function
151     /// type. Returns the interned type index of the trampoline function type.
intern_trampoline_type( &mut self, for_func_ty: ModuleInternedTypeIndex, ) -> ModuleInternedTypeIndex152     fn intern_trampoline_type(
153         &mut self,
154         for_func_ty: ModuleInternedTypeIndex,
155     ) -> ModuleInternedTypeIndex {
156         let sub_ty = &self.types[for_func_ty];
157         let trampoline = sub_ty.unwrap_func().trampoline_type().panic_on_oom();
158 
159         if let Some(idx) = self.trampoline_types.get(&trampoline) {
160             // We've already interned this trampoline type; reuse it.
161             *idx
162         } else {
163             // We have not already interned this trampoline type.
164             match trampoline {
165                 // The trampoline type is the same as the original function
166                 // type. We can reuse the definition and its index, but still
167                 // need to intern the type into our `trampoline_types` map so we
168                 // can reuse it in the future.
169                 TryCow::Borrowed(f) => {
170                     self.trampoline_types
171                         .insert(f.clone_panic_on_oom(), for_func_ty);
172                     for_func_ty
173                 }
174                 // The trampoline type is different from the original function
175                 // type. Define the trampoline type and then intern it in
176                 // `trampoline_types` so we can reuse it in the future.
177                 TryCow::Owned(f) => {
178                     let idx = self.types.push(WasmSubType {
179                         is_final: true,
180                         supertype: None,
181                         composite_type: WasmCompositeType {
182                             inner: WasmCompositeInnerType::Func(f.clone_panic_on_oom()),
183                             shared: sub_ty.composite_type.shared,
184                         },
185                     });
186 
187                     // The trampoline type is its own trampoline type.
188                     self.types.set_trampoline_type(idx, idx);
189 
190                     let next = self.types.next_ty();
191                     self.types.push_rec_group(idx..next);
192                     self.trampoline_types.insert(f, idx);
193                     idx
194                 }
195             }
196         }
197     }
198 
199     /// Start defining a recursion group.
start_rec_group( &mut self, validator_types: wasmparser::types::TypesRef<'_>, elems: impl ExactSizeIterator<Item = wasmparser::types::CoreTypeId>, )200     fn start_rec_group(
201         &mut self,
202         validator_types: wasmparser::types::TypesRef<'_>,
203         elems: impl ExactSizeIterator<Item = wasmparser::types::CoreTypeId>,
204     ) {
205         log::trace!("Starting rec group of length {}", elems.len());
206 
207         assert!(self.defining_rec_group.is_none());
208         assert_eq!(validator_types.id(), self.validator_id);
209 
210         // Eagerly define the reverse map's entries for this rec group's types
211         // so that we can use them when converting `wasmparser` types to our
212         // types.
213         let len = elems.len();
214         for (i, wasmparser_id) in elems.enumerate() {
215             let interned = ModuleInternedTypeIndex::new(self.types.len_types() + i);
216             log::trace!(
217                 "Reserving {interned:?} for {wasmparser_id:?} = {:?}",
218                 validator_types[wasmparser_id]
219             );
220 
221             let old_entry = self.wasmparser_to_wasmtime.insert(wasmparser_id, interned);
222             debug_assert_eq!(
223                 old_entry, None,
224                 "should not have already inserted {wasmparser_id:?}"
225             );
226         }
227 
228         self.defining_rec_group = Some(RecGroupStart {
229             rec_group_index: self.types.next_rec_group(),
230             start: self.types.next_ty(),
231             end: ModuleInternedTypeIndex::new(self.types.len_types() + len),
232         });
233     }
234 
235     /// Finish defining a recursion group.
end_rec_group( &mut self, rec_group_id: wasmparser::types::RecGroupId, ) -> ModuleInternedRecGroupIndex236     fn end_rec_group(
237         &mut self,
238         rec_group_id: wasmparser::types::RecGroupId,
239     ) -> ModuleInternedRecGroupIndex {
240         let RecGroupStart {
241             rec_group_index,
242             start,
243             end,
244         } = self
245             .defining_rec_group
246             .take()
247             .expect("should be defining a rec group");
248 
249         log::trace!("Ending rec group {start:?}..{end:?}");
250 
251         debug_assert!(start.index() < self.types.len_types());
252         debug_assert_eq!(
253             end,
254             self.types.next_ty(),
255             "should have defined the number of types declared in `start_rec_group`"
256         );
257 
258         let idx = self.types.push_rec_group(start..end);
259         debug_assert_eq!(idx, rec_group_index);
260 
261         self.already_seen.insert(rec_group_id, rec_group_index);
262         rec_group_index
263     }
264 
265     /// Intern a type into this builder and get its Wasmtime index.
266     ///
267     /// This will intern not only the single given type, but the type's entire
268     /// rec group. This helper method is provided as a convenience so that
269     /// callers don't have to get the type's rec group, intern the rec group,
270     /// and then look up the Wasmtime index for the original type themselves.
intern_type( &mut self, validator_types: wasmparser::types::TypesRef<'_>, id: wasmparser::types::CoreTypeId, ) -> WasmResult<ModuleInternedTypeIndex>271     pub fn intern_type(
272         &mut self,
273         validator_types: wasmparser::types::TypesRef<'_>,
274         id: wasmparser::types::CoreTypeId,
275     ) -> WasmResult<ModuleInternedTypeIndex> {
276         assert!(self.defining_rec_group.is_none());
277         assert_eq!(validator_types.id(), self.validator_id);
278 
279         let rec_group_id = validator_types.rec_group_id_of(id);
280         debug_assert!(
281             validator_types
282                 .rec_group_elements(rec_group_id)
283                 .any(|e| e == id)
284         );
285 
286         let interned_rec_group = self.intern_rec_group(validator_types, rec_group_id)?;
287 
288         let interned_type = self.wasmparser_to_wasmtime[&id];
289         debug_assert!(
290             self.rec_group_elements(interned_rec_group)
291                 .any(|e| e == interned_type)
292         );
293 
294         Ok(interned_type)
295     }
296 
297     /// Define a new Wasm type while we are defining a rec group.
wasm_sub_type_in_rec_group( &mut self, id: wasmparser::types::CoreTypeId, ty: WasmSubType, ) -> ModuleInternedTypeIndex298     fn wasm_sub_type_in_rec_group(
299         &mut self,
300         id: wasmparser::types::CoreTypeId,
301         ty: WasmSubType,
302     ) -> ModuleInternedTypeIndex {
303         assert!(
304             self.defining_rec_group.is_some(),
305             "must be defining a rec group to define new types"
306         );
307 
308         let module_interned_index = self.types.push(ty);
309         debug_assert_eq!(
310             self.wasmparser_to_wasmtime.get(&id),
311             Some(&module_interned_index),
312             "should have reserved the right module-interned index for this wasmparser type already"
313         );
314 
315         module_interned_index
316     }
317 
318     /// Define a new exception type when we see a function type used
319     /// in a tag.
320     ///
321     /// The returned `ModuleInternedTypeIndex` gives us a Wasmtime
322     /// type which corresponds to the exception object layout, but
323     /// note that these types do not exist in the Wasm spec: at the
324     /// Wasm level, only function types exist (and tags and exception
325     /// instructions reference them). For implementation reasons, we
326     /// need a separate type to describe the exception object layout,
327     /// and this registers and provides that type.
define_exception_type_for_tag( &mut self, for_func_ty: ModuleInternedTypeIndex, ) -> ModuleInternedTypeIndex328     pub fn define_exception_type_for_tag(
329         &mut self,
330         for_func_ty: ModuleInternedTypeIndex,
331     ) -> ModuleInternedTypeIndex {
332         match self.exception_types.entry(for_func_ty) {
333             Entry::Occupied(o) => *o.get(),
334             Entry::Vacant(v) => {
335                 let fields = self.types[for_func_ty]
336                     .unwrap_func()
337                     .params()
338                     .iter()
339                     .map(|valtype| WasmFieldType {
340                         element_type: WasmStorageType::Val(*valtype),
341                         mutable: false,
342                     })
343                     .collect();
344                 let idx = self.types.push(WasmSubType {
345                     is_final: true,
346                     supertype: None,
347                     composite_type: WasmCompositeType {
348                         inner: WasmCompositeInnerType::Exn(WasmExnType {
349                             func_ty: EngineOrModuleTypeIndex::Module(for_func_ty),
350                             fields,
351                         }),
352                         shared: false,
353                     },
354                 });
355                 let next = self.types.next_ty();
356                 self.types.push_rec_group(idx..next);
357                 *v.insert(idx)
358             }
359         }
360     }
361 
362     /// Returns the result [`ModuleTypes`] of this builder.
finish(self) -> ModuleTypes363     pub fn finish(self) -> ModuleTypes {
364         self.types
365     }
366 
367     /// Get the elements within an already-defined rec group.
rec_group_elements( &self, rec_group: ModuleInternedRecGroupIndex, ) -> impl ExactSizeIterator<Item = ModuleInternedTypeIndex> + use<>368     pub fn rec_group_elements(
369         &self,
370         rec_group: ModuleInternedRecGroupIndex,
371     ) -> impl ExactSizeIterator<Item = ModuleInternedTypeIndex> + use<> {
372         self.types.rec_group_elements(rec_group)
373     }
374 
375     /// Returns an iterator over all the unique wasm types defined thus far
376     /// within this builder.
wasm_types(&self) -> impl Iterator<Item = (ModuleInternedTypeIndex, &WasmSubType)>377     pub fn wasm_types(&self) -> impl Iterator<Item = (ModuleInternedTypeIndex, &WasmSubType)> {
378         self.types.wasm_types()
379     }
380 
381     /// Get an iterator over all function types and their associated trampoline
382     /// type.
trampoline_types( &self, ) -> impl Iterator<Item = (ModuleInternedTypeIndex, ModuleInternedTypeIndex)> + '_383     pub fn trampoline_types(
384         &self,
385     ) -> impl Iterator<Item = (ModuleInternedTypeIndex, ModuleInternedTypeIndex)> + '_ {
386         self.types.trampoline_types()
387     }
388 
389     /// Get the associated trampoline type for the given function type.
trampoline_type(&self, ty: ModuleInternedTypeIndex) -> ModuleInternedTypeIndex390     pub fn trampoline_type(&self, ty: ModuleInternedTypeIndex) -> ModuleInternedTypeIndex {
391         self.types.trampoline_type(ty)
392     }
393 
394     /// Get and unwrap a [`WasmStructType`] for the given struct index.
395     ///
396     /// # Panics
397     ///
398     /// Panics if the unwrapped type is not a struct.
399     ///
400     /// # Errors
401     ///
402     /// For now, fails with an unsupported error if the type is shared.
unwrap_struct(&self, ty: ModuleInternedTypeIndex) -> WasmResult<&WasmStructType>403     pub fn unwrap_struct(&self, ty: ModuleInternedTypeIndex) -> WasmResult<&WasmStructType> {
404         let composite_type = &self.types[ty].composite_type;
405         if composite_type.shared {
406             return Err(wasm_unsupported!("shared structs are not yet implemented"));
407         }
408         Ok(composite_type.inner.unwrap_struct())
409     }
410 
411     /// Get and unwrap a [`WasmArrayType`] for the given array index.
412     ///
413     /// # Panics
414     ///
415     /// Panics if the unwrapped type is not an array.
416     ///
417     /// # Errors
418     ///
419     /// For now, fails with an unsupported error if the type is shared.
unwrap_array(&self, interned_ty: ModuleInternedTypeIndex) -> WasmResult<&WasmArrayType>420     pub fn unwrap_array(&self, interned_ty: ModuleInternedTypeIndex) -> WasmResult<&WasmArrayType> {
421         let composite_type = &self.types[interned_ty].composite_type;
422         if composite_type.shared {
423             return Err(wasm_unsupported!("shared arrays are not yet implemented"));
424         }
425         Ok(composite_type.inner.unwrap_array())
426     }
427 
428     /// Get and unwrap a [`WasmExnType`] for the given exception-type index.
429     ///
430     /// # Panics
431     ///
432     /// Panics if the unwrapped type is not an exception type.
433     ///
434     /// # Errors
435     ///
436     /// For now, fails with an unsupported error if the type is shared.
unwrap_exn(&self, interned_ty: ModuleInternedTypeIndex) -> WasmResult<&WasmExnType>437     pub fn unwrap_exn(&self, interned_ty: ModuleInternedTypeIndex) -> WasmResult<&WasmExnType> {
438         let composite_type = &self.types[interned_ty].composite_type;
439         if composite_type.shared {
440             return Err(wasm_unsupported!(
441                 "shared exceptions are not yet implemented"
442             ));
443         }
444         Ok(composite_type.inner.unwrap_exn())
445     }
446 
447     /// Get and unwrap a [`WasmFuncType`] for the given function-type index.
448     ///
449     /// # Panics
450     ///
451     /// Panics if the unwrapped type is not a function type.
452     ///
453     /// # Errors
454     ///
455     /// For now, fails with an unsupported error if the type is shared.
unwrap_func(&self, interned_ty: ModuleInternedTypeIndex) -> WasmResult<&WasmFuncType>456     pub fn unwrap_func(&self, interned_ty: ModuleInternedTypeIndex) -> WasmResult<&WasmFuncType> {
457         let composite_type = &self.types[interned_ty].composite_type;
458         if composite_type.shared {
459             return Err(wasm_unsupported!(
460                 "shared functions are not yet implemented"
461             ));
462         }
463         Ok(composite_type.inner.unwrap_func())
464     }
465 }
466 
467 // Forward the indexing impl to the internal `ModuleTypes`
468 impl<T> Index<T> for ModuleTypesBuilder
469 where
470     ModuleTypes: Index<T>,
471 {
472     type Output = <ModuleTypes as Index<T>>::Output;
473 
index(&self, sig: T) -> &Self::Output474     fn index(&self, sig: T) -> &Self::Output {
475         &self.types[sig]
476     }
477 }
478 
479 /// A convert from `wasmparser` types to Wasmtime types.
480 pub struct WasmparserTypeConverter<'a, F> {
481     types: &'a ModuleTypesBuilder,
482     lookup_type_idx: F,
483     rec_group_context: Option<(
484         wasmparser::types::TypesRef<'a>,
485         wasmparser::types::RecGroupId,
486     )>,
487 }
488 
489 impl<'a, F> WasmparserTypeConverter<'a, F> {
490     /// Construct a new type converter from `wasmparser` types to Wasmtime types.
new(types: &'a ModuleTypesBuilder, lookup_type_idx: F) -> Self491     pub fn new(types: &'a ModuleTypesBuilder, lookup_type_idx: F) -> Self {
492         Self {
493             types,
494             lookup_type_idx,
495             rec_group_context: None,
496         }
497     }
498 
499     /// Configure this converter to be within the context of defining the
500     /// current rec group.
with_rec_group( &mut self, wasmparser_types: wasmparser::types::TypesRef<'a>, rec_group: wasmparser::types::RecGroupId, ) -> &Self501     pub fn with_rec_group(
502         &mut self,
503         wasmparser_types: wasmparser::types::TypesRef<'a>,
504         rec_group: wasmparser::types::RecGroupId,
505     ) -> &Self {
506         self.rec_group_context = Some((wasmparser_types, rec_group));
507         self
508     }
509 }
510 
511 impl<F> TypeConvert for WasmparserTypeConverter<'_, F>
512 where
513     F: Fn(TypeIndex) -> ModuleInternedTypeIndex,
514 {
lookup_heap_type(&self, index: UnpackedIndex) -> WasmHeapType515     fn lookup_heap_type(&self, index: UnpackedIndex) -> WasmHeapType {
516         match index {
517             UnpackedIndex::Id(id) => {
518                 let interned = self.types.wasmparser_to_wasmtime[&id];
519                 let index = EngineOrModuleTypeIndex::Module(interned);
520 
521                 // If this is a forward reference to a type in this type's rec
522                 // group that we haven't converted yet, then we won't have an
523                 // entry in `wasm_types` yet. In this case, fallback to a
524                 // different means of determining whether this is a concrete
525                 // array vs struct vs func reference. In this case, we can use
526                 // the validator's type context.
527                 if let Some(ty) = self.types.types.get(interned) {
528                     assert!(!ty.composite_type.shared);
529                     match &ty.composite_type.inner {
530                         WasmCompositeInnerType::Array(_) => WasmHeapType::ConcreteArray(index),
531                         WasmCompositeInnerType::Func(_) => WasmHeapType::ConcreteFunc(index),
532                         WasmCompositeInnerType::Struct(_) => WasmHeapType::ConcreteStruct(index),
533                         WasmCompositeInnerType::Cont(_) => WasmHeapType::ConcreteCont(index),
534                         WasmCompositeInnerType::Exn(_) => WasmHeapType::ConcreteExn(index),
535                     }
536                 } else if let Some((wasmparser_types, _)) = self.rec_group_context.as_ref() {
537                     let wasmparser_ty = &wasmparser_types[id].composite_type;
538                     assert!(!wasmparser_ty.shared);
539                     match &wasmparser_ty.inner {
540                         wasmparser::CompositeInnerType::Array(_) => {
541                             WasmHeapType::ConcreteArray(index)
542                         }
543                         wasmparser::CompositeInnerType::Func(_) => {
544                             WasmHeapType::ConcreteFunc(index)
545                         }
546                         wasmparser::CompositeInnerType::Struct(_) => {
547                             WasmHeapType::ConcreteStruct(index)
548                         }
549                         wasmparser::CompositeInnerType::Cont(_) => {
550                             WasmHeapType::ConcreteCont(index)
551                         }
552                     }
553                 } else {
554                     panic!("forward reference to type outside of rec group?")
555                 }
556             }
557 
558             UnpackedIndex::Module(module_index) => {
559                 let module_index = TypeIndex::from_u32(module_index);
560                 let interned = (self.lookup_type_idx)(module_index);
561                 let index = EngineOrModuleTypeIndex::Module(interned);
562 
563                 // See comment above about `wasm_types` maybe not having the
564                 // converted sub type yet. However in this case we don't have a
565                 // `wasmparser::types::CoreTypeId` on hand, so we have to
566                 // indirectly get one by looking it up inside the current rec
567                 // group.
568                 if let Some(ty) = self.types.types.get(interned) {
569                     assert!(!ty.composite_type.shared);
570                     match &ty.composite_type.inner {
571                         WasmCompositeInnerType::Array(_) => WasmHeapType::ConcreteArray(index),
572                         WasmCompositeInnerType::Func(_) => WasmHeapType::ConcreteFunc(index),
573                         WasmCompositeInnerType::Struct(_) => WasmHeapType::ConcreteStruct(index),
574                         WasmCompositeInnerType::Cont(_) => WasmHeapType::ConcreteCont(index),
575                         WasmCompositeInnerType::Exn(_) => WasmHeapType::ConcreteExn(index),
576                     }
577                 } else if let Some((parser_types, rec_group)) = self.rec_group_context.as_ref() {
578                     let rec_group_index = interned.index() - self.types.types.len_types();
579                     let id = parser_types
580                         .rec_group_elements(*rec_group)
581                         .nth(rec_group_index)
582                         .unwrap();
583                     let wasmparser_ty = &parser_types[id].composite_type;
584                     assert!(!wasmparser_ty.shared);
585                     match &wasmparser_ty.inner {
586                         wasmparser::CompositeInnerType::Array(_) => {
587                             WasmHeapType::ConcreteArray(index)
588                         }
589                         wasmparser::CompositeInnerType::Func(_) => {
590                             WasmHeapType::ConcreteFunc(index)
591                         }
592                         wasmparser::CompositeInnerType::Struct(_) => {
593                             WasmHeapType::ConcreteStruct(index)
594                         }
595                         wasmparser::CompositeInnerType::Cont(_) => {
596                             WasmHeapType::ConcreteCont(index)
597                         }
598                     }
599                 } else {
600                     panic!("forward reference to type outside of rec group?")
601                 }
602             }
603 
604             UnpackedIndex::RecGroup(_) => unreachable!(),
605         }
606     }
607 
lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex608     fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex {
609         match index {
610             UnpackedIndex::Id(id) => {
611                 let interned = self.types.wasmparser_to_wasmtime[&id];
612                 EngineOrModuleTypeIndex::Module(interned)
613             }
614             UnpackedIndex::Module(module_index) => {
615                 let module_index = TypeIndex::from_u32(module_index);
616                 let interned = (self.lookup_type_idx)(module_index);
617                 EngineOrModuleTypeIndex::Module(interned)
618             }
619             UnpackedIndex::RecGroup(_) => unreachable!(),
620         }
621     }
622 }
623