wasmtime_environ/compile/
module_types.rs1use crate::{
2 EngineOrModuleTypeIndex, EntityRef, ModuleInternedRecGroupIndex, ModuleInternedTypeIndex,
3 ModuleTypes, TypeConvert, TypeIndex, WasmArrayType, WasmCompositeInnerType, WasmCompositeType,
4 WasmFuncType, WasmHeapType, WasmResult, WasmStructType, WasmSubType, wasm_unsupported,
5};
6use std::{borrow::Cow, collections::HashMap, ops::Index};
7use wasmparser::{UnpackedIndex, Validator, ValidatorId};
8
9struct RecGroupStart {
15 rec_group_index: ModuleInternedRecGroupIndex,
16 start: ModuleInternedTypeIndex,
17 end: ModuleInternedTypeIndex,
18}
19
20pub struct ModuleTypesBuilder {
22 validator_id: ValidatorId,
30
31 types: ModuleTypes,
33
34 trampoline_types: HashMap<WasmFuncType, ModuleInternedTypeIndex>,
39
40 wasmparser_to_wasmtime: HashMap<wasmparser::types::CoreTypeId, ModuleInternedTypeIndex>,
43
44 already_seen: HashMap<wasmparser::types::RecGroupId, ModuleInternedRecGroupIndex>,
46
47 defining_rec_group: Option<RecGroupStart>,
50}
51
52impl ModuleTypesBuilder {
53 pub fn new(validator: &Validator) -> Self {
55 Self {
56 validator_id: validator.id(),
57 types: ModuleTypes::default(),
58 trampoline_types: HashMap::default(),
59 wasmparser_to_wasmtime: HashMap::default(),
60 already_seen: HashMap::default(),
61 defining_rec_group: None,
62 }
63 }
64
65 pub fn reserve_wasm_signatures(&mut self, amt: usize) {
67 self.types.reserve(amt);
68 self.wasmparser_to_wasmtime.reserve(amt);
69 self.already_seen.reserve(amt);
70 }
71
72 pub fn validator_id(&self) -> ValidatorId {
74 self.validator_id
75 }
76
77 pub fn intern_rec_group(
84 &mut self,
85 validator_types: wasmparser::types::TypesRef<'_>,
86 rec_group_id: wasmparser::types::RecGroupId,
87 ) -> WasmResult<ModuleInternedRecGroupIndex> {
88 assert_eq!(validator_types.id(), self.validator_id);
89
90 if let Some(interned) = self.already_seen.get(&rec_group_id) {
91 return Ok(*interned);
92 }
93
94 self.define_new_rec_group(validator_types, rec_group_id)
95 }
96
97 fn define_new_rec_group(
99 &mut self,
100 validator_types: wasmparser::types::TypesRef<'_>,
101 rec_group_id: wasmparser::types::RecGroupId,
102 ) -> WasmResult<ModuleInternedRecGroupIndex> {
103 assert_eq!(validator_types.id(), self.validator_id);
104
105 self.start_rec_group(
106 validator_types,
107 validator_types.rec_group_elements(rec_group_id),
108 );
109
110 for id in validator_types.rec_group_elements(rec_group_id) {
111 let ty = &validator_types[id];
112 let wasm_ty = WasmparserTypeConverter::new(self, |_| {
113 unreachable!("no need to lookup indexes; we already have core type IDs")
114 })
115 .with_rec_group(validator_types, rec_group_id)
116 .convert_sub_type(ty)?;
117 self.wasm_sub_type_in_rec_group(id, wasm_ty);
118 }
119
120 let rec_group_index = self.end_rec_group(rec_group_id);
121
122 for ty in self.rec_group_elements(rec_group_index) {
128 if self.types[ty].is_func() {
129 let trampoline = self.intern_trampoline_type(ty);
130 self.types.set_trampoline_type(ty, trampoline);
131 }
132 }
133
134 Ok(rec_group_index)
135 }
136
137 fn intern_trampoline_type(
140 &mut self,
141 for_func_ty: ModuleInternedTypeIndex,
142 ) -> ModuleInternedTypeIndex {
143 let sub_ty = &self.types[for_func_ty];
144 let trampoline = sub_ty.unwrap_func().trampoline_type();
145
146 if let Some(idx) = self.trampoline_types.get(&trampoline) {
147 *idx
149 } else {
150 match trampoline {
152 Cow::Borrowed(f) => {
157 self.trampoline_types.insert(f.clone(), for_func_ty);
158 for_func_ty
159 }
160 Cow::Owned(f) => {
164 let idx = self.types.push(WasmSubType {
165 is_final: true,
166 supertype: None,
167 composite_type: WasmCompositeType {
168 inner: WasmCompositeInnerType::Func(f.clone()),
169 shared: sub_ty.composite_type.shared,
170 },
171 });
172
173 self.types.set_trampoline_type(idx, idx);
175
176 let next = self.types.next_ty();
177 self.types.push_rec_group(idx..next);
178 self.trampoline_types.insert(f, idx);
179 idx
180 }
181 }
182 }
183 }
184
185 fn start_rec_group(
187 &mut self,
188 validator_types: wasmparser::types::TypesRef<'_>,
189 elems: impl ExactSizeIterator<Item = wasmparser::types::CoreTypeId>,
190 ) {
191 log::trace!("Starting rec group of length {}", elems.len());
192
193 assert!(self.defining_rec_group.is_none());
194 assert_eq!(validator_types.id(), self.validator_id);
195
196 let len = elems.len();
200 for (i, wasmparser_id) in elems.enumerate() {
201 let interned = ModuleInternedTypeIndex::new(self.types.len_types() + i);
202 log::trace!(
203 "Reserving {interned:?} for {wasmparser_id:?} = {:?}",
204 validator_types[wasmparser_id]
205 );
206
207 let old_entry = self.wasmparser_to_wasmtime.insert(wasmparser_id, interned);
208 debug_assert_eq!(
209 old_entry, None,
210 "should not have already inserted {wasmparser_id:?}"
211 );
212 }
213
214 self.defining_rec_group = Some(RecGroupStart {
215 rec_group_index: self.types.next_rec_group(),
216 start: self.types.next_ty(),
217 end: ModuleInternedTypeIndex::new(self.types.len_types() + len),
218 });
219 }
220
221 fn end_rec_group(
223 &mut self,
224 rec_group_id: wasmparser::types::RecGroupId,
225 ) -> ModuleInternedRecGroupIndex {
226 let RecGroupStart {
227 rec_group_index,
228 start,
229 end,
230 } = self
231 .defining_rec_group
232 .take()
233 .expect("should be defining a rec group");
234
235 log::trace!("Ending rec group {start:?}..{end:?}");
236
237 debug_assert!(start.index() < self.types.len_types());
238 debug_assert_eq!(
239 end,
240 self.types.next_ty(),
241 "should have defined the number of types declared in `start_rec_group`"
242 );
243
244 let idx = self.types.push_rec_group(start..end);
245 debug_assert_eq!(idx, rec_group_index);
246
247 self.already_seen.insert(rec_group_id, rec_group_index);
248 rec_group_index
249 }
250
251 pub fn intern_type(
258 &mut self,
259 validator_types: wasmparser::types::TypesRef<'_>,
260 id: wasmparser::types::CoreTypeId,
261 ) -> WasmResult<ModuleInternedTypeIndex> {
262 assert!(self.defining_rec_group.is_none());
263 assert_eq!(validator_types.id(), self.validator_id);
264
265 let rec_group_id = validator_types.rec_group_id_of(id);
266 debug_assert!(
267 validator_types
268 .rec_group_elements(rec_group_id)
269 .any(|e| e == id)
270 );
271
272 let interned_rec_group = self.intern_rec_group(validator_types, rec_group_id)?;
273
274 let interned_type = self.wasmparser_to_wasmtime[&id];
275 debug_assert!(
276 self.rec_group_elements(interned_rec_group)
277 .any(|e| e == interned_type)
278 );
279
280 Ok(interned_type)
281 }
282
283 fn wasm_sub_type_in_rec_group(
285 &mut self,
286 id: wasmparser::types::CoreTypeId,
287 ty: WasmSubType,
288 ) -> ModuleInternedTypeIndex {
289 assert!(
290 self.defining_rec_group.is_some(),
291 "must be defining a rec group to define new types"
292 );
293
294 let module_interned_index = self.types.push(ty);
295 debug_assert_eq!(
296 self.wasmparser_to_wasmtime.get(&id),
297 Some(&module_interned_index),
298 "should have reserved the right module-interned index for this wasmparser type already"
299 );
300
301 module_interned_index
302 }
303
304 pub fn finish(self) -> ModuleTypes {
306 self.types
307 }
308
309 pub fn rec_group_elements(
311 &self,
312 rec_group: ModuleInternedRecGroupIndex,
313 ) -> impl ExactSizeIterator<Item = ModuleInternedTypeIndex> + use<> {
314 self.types.rec_group_elements(rec_group)
315 }
316
317 pub fn wasm_types(&self) -> impl Iterator<Item = (ModuleInternedTypeIndex, &WasmSubType)> {
320 self.types.wasm_types()
321 }
322
323 pub fn trampoline_types(
326 &self,
327 ) -> impl Iterator<Item = (ModuleInternedTypeIndex, ModuleInternedTypeIndex)> + '_ {
328 self.types.trampoline_types()
329 }
330
331 pub fn trampoline_type(&self, ty: ModuleInternedTypeIndex) -> ModuleInternedTypeIndex {
333 self.types.trampoline_type(ty)
334 }
335
336 pub fn unwrap_struct(&self, ty: ModuleInternedTypeIndex) -> WasmResult<&WasmStructType> {
346 let composite_type = &self.types[ty].composite_type;
347 if composite_type.shared {
348 return Err(wasm_unsupported!("shared structs are not yet implemented"));
349 }
350 match &composite_type.inner {
351 WasmCompositeInnerType::Struct(s) => Ok(s),
352 _ => unreachable!(),
353 }
354 }
355
356 pub fn unwrap_array(&self, interned_ty: ModuleInternedTypeIndex) -> WasmResult<&WasmArrayType> {
366 let composite_type = &self.types[interned_ty].composite_type;
367 if composite_type.shared {
368 return Err(wasm_unsupported!("shared arrays are not yet implemented"));
369 }
370 match &composite_type.inner {
371 WasmCompositeInnerType::Array(a) => Ok(a),
372 _ => unreachable!(),
373 }
374 }
375}
376
377impl<T> Index<T> for ModuleTypesBuilder
379where
380 ModuleTypes: Index<T>,
381{
382 type Output = <ModuleTypes as Index<T>>::Output;
383
384 fn index(&self, sig: T) -> &Self::Output {
385 &self.types[sig]
386 }
387}
388
389pub struct WasmparserTypeConverter<'a, F> {
391 types: &'a ModuleTypesBuilder,
392 lookup_type_idx: F,
393 rec_group_context: Option<(
394 wasmparser::types::TypesRef<'a>,
395 wasmparser::types::RecGroupId,
396 )>,
397}
398
399impl<'a, F> WasmparserTypeConverter<'a, F> {
400 pub fn new(types: &'a ModuleTypesBuilder, lookup_type_idx: F) -> Self {
402 Self {
403 types,
404 lookup_type_idx,
405 rec_group_context: None,
406 }
407 }
408
409 pub fn with_rec_group(
412 &mut self,
413 wasmparser_types: wasmparser::types::TypesRef<'a>,
414 rec_group: wasmparser::types::RecGroupId,
415 ) -> &Self {
416 self.rec_group_context = Some((wasmparser_types, rec_group));
417 self
418 }
419}
420
421impl<F> TypeConvert for WasmparserTypeConverter<'_, F>
422where
423 F: Fn(TypeIndex) -> ModuleInternedTypeIndex,
424{
425 fn lookup_heap_type(&self, index: UnpackedIndex) -> WasmHeapType {
426 match index {
427 UnpackedIndex::Id(id) => {
428 let interned = self.types.wasmparser_to_wasmtime[&id];
429 let index = EngineOrModuleTypeIndex::Module(interned);
430
431 if let Some(ty) = self.types.types.get(interned) {
438 assert!(!ty.composite_type.shared);
439 match &ty.composite_type.inner {
440 WasmCompositeInnerType::Array(_) => WasmHeapType::ConcreteArray(index),
441 WasmCompositeInnerType::Func(_) => WasmHeapType::ConcreteFunc(index),
442 WasmCompositeInnerType::Struct(_) => WasmHeapType::ConcreteStruct(index),
443 WasmCompositeInnerType::Cont(_) => WasmHeapType::ConcreteCont(index),
444 }
445 } else if let Some((wasmparser_types, _)) = self.rec_group_context.as_ref() {
446 let wasmparser_ty = &wasmparser_types[id].composite_type;
447 assert!(!wasmparser_ty.shared);
448 match &wasmparser_ty.inner {
449 wasmparser::CompositeInnerType::Array(_) => {
450 WasmHeapType::ConcreteArray(index)
451 }
452 wasmparser::CompositeInnerType::Func(_) => {
453 WasmHeapType::ConcreteFunc(index)
454 }
455 wasmparser::CompositeInnerType::Struct(_) => {
456 WasmHeapType::ConcreteStruct(index)
457 }
458 wasmparser::CompositeInnerType::Cont(_) => {
459 WasmHeapType::ConcreteCont(index)
460 }
461 }
462 } else {
463 panic!("forward reference to type outside of rec group?")
464 }
465 }
466
467 UnpackedIndex::Module(module_index) => {
468 let module_index = TypeIndex::from_u32(module_index);
469 let interned = (self.lookup_type_idx)(module_index);
470 let index = EngineOrModuleTypeIndex::Module(interned);
471
472 if let Some(ty) = self.types.types.get(interned) {
478 assert!(!ty.composite_type.shared);
479 match &ty.composite_type.inner {
480 WasmCompositeInnerType::Array(_) => WasmHeapType::ConcreteArray(index),
481 WasmCompositeInnerType::Func(_) => WasmHeapType::ConcreteFunc(index),
482 WasmCompositeInnerType::Struct(_) => WasmHeapType::ConcreteStruct(index),
483 WasmCompositeInnerType::Cont(_) => WasmHeapType::ConcreteCont(index),
484 }
485 } else if let Some((parser_types, rec_group)) = self.rec_group_context.as_ref() {
486 let rec_group_index = interned.index() - self.types.types.len_types();
487 let id = parser_types
488 .rec_group_elements(*rec_group)
489 .nth(rec_group_index)
490 .unwrap();
491 let wasmparser_ty = &parser_types[id].composite_type;
492 assert!(!wasmparser_ty.shared);
493 match &wasmparser_ty.inner {
494 wasmparser::CompositeInnerType::Array(_) => {
495 WasmHeapType::ConcreteArray(index)
496 }
497 wasmparser::CompositeInnerType::Func(_) => {
498 WasmHeapType::ConcreteFunc(index)
499 }
500 wasmparser::CompositeInnerType::Struct(_) => {
501 WasmHeapType::ConcreteStruct(index)
502 }
503 wasmparser::CompositeInnerType::Cont(_) => {
504 WasmHeapType::ConcreteCont(index)
505 }
506 }
507 } else {
508 panic!("forward reference to type outside of rec group?")
509 }
510 }
511
512 UnpackedIndex::RecGroup(_) => unreachable!(),
513 }
514 }
515
516 fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex {
517 match index {
518 UnpackedIndex::Id(id) => {
519 let interned = self.types.wasmparser_to_wasmtime[&id];
520 EngineOrModuleTypeIndex::Module(interned)
521 }
522 UnpackedIndex::Module(module_index) => {
523 let module_index = TypeIndex::from_u32(module_index);
524 let interned = (self.lookup_type_idx)(module_index);
525 EngineOrModuleTypeIndex::Module(interned)
526 }
527 UnpackedIndex::RecGroup(_) => unreachable!(),
528 }
529 }
530}