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