1use 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, WasmValType,
6 collections::{TryClone as _, TryCow},
7 wasm_unsupported,
8};
9use std::{
10 collections::{HashMap, hash_map::Entry},
11 ops::Index,
12};
13use wasmparser::{UnpackedIndex, Validator, ValidatorId};
14
15struct RecGroupStart {
21 rec_group_index: ModuleInternedRecGroupIndex,
22 start: ModuleInternedTypeIndex,
23 end: ModuleInternedTypeIndex,
24}
25
26pub struct ModuleTypesBuilder {
28 validator_id: ValidatorId,
36
37 types: ModuleTypes,
39
40 trampoline_types: HashMap<WasmFuncType, ModuleInternedTypeIndex>,
45
46 exception_types: HashMap<ModuleInternedTypeIndex, ModuleInternedTypeIndex>,
51
52 wasmparser_to_wasmtime: HashMap<wasmparser::types::CoreTypeId, ModuleInternedTypeIndex>,
55
56 already_seen: HashMap<wasmparser::types::RecGroupId, ModuleInternedRecGroupIndex>,
58
59 defining_rec_group: Option<RecGroupStart>,
62
63 startup_func_type: Option<ModuleInternedTypeIndex>,
65}
66
67impl ModuleTypesBuilder {
68 pub fn new(validator: &Validator) -> Self {
70 Self {
71 validator_id: validator.id(),
72 types: ModuleTypes::default(),
73 trampoline_types: HashMap::default(),
74 exception_types: HashMap::default(),
75 wasmparser_to_wasmtime: HashMap::default(),
76 already_seen: HashMap::default(),
77 defining_rec_group: None,
78 startup_func_type: None,
79 }
80 }
81
82 pub fn reserve_wasm_signatures(&mut self, amt: usize) {
84 self.types.reserve(amt);
85 self.wasmparser_to_wasmtime.reserve(amt);
86 self.already_seen.reserve(amt);
87 }
88
89 pub fn validator_id(&self) -> ValidatorId {
91 self.validator_id
92 }
93
94 pub fn intern_rec_group(
101 &mut self,
102 validator_types: wasmparser::types::TypesRef<'_>,
103 rec_group_id: wasmparser::types::RecGroupId,
104 ) -> WasmResult<ModuleInternedRecGroupIndex> {
105 assert_eq!(validator_types.id(), self.validator_id);
106
107 if let Some(interned) = self.already_seen.get(&rec_group_id) {
108 return Ok(*interned);
109 }
110
111 self.define_new_rec_group(validator_types, rec_group_id)
112 }
113
114 fn define_new_rec_group(
116 &mut self,
117 validator_types: wasmparser::types::TypesRef<'_>,
118 rec_group_id: wasmparser::types::RecGroupId,
119 ) -> WasmResult<ModuleInternedRecGroupIndex> {
120 assert_eq!(validator_types.id(), self.validator_id);
121
122 self.start_rec_group(
123 validator_types,
124 validator_types.rec_group_elements(rec_group_id),
125 );
126
127 for id in validator_types.rec_group_elements(rec_group_id) {
128 let ty = &validator_types[id];
129 let wasm_ty = WasmparserTypeConverter::new(self, |_| {
130 unreachable!("no need to lookup indexes; we already have core type IDs")
131 })
132 .with_rec_group(validator_types, rec_group_id)
133 .convert_sub_type(ty)?;
134 self.wasm_sub_type_in_rec_group(id, wasm_ty);
135 }
136
137 let rec_group_index = self.end_rec_group(rec_group_id);
138
139 for ty in self.rec_group_elements(rec_group_index) {
145 if self.types[ty].is_func() {
146 let trampoline = self.intern_trampoline_type(ty);
147 self.types.set_trampoline_type(ty, trampoline);
148 }
149 }
150
151 Ok(rec_group_index)
152 }
153
154 fn intern_trampoline_type(
157 &mut self,
158 for_func_ty: ModuleInternedTypeIndex,
159 ) -> ModuleInternedTypeIndex {
160 let sub_ty = &self.types[for_func_ty];
161 let trampoline = sub_ty.unwrap_func().trampoline_type().panic_on_oom();
162
163 if let Some(idx) = self.trampoline_types.get(&trampoline) {
164 *idx
166 } else {
167 match trampoline {
169 TryCow::Borrowed(f) => {
174 self.trampoline_types
175 .insert(f.clone_panic_on_oom(), for_func_ty);
176 for_func_ty
177 }
178 TryCow::Owned(f) => {
182 let idx = self.types.push(WasmSubType {
183 is_final: true,
184 supertype: None,
185 composite_type: WasmCompositeType {
186 inner: WasmCompositeInnerType::Func(f.clone_panic_on_oom()),
187 shared: sub_ty.composite_type.shared,
188 },
189 });
190
191 self.types.set_trampoline_type(idx, idx);
193
194 let next = self.types.next_ty();
195 self.types.push_rec_group(idx..next);
196 self.trampoline_types.insert(f, idx);
197 idx
198 }
199 }
200 }
201 }
202
203 fn start_rec_group(
205 &mut self,
206 validator_types: wasmparser::types::TypesRef<'_>,
207 elems: impl ExactSizeIterator<Item = wasmparser::types::CoreTypeId>,
208 ) {
209 log::trace!("Starting rec group of length {}", elems.len());
210
211 assert!(self.defining_rec_group.is_none());
212 assert_eq!(validator_types.id(), self.validator_id);
213
214 let len = elems.len();
218 for (i, wasmparser_id) in elems.enumerate() {
219 let interned = ModuleInternedTypeIndex::new(self.types.len_types() + i);
220 log::trace!(
221 "Reserving {interned:?} for {wasmparser_id:?} = {:?}",
222 validator_types[wasmparser_id]
223 );
224
225 let old_entry = self.wasmparser_to_wasmtime.insert(wasmparser_id, interned);
226 debug_assert_eq!(
227 old_entry, None,
228 "should not have already inserted {wasmparser_id:?}"
229 );
230 }
231
232 self.defining_rec_group = Some(RecGroupStart {
233 rec_group_index: self.types.next_rec_group(),
234 start: self.types.next_ty(),
235 end: ModuleInternedTypeIndex::new(self.types.len_types() + len),
236 });
237 }
238
239 fn end_rec_group(
241 &mut self,
242 rec_group_id: wasmparser::types::RecGroupId,
243 ) -> ModuleInternedRecGroupIndex {
244 let RecGroupStart {
245 rec_group_index,
246 start,
247 end,
248 } = self
249 .defining_rec_group
250 .take()
251 .expect("should be defining a rec group");
252
253 log::trace!("Ending rec group {start:?}..{end:?}");
254
255 debug_assert!(start.index() < self.types.len_types());
256 debug_assert_eq!(
257 end,
258 self.types.next_ty(),
259 "should have defined the number of types declared in `start_rec_group`"
260 );
261
262 let idx = self.types.push_rec_group(start..end);
263 debug_assert_eq!(idx, rec_group_index);
264
265 self.already_seen.insert(rec_group_id, rec_group_index);
266 rec_group_index
267 }
268
269 pub fn intern_type(
276 &mut self,
277 validator_types: wasmparser::types::TypesRef<'_>,
278 id: wasmparser::types::CoreTypeId,
279 ) -> WasmResult<ModuleInternedTypeIndex> {
280 assert!(self.defining_rec_group.is_none());
281 assert_eq!(validator_types.id(), self.validator_id);
282
283 let rec_group_id = validator_types.rec_group_id_of(id);
284 debug_assert!(
285 validator_types
286 .rec_group_elements(rec_group_id)
287 .any(|e| e == id)
288 );
289
290 let interned_rec_group = self.intern_rec_group(validator_types, rec_group_id)?;
291
292 let interned_type = self.wasmparser_to_wasmtime[&id];
293 debug_assert!(
294 self.rec_group_elements(interned_rec_group)
295 .any(|e| e == interned_type)
296 );
297
298 Ok(interned_type)
299 }
300
301 fn wasm_sub_type_in_rec_group(
303 &mut self,
304 id: wasmparser::types::CoreTypeId,
305 ty: WasmSubType,
306 ) -> ModuleInternedTypeIndex {
307 assert!(
308 self.defining_rec_group.is_some(),
309 "must be defining a rec group to define new types"
310 );
311
312 let module_interned_index = self.types.push(ty);
313 debug_assert_eq!(
314 self.wasmparser_to_wasmtime.get(&id),
315 Some(&module_interned_index),
316 "should have reserved the right module-interned index for this wasmparser type already"
317 );
318
319 module_interned_index
320 }
321
322 pub fn define_exception_type_for_tag(
333 &mut self,
334 for_func_ty: ModuleInternedTypeIndex,
335 ) -> ModuleInternedTypeIndex {
336 match self.exception_types.entry(for_func_ty) {
337 Entry::Occupied(o) => *o.get(),
338 Entry::Vacant(v) => {
339 let fields = self.types[for_func_ty]
340 .unwrap_func()
341 .params()
342 .iter()
343 .map(|valtype| WasmFieldType {
344 element_type: WasmStorageType::Val(*valtype),
345 mutable: false,
346 })
347 .collect();
348 let idx = self.types.push(WasmSubType {
349 is_final: true,
350 supertype: None,
351 composite_type: WasmCompositeType {
352 inner: WasmCompositeInnerType::Exn(WasmExnType {
353 func_ty: EngineOrModuleTypeIndex::Module(for_func_ty),
354 fields,
355 }),
356 shared: false,
357 },
358 });
359 let next = self.types.next_ty();
360 self.types.push_rec_group(idx..next);
361 *v.insert(idx)
362 }
363 }
364 }
365
366 pub fn finish(self) -> ModuleTypes {
368 self.types
369 }
370
371 pub fn rec_group_elements(
373 &self,
374 rec_group: ModuleInternedRecGroupIndex,
375 ) -> impl ExactSizeIterator<Item = ModuleInternedTypeIndex> + use<> {
376 self.types.rec_group_elements(rec_group)
377 }
378
379 pub fn wasm_types(&self) -> impl Iterator<Item = (ModuleInternedTypeIndex, &WasmSubType)> {
382 self.types.wasm_types()
383 }
384
385 pub fn trampoline_types(
388 &self,
389 ) -> impl Iterator<Item = (ModuleInternedTypeIndex, ModuleInternedTypeIndex)> + '_ {
390 self.types.trampoline_types()
391 }
392
393 pub fn trampoline_type(&self, ty: ModuleInternedTypeIndex) -> ModuleInternedTypeIndex {
395 self.types.trampoline_type(ty)
396 }
397
398 pub fn unwrap_struct(&self, ty: ModuleInternedTypeIndex) -> WasmResult<&WasmStructType> {
408 let composite_type = &self.types[ty].composite_type;
409 if composite_type.shared {
410 return Err(wasm_unsupported!("shared structs are not yet implemented"));
411 }
412 Ok(composite_type.inner.unwrap_struct())
413 }
414
415 pub fn unwrap_array(&self, interned_ty: ModuleInternedTypeIndex) -> WasmResult<&WasmArrayType> {
425 let composite_type = &self.types[interned_ty].composite_type;
426 if composite_type.shared {
427 return Err(wasm_unsupported!("shared arrays are not yet implemented"));
428 }
429 Ok(composite_type.inner.unwrap_array())
430 }
431
432 pub fn unwrap_exn(&self, interned_ty: ModuleInternedTypeIndex) -> WasmResult<&WasmExnType> {
442 let composite_type = &self.types[interned_ty].composite_type;
443 if composite_type.shared {
444 return Err(wasm_unsupported!(
445 "shared exceptions are not yet implemented"
446 ));
447 }
448 Ok(composite_type.inner.unwrap_exn())
449 }
450
451 pub fn unwrap_func(&self, interned_ty: ModuleInternedTypeIndex) -> WasmResult<&WasmFuncType> {
461 let composite_type = &self.types[interned_ty].composite_type;
462 if composite_type.shared {
463 return Err(wasm_unsupported!(
464 "shared functions are not yet implemented"
465 ));
466 }
467 Ok(composite_type.inner.unwrap_func())
468 }
469
470 pub fn startup_func_type(&mut self) -> ModuleInternedTypeIndex {
473 *self.startup_func_type.get_or_insert_with(|| {
474 let idx = self.types.push(WasmSubType {
475 is_final: true,
476 supertype: None,
477 composite_type: WasmCompositeType {
478 inner: WasmCompositeInnerType::Func(WasmFuncType::new([], []).panic_on_oom()),
479 shared: false,
480 },
481 });
482 let next = self.types.next_ty();
483 self.types.push_rec_group(idx..next);
484 idx
485 })
486 }
487
488 pub fn find_resource_drop_signature(&self) -> Option<ModuleInternedTypeIndex> {
498 self.wasm_types()
499 .find(|(_, ty)| {
500 ty.as_func().map_or(false, |sig| {
501 sig.params().len() == 1
502 && sig.results().len() == 0
503 && sig.params()[0] == WasmValType::I32
504 })
505 })
506 .map(|(i, _)| i)
507 }
508}
509
510impl<T> Index<T> for ModuleTypesBuilder
512where
513 ModuleTypes: Index<T>,
514{
515 type Output = <ModuleTypes as Index<T>>::Output;
516
517 fn index(&self, sig: T) -> &Self::Output {
518 &self.types[sig]
519 }
520}
521
522pub struct WasmparserTypeConverter<'a, F> {
524 types: &'a ModuleTypesBuilder,
525 lookup_type_idx: F,
526 rec_group_context: Option<(
527 wasmparser::types::TypesRef<'a>,
528 wasmparser::types::RecGroupId,
529 )>,
530}
531
532impl<'a, F> WasmparserTypeConverter<'a, F> {
533 pub fn new(types: &'a ModuleTypesBuilder, lookup_type_idx: F) -> Self {
535 Self {
536 types,
537 lookup_type_idx,
538 rec_group_context: None,
539 }
540 }
541
542 pub fn with_rec_group(
545 &mut self,
546 wasmparser_types: wasmparser::types::TypesRef<'a>,
547 rec_group: wasmparser::types::RecGroupId,
548 ) -> &Self {
549 self.rec_group_context = Some((wasmparser_types, rec_group));
550 self
551 }
552}
553
554impl<F> TypeConvert for WasmparserTypeConverter<'_, F>
555where
556 F: Fn(TypeIndex) -> ModuleInternedTypeIndex,
557{
558 fn lookup_heap_type(&self, index: UnpackedIndex) -> WasmHeapType {
559 match index {
560 UnpackedIndex::Id(id) => {
561 let interned = self.types.wasmparser_to_wasmtime[&id];
562 let index = EngineOrModuleTypeIndex::Module(interned);
563
564 if let Some(ty) = self.types.types.get(interned) {
571 assert!(!ty.composite_type.shared);
572 match &ty.composite_type.inner {
573 WasmCompositeInnerType::Array(_) => WasmHeapType::ConcreteArray(index),
574 WasmCompositeInnerType::Func(_) => WasmHeapType::ConcreteFunc(index),
575 WasmCompositeInnerType::Struct(_) => WasmHeapType::ConcreteStruct(index),
576 WasmCompositeInnerType::Cont(_) => WasmHeapType::ConcreteCont(index),
577 WasmCompositeInnerType::Exn(_) => WasmHeapType::ConcreteExn(index),
578 }
579 } else if let Some((wasmparser_types, _)) = self.rec_group_context.as_ref() {
580 let wasmparser_ty = &wasmparser_types[id].composite_type;
581 assert!(!wasmparser_ty.shared);
582 match &wasmparser_ty.inner {
583 wasmparser::CompositeInnerType::Array(_) => {
584 WasmHeapType::ConcreteArray(index)
585 }
586 wasmparser::CompositeInnerType::Func(_) => {
587 WasmHeapType::ConcreteFunc(index)
588 }
589 wasmparser::CompositeInnerType::Struct(_) => {
590 WasmHeapType::ConcreteStruct(index)
591 }
592 wasmparser::CompositeInnerType::Cont(_) => {
593 WasmHeapType::ConcreteCont(index)
594 }
595 }
596 } else {
597 panic!("forward reference to type outside of rec group?")
598 }
599 }
600
601 UnpackedIndex::Module(module_index) => {
602 let module_index = TypeIndex::from_u32(module_index);
603 let interned = (self.lookup_type_idx)(module_index);
604 let index = EngineOrModuleTypeIndex::Module(interned);
605
606 if let Some(ty) = self.types.types.get(interned) {
612 assert!(!ty.composite_type.shared);
613 match &ty.composite_type.inner {
614 WasmCompositeInnerType::Array(_) => WasmHeapType::ConcreteArray(index),
615 WasmCompositeInnerType::Func(_) => WasmHeapType::ConcreteFunc(index),
616 WasmCompositeInnerType::Struct(_) => WasmHeapType::ConcreteStruct(index),
617 WasmCompositeInnerType::Cont(_) => WasmHeapType::ConcreteCont(index),
618 WasmCompositeInnerType::Exn(_) => WasmHeapType::ConcreteExn(index),
619 }
620 } else if let Some((parser_types, rec_group)) = self.rec_group_context.as_ref() {
621 let rec_group_index = interned.index() - self.types.types.len_types();
622 let id = parser_types
623 .rec_group_elements(*rec_group)
624 .nth(rec_group_index)
625 .unwrap();
626 let wasmparser_ty = &parser_types[id].composite_type;
627 assert!(!wasmparser_ty.shared);
628 match &wasmparser_ty.inner {
629 wasmparser::CompositeInnerType::Array(_) => {
630 WasmHeapType::ConcreteArray(index)
631 }
632 wasmparser::CompositeInnerType::Func(_) => {
633 WasmHeapType::ConcreteFunc(index)
634 }
635 wasmparser::CompositeInnerType::Struct(_) => {
636 WasmHeapType::ConcreteStruct(index)
637 }
638 wasmparser::CompositeInnerType::Cont(_) => {
639 WasmHeapType::ConcreteCont(index)
640 }
641 }
642 } else {
643 panic!("forward reference to type outside of rec group?")
644 }
645 }
646
647 UnpackedIndex::RecGroup(_) => unreachable!(),
648 }
649 }
650
651 fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex {
652 match index {
653 UnpackedIndex::Id(id) => {
654 let interned = self.types.wasmparser_to_wasmtime[&id];
655 EngineOrModuleTypeIndex::Module(interned)
656 }
657 UnpackedIndex::Module(module_index) => {
658 let module_index = TypeIndex::from_u32(module_index);
659 let interned = (self.lookup_type_idx)(module_index);
660 EngineOrModuleTypeIndex::Module(interned)
661 }
662 UnpackedIndex::RecGroup(_) => unreachable!(),
663 }
664 }
665}