wasmtime_environ/compile/
module_types.rs1use crate::{EntityRef, Module, ModuleTypes, TypeConvert};
2use std::{borrow::Cow, collections::HashMap, ops::Index};
3use wasmparser::{UnpackedIndex, Validator, ValidatorId};
4use wasmtime_types::{
5 EngineOrModuleTypeIndex, ModuleInternedRecGroupIndex, ModuleInternedTypeIndex, TypeIndex,
6 WasmCompositeType, WasmFuncType, WasmHeapType, WasmResult, WasmSubType,
7};
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 module: &Module,
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(module, validator_types, rec_group_id)
96 }
97
98 fn define_new_rec_group(
100 &mut self,
101 module: &Module,
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 self.start_rec_group(
108 validator_types,
109 validator_types.rec_group_elements(rec_group_id),
110 );
111
112 for id in validator_types.rec_group_elements(rec_group_id) {
113 let ty = &validator_types[id];
114 let wasm_ty = WasmparserTypeConverter::new(self, module)
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 trampoline = self.types[for_func_ty].unwrap_func().trampoline_type();
144
145 if let Some(idx) = self.trampoline_types.get(&trampoline) {
146 *idx
148 } else {
149 match trampoline {
151 Cow::Borrowed(f) => {
156 self.trampoline_types.insert(f.clone(), for_func_ty);
157 for_func_ty
158 }
159 Cow::Owned(f) => {
163 let idx = self.types.push(WasmSubType {
164 is_final: true,
165 supertype: None,
166 composite_type: WasmCompositeType::Func(f.clone()),
167 });
168
169 self.types.set_trampoline_type(idx, idx);
171
172 let next = self.types.next_ty();
173 self.types.push_rec_group(idx..next);
174 self.trampoline_types.insert(f, idx);
175 idx
176 }
177 }
178 }
179 }
180
181 fn start_rec_group(
183 &mut self,
184 validator_types: wasmparser::types::TypesRef<'_>,
185 elems: impl ExactSizeIterator<Item = wasmparser::types::CoreTypeId>,
186 ) {
187 log::trace!("Starting rec group of length {}", elems.len());
188
189 assert!(self.defining_rec_group.is_none());
190 assert_eq!(validator_types.id(), self.validator_id);
191
192 let len = elems.len();
196 for (i, wasmparser_id) in elems.enumerate() {
197 let interned = ModuleInternedTypeIndex::new(self.types.len_types() + i);
198 log::trace!(
199 "Reserving {interned:?} for {wasmparser_id:?} = {:?}",
200 validator_types[wasmparser_id]
201 );
202
203 let old_entry = self.wasmparser_to_wasmtime.insert(wasmparser_id, interned);
204 debug_assert_eq!(
205 old_entry, None,
206 "should not have already inserted {wasmparser_id:?}"
207 );
208 }
209
210 self.defining_rec_group = Some(RecGroupStart {
211 rec_group_index: self.types.next_rec_group(),
212 start: self.types.next_ty(),
213 end: ModuleInternedTypeIndex::new(self.types.len_types() + len),
214 });
215 }
216
217 fn end_rec_group(
219 &mut self,
220 rec_group_id: wasmparser::types::RecGroupId,
221 ) -> ModuleInternedRecGroupIndex {
222 let RecGroupStart {
223 rec_group_index,
224 start,
225 end,
226 } = self
227 .defining_rec_group
228 .take()
229 .expect("should be defining a rec group");
230
231 log::trace!("Ending rec group {start:?}..{end:?}");
232
233 debug_assert!(start.index() < self.types.len_types());
234 debug_assert_eq!(
235 end,
236 self.types.next_ty(),
237 "should have defined the number of types declared in `start_rec_group`"
238 );
239
240 let idx = self.types.push_rec_group(start..end);
241 debug_assert_eq!(idx, rec_group_index);
242
243 self.already_seen.insert(rec_group_id, rec_group_index);
244 rec_group_index
245 }
246
247 pub fn intern_type(
254 &mut self,
255 module: &Module,
256 validator_types: wasmparser::types::TypesRef<'_>,
257 id: wasmparser::types::CoreTypeId,
258 ) -> WasmResult<ModuleInternedTypeIndex> {
259 assert!(self.defining_rec_group.is_none());
260 assert_eq!(validator_types.id(), self.validator_id);
261
262 let rec_group_id = validator_types.rec_group_id_of(id);
263 debug_assert!(validator_types
264 .rec_group_elements(rec_group_id)
265 .any(|e| e == id));
266
267 let interned_rec_group = self.intern_rec_group(module, validator_types, rec_group_id)?;
268
269 let interned_type = self.wasmparser_to_wasmtime[&id];
270 debug_assert!(self
271 .rec_group_elements(interned_rec_group)
272 .any(|e| e == interned_type));
273
274 Ok(interned_type)
275 }
276
277 fn wasm_sub_type_in_rec_group(
279 &mut self,
280 id: wasmparser::types::CoreTypeId,
281 ty: WasmSubType,
282 ) -> ModuleInternedTypeIndex {
283 assert!(
284 self.defining_rec_group.is_some(),
285 "must be defining a rec group to define new types"
286 );
287
288 let module_interned_index = self.types.push(ty);
289 debug_assert_eq!(
290 self.wasmparser_to_wasmtime.get(&id),
291 Some(&module_interned_index),
292 "should have reserved the right module-interned index for this wasmparser type already"
293 );
294
295 module_interned_index
296 }
297
298 pub fn finish(self) -> ModuleTypes {
300 self.types
301 }
302
303 pub fn rec_group_elements(
305 &self,
306 rec_group: ModuleInternedRecGroupIndex,
307 ) -> impl ExactSizeIterator<Item = ModuleInternedTypeIndex> {
308 self.types.rec_group_elements(rec_group)
309 }
310
311 pub fn wasm_types(&self) -> impl Iterator<Item = (ModuleInternedTypeIndex, &WasmSubType)> {
314 self.types.wasm_types()
315 }
316
317 pub fn trampoline_types(
320 &self,
321 ) -> impl Iterator<Item = (ModuleInternedTypeIndex, ModuleInternedTypeIndex)> + '_ {
322 self.types.trampoline_types()
323 }
324
325 pub fn trampoline_type(&self, ty: ModuleInternedTypeIndex) -> ModuleInternedTypeIndex {
327 self.types.trampoline_type(ty)
328 }
329}
330
331impl<T> Index<T> for ModuleTypesBuilder
333where
334 ModuleTypes: Index<T>,
335{
336 type Output = <ModuleTypes as Index<T>>::Output;
337
338 fn index(&self, sig: T) -> &Self::Output {
339 &self.types[sig]
340 }
341}
342
343pub struct WasmparserTypeConverter<'a> {
345 types: &'a ModuleTypesBuilder,
346 module: &'a Module,
347 rec_group_context: Option<(
348 wasmparser::types::TypesRef<'a>,
349 wasmparser::types::RecGroupId,
350 )>,
351}
352
353impl<'a> WasmparserTypeConverter<'a> {
354 pub fn new(types: &'a ModuleTypesBuilder, module: &'a Module) -> Self {
356 Self {
357 types,
358 module,
359 rec_group_context: None,
360 }
361 }
362
363 pub fn with_rec_group(
366 &mut self,
367 wasmparser_types: wasmparser::types::TypesRef<'a>,
368 rec_group: wasmparser::types::RecGroupId,
369 ) -> &Self {
370 self.rec_group_context = Some((wasmparser_types, rec_group));
371 self
372 }
373}
374
375impl TypeConvert for WasmparserTypeConverter<'_> {
376 fn lookup_heap_type(&self, index: UnpackedIndex) -> WasmHeapType {
377 match index {
378 UnpackedIndex::Id(id) => {
379 let interned = self.types.wasmparser_to_wasmtime[&id];
380 let index = EngineOrModuleTypeIndex::Module(interned);
381
382 if let Some(ty) = self.types.types.get(interned) {
389 match &ty.composite_type {
390 WasmCompositeType::Array(_) => WasmHeapType::ConcreteArray(index),
391 WasmCompositeType::Func(_) => WasmHeapType::ConcreteFunc(index),
392 WasmCompositeType::Struct(_) => WasmHeapType::ConcreteStruct(index),
393 }
394 } else if let Some((wasmparser_types, _)) = self.rec_group_context.as_ref() {
395 let wasmparser_ty = &wasmparser_types[id].composite_type;
396 assert!(!wasmparser_ty.shared);
397 match &wasmparser_ty.inner {
398 wasmparser::CompositeInnerType::Array(_) => {
399 WasmHeapType::ConcreteArray(index)
400 }
401 wasmparser::CompositeInnerType::Func(_) => {
402 WasmHeapType::ConcreteFunc(index)
403 }
404 wasmparser::CompositeInnerType::Struct(_) => {
405 WasmHeapType::ConcreteStruct(index)
406 }
407 }
408 } else {
409 panic!("forward reference to type outside of rec group?")
410 }
411 }
412
413 UnpackedIndex::Module(module_index) => {
414 let module_index = TypeIndex::from_u32(module_index);
415 let interned = self.module.types[module_index];
416 let index = EngineOrModuleTypeIndex::Module(interned);
417
418 if let Some(ty) = self.types.types.get(interned) {
424 match &ty.composite_type {
425 WasmCompositeType::Array(_) => WasmHeapType::ConcreteArray(index),
426 WasmCompositeType::Func(_) => WasmHeapType::ConcreteFunc(index),
427 WasmCompositeType::Struct(_) => WasmHeapType::ConcreteStruct(index),
428 }
429 } else if let Some((parser_types, rec_group)) = self.rec_group_context.as_ref() {
430 let rec_group_index = interned.index() - self.types.types.len_types();
431 let id = parser_types
432 .rec_group_elements(*rec_group)
433 .nth(rec_group_index)
434 .unwrap();
435 let wasmparser_ty = &parser_types[id].composite_type;
436 assert!(!wasmparser_ty.shared);
437 match &wasmparser_ty.inner {
438 wasmparser::CompositeInnerType::Array(_) => {
439 WasmHeapType::ConcreteArray(index)
440 }
441 wasmparser::CompositeInnerType::Func(_) => {
442 WasmHeapType::ConcreteFunc(index)
443 }
444 wasmparser::CompositeInnerType::Struct(_) => {
445 WasmHeapType::ConcreteStruct(index)
446 }
447 }
448 } else {
449 panic!("forward reference to type outside of rec group?")
450 }
451 }
452
453 UnpackedIndex::RecGroup(_) => unreachable!(),
454 }
455 }
456
457 fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex {
458 match index {
459 UnpackedIndex::Id(id) => {
460 let interned = self.types.wasmparser_to_wasmtime[&id];
461 EngineOrModuleTypeIndex::Module(interned)
462 }
463 UnpackedIndex::Module(module_index) => {
464 let module_index = TypeIndex::from_u32(module_index);
465 let interned = self.module.types[module_index];
466 EngineOrModuleTypeIndex::Module(interned)
467 }
468 UnpackedIndex::RecGroup(_) => unreachable!(),
469 }
470 }
471}