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,
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
64impl ModuleTypesBuilder {
65 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 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 pub fn validator_id(&self) -> ValidatorId {
87 self.validator_id
88 }
89
90 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 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 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 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 *idx
162 } else {
163 match trampoline {
165 TryCow::Borrowed(f) => {
170 self.trampoline_types
171 .insert(f.clone_panic_on_oom(), for_func_ty);
172 for_func_ty
173 }
174 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 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 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 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 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 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 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 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 pub fn finish(self) -> ModuleTypes {
364 self.types
365 }
366
367 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 pub fn wasm_types(&self) -> impl Iterator<Item = (ModuleInternedTypeIndex, &WasmSubType)> {
378 self.types.wasm_types()
379 }
380
381 pub fn trampoline_types(
384 &self,
385 ) -> impl Iterator<Item = (ModuleInternedTypeIndex, ModuleInternedTypeIndex)> + '_ {
386 self.types.trampoline_types()
387 }
388
389 pub fn trampoline_type(&self, ty: ModuleInternedTypeIndex) -> ModuleInternedTypeIndex {
391 self.types.trampoline_type(ty)
392 }
393
394 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 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 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 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
467impl<T> Index<T> for ModuleTypesBuilder
469where
470 ModuleTypes: Index<T>,
471{
472 type Output = <ModuleTypes as Index<T>>::Output;
473
474 fn index(&self, sig: T) -> &Self::Output {
475 &self.types[sig]
476 }
477}
478
479pub 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
489impl<'a, F> WasmparserTypeConverter<'a, F> {
490 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 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
511impl<F> TypeConvert for WasmparserTypeConverter<'_, F>
512where
513 F: Fn(TypeIndex) -> ModuleInternedTypeIndex,
514{
515 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 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 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
608 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}