1use crate::{
2 MemoryTunables, PanicOnOom as _, Tunables, WasmResult, collections::TryCow, error::OutOfMemory,
3 prelude::*, wasm_unsupported,
4};
5use alloc::boxed::Box;
6use core::{fmt, ops::Range};
7use serde_derive::{Deserialize, Serialize};
8use smallvec::SmallVec;
9
10#[doc(hidden)]
11pub fn deserialize_boxed_slice<'de, T, D>(deserializer: D) -> Result<Box<[T]>, D::Error>
12where
13 T: serde::de::Deserialize<'de>,
14 D: serde::de::Deserializer<'de>,
15{
16 let tys: crate::collections::TryVec<T> = serde::Deserialize::deserialize(deserializer)?;
17 let tys = tys
18 .into_boxed_slice()
19 .map_err(|oom| serde::de::Error::custom(oom))?;
20 Ok(tys)
21}
22
23pub trait TypeTrace {
26 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
30 where
31 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>;
32
33 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
39 where
40 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>;
41
42 fn trace_engine_indices<F, E>(&self, func: &mut F) -> Result<(), E>
44 where
45 F: FnMut(VMSharedTypeIndex) -> Result<(), E>,
46 {
47 self.trace(&mut |idx| match idx {
48 EngineOrModuleTypeIndex::Engine(idx) => func(idx),
49 EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
50 })
51 }
52
53 fn canonicalize_for_runtime_usage<F>(&mut self, module_to_engine: &mut F)
64 where
65 F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
66 {
67 self.trace_mut::<_, ()>(&mut |idx| match idx {
68 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
69 EngineOrModuleTypeIndex::Module(module_index) => {
70 let engine_index = module_to_engine(*module_index);
71 *idx = EngineOrModuleTypeIndex::Engine(engine_index);
72 Ok(())
73 }
74 EngineOrModuleTypeIndex::RecGroup(_) => {
75 panic!("should not already be canonicalized for hash consing")
76 }
77 })
78 .unwrap()
79 }
80
81 fn is_canonicalized_for_runtime_usage(&self) -> bool {
83 self.trace(&mut |idx| match idx {
84 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
85 EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Err(()),
86 })
87 .is_ok()
88 }
89
90 fn canonicalize_for_hash_consing<F>(
101 &mut self,
102 rec_group_range: Range<ModuleInternedTypeIndex>,
103 module_to_engine: &mut F,
104 ) where
105 F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
106 {
107 self.trace_mut::<_, ()>(&mut |idx| match *idx {
108 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
109 EngineOrModuleTypeIndex::Module(module_index) => {
110 *idx = if rec_group_range.start <= module_index {
111 debug_assert!(module_index < rec_group_range.end);
114 let relative = module_index.as_u32() - rec_group_range.start.as_u32();
115 let relative = RecGroupRelativeTypeIndex::from_u32(relative);
116 EngineOrModuleTypeIndex::RecGroup(relative)
117 } else {
118 debug_assert!(module_index < rec_group_range.start);
121 EngineOrModuleTypeIndex::Engine(module_to_engine(module_index))
122 };
123 Ok(())
124 }
125 EngineOrModuleTypeIndex::RecGroup(_) => {
126 panic!("should not already be canonicalized for hash consing")
127 }
128 })
129 .unwrap()
130 }
131
132 fn is_canonicalized_for_hash_consing(&self) -> bool {
134 self.trace(&mut |idx| match idx {
135 EngineOrModuleTypeIndex::Engine(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
136 EngineOrModuleTypeIndex::Module(_) => Err(()),
137 })
138 .is_ok()
139 }
140}
141
142#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
144pub enum WasmValType {
145 I32,
147 I64,
149 F32,
151 F64,
153 V128,
155 Ref(WasmRefType),
157}
158
159impl TryClone for WasmValType {
160 fn try_clone(&self) -> Result<Self, OutOfMemory> {
161 Ok(*self)
162 }
163}
164
165impl fmt::Display for WasmValType {
166 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
167 match self {
168 WasmValType::I32 => write!(f, "i32"),
169 WasmValType::I64 => write!(f, "i64"),
170 WasmValType::F32 => write!(f, "f32"),
171 WasmValType::F64 => write!(f, "f64"),
172 WasmValType::V128 => write!(f, "v128"),
173 WasmValType::Ref(rt) => write!(f, "{rt}"),
174 }
175 }
176}
177
178impl TypeTrace for WasmValType {
179 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
180 where
181 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
182 {
183 match self {
184 WasmValType::Ref(r) => r.trace(func),
185 WasmValType::I32
186 | WasmValType::I64
187 | WasmValType::F32
188 | WasmValType::F64
189 | WasmValType::V128 => Ok(()),
190 }
191 }
192
193 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
194 where
195 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
196 {
197 match self {
198 WasmValType::Ref(r) => r.trace_mut(func),
199 WasmValType::I32
200 | WasmValType::I64
201 | WasmValType::F32
202 | WasmValType::F64
203 | WasmValType::V128 => Ok(()),
204 }
205 }
206}
207
208impl WasmValType {
209 pub const FUNCREF: WasmValType = WasmValType::Ref(WasmRefType::FUNCREF);
211
212 #[inline]
214 pub fn is_vmgcref_type(&self) -> bool {
215 match self {
216 WasmValType::Ref(r) => r.is_vmgcref_type(),
217 _ => false,
218 }
219 }
220
221 #[inline]
227 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
228 match self {
229 WasmValType::Ref(r) => r.is_vmgcref_type_and_not_i31(),
230 _ => false,
231 }
232 }
233
234 fn trampoline_type(&self) -> Self {
235 match self {
236 WasmValType::Ref(r) => WasmValType::Ref(WasmRefType {
237 nullable: true,
238 heap_type: r.heap_type.top().into(),
239 }),
240 WasmValType::I32
241 | WasmValType::I64
242 | WasmValType::F32
243 | WasmValType::F64
244 | WasmValType::V128 => *self,
245 }
246 }
247
248 pub fn int_from_bits(bits: u8) -> Self {
252 match bits {
253 32 => Self::I32,
254 64 => Self::I64,
255 size => panic!("invalid int bits for WasmValType: {size}"),
256 }
257 }
258
259 pub fn unwrap_ref_type(&self) -> WasmRefType {
263 match self {
264 WasmValType::Ref(ref_type) => *ref_type,
265 _ => panic!("Called WasmValType::unwrap_ref_type on non-reference type"),
266 }
267 }
268}
269
270#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
272pub struct WasmRefType {
273 pub nullable: bool,
275 pub heap_type: WasmHeapType,
277}
278
279impl TypeTrace for WasmRefType {
280 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
281 where
282 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
283 {
284 self.heap_type.trace(func)
285 }
286
287 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
288 where
289 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
290 {
291 self.heap_type.trace_mut(func)
292 }
293}
294
295impl WasmRefType {
296 pub const EXTERNREF: WasmRefType = WasmRefType {
298 nullable: true,
299 heap_type: WasmHeapType::Extern,
300 };
301 pub const FUNCREF: WasmRefType = WasmRefType {
303 nullable: true,
304 heap_type: WasmHeapType::Func,
305 };
306
307 #[inline]
309 pub fn is_vmgcref_type(&self) -> bool {
310 self.heap_type.is_vmgcref_type()
311 }
312
313 #[inline]
319 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
320 self.heap_type.is_vmgcref_type_and_not_i31()
321 }
322}
323
324impl fmt::Display for WasmRefType {
325 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
326 match *self {
327 Self::FUNCREF => write!(f, "funcref"),
328 Self::EXTERNREF => write!(f, "externref"),
329 _ => {
330 if self.nullable {
331 write!(f, "(ref null {})", self.heap_type)
332 } else {
333 write!(f, "(ref {})", self.heap_type)
334 }
335 }
336 }
337 }
338}
339
340#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
345pub enum EngineOrModuleTypeIndex {
346 Engine(VMSharedTypeIndex),
349
350 Module(ModuleInternedTypeIndex),
353
354 RecGroup(RecGroupRelativeTypeIndex),
358}
359
360impl From<ModuleInternedTypeIndex> for EngineOrModuleTypeIndex {
361 #[inline]
362 fn from(i: ModuleInternedTypeIndex) -> Self {
363 Self::Module(i)
364 }
365}
366
367impl From<VMSharedTypeIndex> for EngineOrModuleTypeIndex {
368 #[inline]
369 fn from(i: VMSharedTypeIndex) -> Self {
370 Self::Engine(i)
371 }
372}
373
374impl From<RecGroupRelativeTypeIndex> for EngineOrModuleTypeIndex {
375 #[inline]
376 fn from(i: RecGroupRelativeTypeIndex) -> Self {
377 Self::RecGroup(i)
378 }
379}
380
381impl fmt::Display for EngineOrModuleTypeIndex {
382 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
383 match self {
384 Self::Engine(i) => write!(f, "(engine {})", i.bits()),
385 Self::Module(i) => write!(f, "(module {})", i.as_u32()),
386 Self::RecGroup(i) => write!(f, "(recgroup {})", i.as_u32()),
387 }
388 }
389}
390
391impl EngineOrModuleTypeIndex {
392 pub fn is_engine_type_index(self) -> bool {
394 matches!(self, Self::Engine(_))
395 }
396
397 #[inline]
399 pub fn as_engine_type_index(self) -> Option<VMSharedTypeIndex> {
400 match self {
401 Self::Engine(e) => Some(e),
402 Self::RecGroup(_) | Self::Module(_) => None,
403 }
404 }
405
406 #[track_caller]
408 #[inline]
409 pub fn unwrap_engine_type_index(self) -> VMSharedTypeIndex {
410 match self.as_engine_type_index() {
411 Some(x) => x,
412 None => panic!("`unwrap_engine_type_index` on {self:?}"),
413 }
414 }
415
416 pub fn is_module_type_index(self) -> bool {
418 matches!(self, Self::Module(_))
419 }
420
421 pub fn as_module_type_index(self) -> Option<ModuleInternedTypeIndex> {
423 match self {
424 Self::Module(e) => Some(e),
425 Self::RecGroup(_) | Self::Engine(_) => None,
426 }
427 }
428
429 #[track_caller]
431 pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
432 match self.as_module_type_index() {
433 Some(x) => x,
434 None => panic!("`unwrap_module_type_index` on {self:?}"),
435 }
436 }
437
438 pub fn is_rec_group_type_index(self) -> bool {
440 matches!(self, Self::RecGroup(_))
441 }
442
443 pub fn as_rec_group_type_index(self) -> Option<RecGroupRelativeTypeIndex> {
445 match self {
446 Self::RecGroup(r) => Some(r),
447 Self::Module(_) | Self::Engine(_) => None,
448 }
449 }
450
451 #[track_caller]
453 pub fn unwrap_rec_group_type_index(self) -> RecGroupRelativeTypeIndex {
454 match self.as_rec_group_type_index() {
455 Some(x) => x,
456 None => panic!("`unwrap_rec_group_type_index` on {self:?}"),
457 }
458 }
459}
460
461#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
463#[expect(missing_docs, reason = "self-describing variants")]
464pub enum WasmHeapType {
465 Extern,
467 NoExtern,
468
469 Func,
471 ConcreteFunc(EngineOrModuleTypeIndex),
472 NoFunc,
473
474 Exn,
476 ConcreteExn(EngineOrModuleTypeIndex),
477 NoExn,
478
479 Cont,
481 ConcreteCont(EngineOrModuleTypeIndex),
482 NoCont,
483
484 Any,
486 Eq,
487 I31,
488 Array,
489 ConcreteArray(EngineOrModuleTypeIndex),
490 Struct,
491 ConcreteStruct(EngineOrModuleTypeIndex),
492 None,
493}
494
495impl From<WasmHeapTopType> for WasmHeapType {
496 #[inline]
497 fn from(value: WasmHeapTopType) -> Self {
498 match value {
499 WasmHeapTopType::Extern => Self::Extern,
500 WasmHeapTopType::Any => Self::Any,
501 WasmHeapTopType::Func => Self::Func,
502 WasmHeapTopType::Cont => Self::Cont,
503 WasmHeapTopType::Exn => Self::Exn,
504 }
505 }
506}
507
508impl From<WasmHeapBottomType> for WasmHeapType {
509 #[inline]
510 fn from(value: WasmHeapBottomType) -> Self {
511 match value {
512 WasmHeapBottomType::NoExtern => Self::NoExtern,
513 WasmHeapBottomType::None => Self::None,
514 WasmHeapBottomType::NoFunc => Self::NoFunc,
515 WasmHeapBottomType::NoCont => Self::NoCont,
516 WasmHeapBottomType::NoExn => Self::NoExn,
517 }
518 }
519}
520
521impl fmt::Display for WasmHeapType {
522 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
523 match self {
524 Self::Extern => write!(f, "extern"),
525 Self::NoExtern => write!(f, "noextern"),
526 Self::Func => write!(f, "func"),
527 Self::ConcreteFunc(i) => write!(f, "func {i}"),
528 Self::NoFunc => write!(f, "nofunc"),
529 Self::Cont => write!(f, "cont"),
530 Self::ConcreteCont(i) => write!(f, "cont {i}"),
531 Self::NoCont => write!(f, "nocont"),
532 Self::Any => write!(f, "any"),
533 Self::Eq => write!(f, "eq"),
534 Self::I31 => write!(f, "i31"),
535 Self::Array => write!(f, "array"),
536 Self::ConcreteArray(i) => write!(f, "array {i}"),
537 Self::Struct => write!(f, "struct"),
538 Self::ConcreteStruct(i) => write!(f, "struct {i}"),
539 Self::Exn => write!(f, "exn"),
540 Self::ConcreteExn(i) => write!(f, "exn {i}"),
541 Self::NoExn => write!(f, "noexn"),
542 Self::None => write!(f, "none"),
543 }
544 }
545}
546
547impl TypeTrace for WasmHeapType {
548 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
549 where
550 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
551 {
552 match *self {
553 Self::ConcreteArray(i) => func(i),
554 Self::ConcreteFunc(i) => func(i),
555 Self::ConcreteStruct(i) => func(i),
556 Self::ConcreteCont(i) => func(i),
557 _ => Ok(()),
558 }
559 }
560
561 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
562 where
563 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
564 {
565 match self {
566 Self::ConcreteArray(i) => func(i),
567 Self::ConcreteFunc(i) => func(i),
568 Self::ConcreteStruct(i) => func(i),
569 Self::ConcreteCont(i) => func(i),
570 _ => Ok(()),
571 }
572 }
573}
574
575impl WasmHeapType {
576 #[inline]
578 pub fn is_vmgcref_type(&self) -> bool {
579 match self.top() {
580 WasmHeapTopType::Any | WasmHeapTopType::Extern | WasmHeapTopType::Exn => true,
584
585 WasmHeapTopType::Func => false,
587 WasmHeapTopType::Cont => false,
588 }
589 }
590
591 #[inline]
597 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
598 self.is_vmgcref_type() && *self != Self::I31
599 }
600
601 #[inline]
603 pub fn is_top(&self) -> bool {
604 *self == Self::from(self.top())
605 }
606
607 #[inline]
609 pub fn top(&self) -> WasmHeapTopType {
610 match self {
611 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapTopType::Extern,
612
613 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
614 WasmHeapTopType::Func
615 }
616
617 WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
618 WasmHeapTopType::Cont
619 }
620
621 WasmHeapType::Exn | WasmHeapType::ConcreteExn(_) | WasmHeapType::NoExn => {
622 WasmHeapTopType::Exn
623 }
624
625 WasmHeapType::Any
626 | WasmHeapType::Eq
627 | WasmHeapType::I31
628 | WasmHeapType::Array
629 | WasmHeapType::ConcreteArray(_)
630 | WasmHeapType::Struct
631 | WasmHeapType::ConcreteStruct(_)
632 | WasmHeapType::None => WasmHeapTopType::Any,
633 }
634 }
635
636 #[inline]
638 pub fn is_bottom(&self) -> bool {
639 *self == Self::from(self.bottom())
640 }
641
642 #[inline]
644 pub fn bottom(&self) -> WasmHeapBottomType {
645 match self {
646 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapBottomType::NoExtern,
647
648 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
649 WasmHeapBottomType::NoFunc
650 }
651
652 WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
653 WasmHeapBottomType::NoCont
654 }
655
656 WasmHeapType::Exn | WasmHeapType::ConcreteExn(_) | WasmHeapType::NoExn => {
657 WasmHeapBottomType::NoExn
658 }
659
660 WasmHeapType::Any
661 | WasmHeapType::Eq
662 | WasmHeapType::I31
663 | WasmHeapType::Array
664 | WasmHeapType::ConcreteArray(_)
665 | WasmHeapType::Struct
666 | WasmHeapType::ConcreteStruct(_)
667 | WasmHeapType::None => WasmHeapBottomType::None,
668 }
669 }
670}
671
672#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
674pub enum WasmHeapTopType {
675 Extern,
677 Any,
679 Func,
681 Exn,
683 Cont,
685}
686
687#[derive(Debug, Clone, Copy, Eq, PartialEq)]
689pub enum WasmHeapBottomType {
690 NoExtern,
692 None,
694 NoFunc,
696 NoExn,
698 NoCont,
700}
701
702#[derive(Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
704pub struct WasmFuncType {
705 #[serde(deserialize_with = "deserialize_boxed_slice")]
706 params_results: Box<[WasmValType]>,
707 params_len: u32,
708 non_i31_gc_ref_params_count: u32,
709 non_i31_gc_ref_results_count: u32,
710}
711
712impl TryClone for WasmFuncType {
713 fn try_clone(&self) -> Result<Self, OutOfMemory> {
714 Ok(Self {
715 params_results: TryClone::try_clone(&self.params_results)?,
716 params_len: self.params_len,
717 non_i31_gc_ref_params_count: self.non_i31_gc_ref_params_count,
718 non_i31_gc_ref_results_count: self.non_i31_gc_ref_results_count,
719 })
720 }
721}
722
723impl fmt::Display for WasmFuncType {
724 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
725 write!(f, "(func")?;
726 if !self.params().is_empty() {
727 write!(f, " (param")?;
728 for p in self.params() {
729 write!(f, " {p}")?;
730 }
731 write!(f, ")")?;
732 }
733 if !self.results().is_empty() {
734 write!(f, " (result")?;
735 for r in self.results() {
736 write!(f, " {r}")?;
737 }
738 write!(f, ")")?;
739 }
740 write!(f, ")")
741 }
742}
743
744impl TypeTrace for WasmFuncType {
745 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
746 where
747 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
748 {
749 for ty in self.params_results.iter() {
750 ty.trace(func)?;
751 }
752 Ok(())
753 }
754
755 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
756 where
757 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
758 {
759 for ty in self.params_results.iter_mut() {
760 ty.trace_mut(func)?;
761 }
762 Ok(())
763 }
764}
765
766impl WasmFuncType {
767 #[inline]
769 pub fn new(
770 params: impl IntoIterator<Item = WasmValType>,
771 results: impl IntoIterator<Item = WasmValType>,
772 ) -> Result<Self, OutOfMemory> {
773 let mut params_results: crate::collections::TryVec<_> = params.into_iter().try_collect()?;
774 let non_i31_gc_ref_params_count = params_results
775 .iter()
776 .filter(|p| p.is_vmgcref_type_and_not_i31())
777 .count();
778
779 let params_len = params_results.len();
780 params_results.try_extend(results)?;
781 let non_i31_gc_ref_results_count = params_results[params_len..]
782 .iter()
783 .filter(|r| r.is_vmgcref_type_and_not_i31())
784 .count();
785
786 let params_results = params_results.into_boxed_slice()?;
787 let params_len = u32::try_from(params_len).unwrap();
788 let non_i31_gc_ref_params_count = u32::try_from(non_i31_gc_ref_params_count).unwrap();
789 let non_i31_gc_ref_results_count = u32::try_from(non_i31_gc_ref_results_count).unwrap();
790
791 Ok(Self {
792 params_results,
793 params_len,
794 non_i31_gc_ref_params_count,
795 non_i31_gc_ref_results_count,
796 })
797 }
798
799 fn results_start(&self) -> usize {
800 usize::try_from(self.params_len).unwrap()
801 }
802
803 #[inline]
805 pub fn params(&self) -> &[WasmValType] {
806 &self.params_results[..self.results_start()]
807 }
808
809 #[inline]
811 pub fn non_i31_gc_ref_params_count(&self) -> usize {
812 usize::try_from(self.non_i31_gc_ref_params_count).unwrap()
813 }
814
815 #[inline]
817 pub fn results(&self) -> &[WasmValType] {
818 &self.params_results[self.results_start()..]
819 }
820
821 #[inline]
823 pub fn non_i31_gc_ref_results_count(&self) -> usize {
824 usize::try_from(self.non_i31_gc_ref_results_count).unwrap()
825 }
826
827 pub fn is_trampoline_type(&self) -> bool {
829 self.params().iter().all(|p| *p == p.trampoline_type())
830 && self.results().iter().all(|r| *r == r.trampoline_type())
831 }
832
833 pub fn trampoline_type(&self) -> Result<TryCow<'_, Self>, OutOfMemory> {
859 if self.is_trampoline_type() {
860 return Ok(TryCow::Borrowed(self));
861 }
862
863 Ok(TryCow::Owned(Self::new(
864 self.params().iter().map(|p| p.trampoline_type()),
865 self.results().iter().map(|r| r.trampoline_type()),
866 )?))
867 }
868}
869
870#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
872pub struct WasmContType(EngineOrModuleTypeIndex);
873
874impl fmt::Display for WasmContType {
875 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
876 write!(f, "(cont {})", self.0)
877 }
878}
879
880impl WasmContType {
881 pub fn new(idx: EngineOrModuleTypeIndex) -> Self {
883 WasmContType(idx)
884 }
885
886 pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
888 match self.0 {
889 EngineOrModuleTypeIndex::Engine(_) => panic!("not module interned"),
890 EngineOrModuleTypeIndex::Module(idx) => idx,
891 EngineOrModuleTypeIndex::RecGroup(_) => todo!(),
892 }
893 }
894}
895
896impl TypeTrace for WasmContType {
897 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
898 where
899 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
900 {
901 func(self.0)
902 }
903
904 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
905 where
906 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
907 {
908 func(&mut self.0)
909 }
910}
911
912#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
937pub struct WasmExnType {
938 pub func_ty: EngineOrModuleTypeIndex,
942 #[serde(deserialize_with = "deserialize_boxed_slice")]
949 pub fields: Box<[WasmFieldType]>,
950}
951
952impl TryClone for WasmExnType {
953 fn try_clone(&self) -> Result<Self, OutOfMemory> {
954 Ok(Self {
955 func_ty: self.func_ty,
956 fields: self.fields.try_clone()?,
957 })
958 }
959}
960
961impl fmt::Display for WasmExnType {
962 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
963 write!(f, "(exn ({})", self.func_ty)?;
964 for ty in self.fields.iter() {
965 write!(f, " {ty}")?;
966 }
967 write!(f, ")")
968 }
969}
970
971impl TypeTrace for WasmExnType {
972 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
973 where
974 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
975 {
976 func(self.func_ty)?;
977 for f in self.fields.iter() {
978 f.trace(func)?;
979 }
980 Ok(())
981 }
982
983 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
984 where
985 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
986 {
987 func(&mut self.func_ty)?;
988 for f in self.fields.iter_mut() {
989 f.trace_mut(func)?;
990 }
991 Ok(())
992 }
993}
994
995#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
997pub enum WasmStorageType {
998 I8,
1000 I16,
1002 Val(WasmValType),
1004}
1005
1006impl fmt::Display for WasmStorageType {
1007 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1008 match self {
1009 WasmStorageType::I8 => write!(f, "i8"),
1010 WasmStorageType::I16 => write!(f, "i16"),
1011 WasmStorageType::Val(v) => fmt::Display::fmt(v, f),
1012 }
1013 }
1014}
1015
1016impl TypeTrace for WasmStorageType {
1017 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1018 where
1019 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1020 {
1021 match self {
1022 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
1023 WasmStorageType::Val(v) => v.trace(func),
1024 }
1025 }
1026
1027 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1028 where
1029 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1030 {
1031 match self {
1032 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
1033 WasmStorageType::Val(v) => v.trace_mut(func),
1034 }
1035 }
1036}
1037
1038impl WasmStorageType {
1039 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
1045 match self {
1046 WasmStorageType::I8 | WasmStorageType::I16 => false,
1047 WasmStorageType::Val(v) => v.is_vmgcref_type_and_not_i31(),
1048 }
1049 }
1050}
1051
1052#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
1054pub struct WasmFieldType {
1055 pub element_type: WasmStorageType,
1057
1058 pub mutable: bool,
1060}
1061
1062impl TryClone for WasmFieldType {
1063 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1064 Ok(*self)
1065 }
1066}
1067
1068impl fmt::Display for WasmFieldType {
1069 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1070 if self.mutable {
1071 write!(f, "(mut {})", self.element_type)
1072 } else {
1073 fmt::Display::fmt(&self.element_type, f)
1074 }
1075 }
1076}
1077
1078impl TypeTrace for WasmFieldType {
1079 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1080 where
1081 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1082 {
1083 self.element_type.trace(func)
1084 }
1085
1086 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1087 where
1088 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1089 {
1090 self.element_type.trace_mut(func)
1091 }
1092}
1093
1094#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
1096pub struct WasmArrayType(pub WasmFieldType);
1097
1098impl fmt::Display for WasmArrayType {
1099 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1100 write!(f, "(array {})", self.0)
1101 }
1102}
1103
1104impl TypeTrace for WasmArrayType {
1105 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1106 where
1107 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1108 {
1109 self.0.trace(func)
1110 }
1111
1112 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1113 where
1114 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1115 {
1116 self.0.trace_mut(func)
1117 }
1118}
1119
1120#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1122pub struct WasmStructType {
1123 #[serde(deserialize_with = "deserialize_boxed_slice")]
1125 pub fields: Box<[WasmFieldType]>,
1126}
1127
1128impl TryClone for WasmStructType {
1129 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1130 Ok(Self {
1131 fields: self.fields.try_clone()?,
1132 })
1133 }
1134}
1135
1136impl fmt::Display for WasmStructType {
1137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1138 write!(f, "(struct")?;
1139 for ty in self.fields.iter() {
1140 write!(f, " {ty}")?;
1141 }
1142 write!(f, ")")
1143 }
1144}
1145
1146impl TypeTrace for WasmStructType {
1147 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1148 where
1149 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1150 {
1151 for f in self.fields.iter() {
1152 f.trace(func)?;
1153 }
1154 Ok(())
1155 }
1156
1157 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1158 where
1159 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1160 {
1161 for f in self.fields.iter_mut() {
1162 f.trace_mut(func)?;
1163 }
1164 Ok(())
1165 }
1166}
1167
1168#[derive(Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1169#[expect(missing_docs, reason = "self-describing type")]
1170pub struct WasmCompositeType {
1171 pub inner: WasmCompositeInnerType,
1173 pub shared: bool,
1176}
1177
1178impl TryClone for WasmCompositeType {
1179 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1180 Ok(Self {
1181 inner: self.inner.try_clone()?,
1182 shared: self.shared,
1183 })
1184 }
1185}
1186
1187impl fmt::Display for WasmCompositeType {
1188 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1189 if self.shared {
1190 write!(f, "(shared ")?;
1191 }
1192 fmt::Display::fmt(&self.inner, f)?;
1193 if self.shared {
1194 write!(f, ")")?;
1195 }
1196 Ok(())
1197 }
1198}
1199
1200#[derive(Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1202#[expect(missing_docs, reason = "self-describing variants")]
1203pub enum WasmCompositeInnerType {
1204 Array(WasmArrayType),
1205 Func(WasmFuncType),
1206 Struct(WasmStructType),
1207 Cont(WasmContType),
1208 Exn(WasmExnType),
1209}
1210
1211impl TryClone for WasmCompositeInnerType {
1212 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1213 Ok(match self {
1214 Self::Array(ty) => Self::Array(*ty),
1215 Self::Func(ty) => Self::Func(ty.try_clone()?),
1216 Self::Struct(ty) => Self::Struct(ty.try_clone()?),
1217 Self::Cont(ty) => Self::Cont(*ty),
1218 Self::Exn(ty) => Self::Exn(ty.try_clone()?),
1219 })
1220 }
1221}
1222
1223impl fmt::Display for WasmCompositeInnerType {
1224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1225 match self {
1226 Self::Array(ty) => fmt::Display::fmt(ty, f),
1227 Self::Func(ty) => fmt::Display::fmt(ty, f),
1228 Self::Struct(ty) => fmt::Display::fmt(ty, f),
1229 Self::Cont(ty) => fmt::Display::fmt(ty, f),
1230 Self::Exn(ty) => fmt::Display::fmt(ty, f),
1231 }
1232 }
1233}
1234
1235#[expect(missing_docs, reason = "self-describing functions")]
1236impl WasmCompositeInnerType {
1237 #[inline]
1238 pub fn is_array(&self) -> bool {
1239 matches!(self, Self::Array(_))
1240 }
1241
1242 #[inline]
1243 pub fn as_array(&self) -> Option<&WasmArrayType> {
1244 match self {
1245 Self::Array(f) => Some(f),
1246 _ => None,
1247 }
1248 }
1249
1250 #[inline]
1251 pub fn unwrap_array(&self) -> &WasmArrayType {
1252 self.as_array().unwrap()
1253 }
1254
1255 #[inline]
1256 pub fn is_func(&self) -> bool {
1257 matches!(self, Self::Func(_))
1258 }
1259
1260 #[inline]
1261 pub fn as_func(&self) -> Option<&WasmFuncType> {
1262 match self {
1263 Self::Func(f) => Some(f),
1264 _ => None,
1265 }
1266 }
1267
1268 #[inline]
1269 pub fn unwrap_func(&self) -> &WasmFuncType {
1270 self.as_func().unwrap()
1271 }
1272
1273 #[inline]
1274 pub fn is_struct(&self) -> bool {
1275 matches!(self, Self::Struct(_))
1276 }
1277
1278 #[inline]
1279 pub fn as_struct(&self) -> Option<&WasmStructType> {
1280 match self {
1281 Self::Struct(f) => Some(f),
1282 _ => None,
1283 }
1284 }
1285
1286 #[inline]
1287 pub fn unwrap_struct(&self) -> &WasmStructType {
1288 self.as_struct().unwrap()
1289 }
1290
1291 #[inline]
1292 pub fn is_cont(&self) -> bool {
1293 matches!(self, Self::Cont(_))
1294 }
1295
1296 #[inline]
1297 pub fn as_cont(&self) -> Option<&WasmContType> {
1298 match self {
1299 Self::Cont(f) => Some(f),
1300 _ => None,
1301 }
1302 }
1303
1304 #[inline]
1305 pub fn unwrap_cont(&self) -> &WasmContType {
1306 self.as_cont().unwrap()
1307 }
1308
1309 #[inline]
1310 pub fn is_exn(&self) -> bool {
1311 matches!(self, Self::Exn(_))
1312 }
1313
1314 #[inline]
1315 pub fn as_exn(&self) -> Option<&WasmExnType> {
1316 match self {
1317 Self::Exn(f) => Some(f),
1318 _ => None,
1319 }
1320 }
1321
1322 #[inline]
1323 pub fn unwrap_exn(&self) -> &WasmExnType {
1324 self.as_exn().unwrap()
1325 }
1326}
1327
1328impl TypeTrace for WasmCompositeType {
1329 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1330 where
1331 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1332 {
1333 match &self.inner {
1334 WasmCompositeInnerType::Array(a) => a.trace(func),
1335 WasmCompositeInnerType::Func(f) => f.trace(func),
1336 WasmCompositeInnerType::Struct(a) => a.trace(func),
1337 WasmCompositeInnerType::Cont(c) => c.trace(func),
1338 WasmCompositeInnerType::Exn(e) => e.trace(func),
1339 }
1340 }
1341
1342 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1343 where
1344 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1345 {
1346 match &mut self.inner {
1347 WasmCompositeInnerType::Array(a) => a.trace_mut(func),
1348 WasmCompositeInnerType::Func(f) => f.trace_mut(func),
1349 WasmCompositeInnerType::Struct(a) => a.trace_mut(func),
1350 WasmCompositeInnerType::Cont(c) => c.trace_mut(func),
1351 WasmCompositeInnerType::Exn(e) => e.trace_mut(func),
1352 }
1353 }
1354}
1355
1356#[derive(Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1358pub struct WasmSubType {
1359 pub is_final: bool,
1362
1363 pub supertype: Option<EngineOrModuleTypeIndex>,
1365
1366 pub composite_type: WasmCompositeType,
1368}
1369
1370impl TryClone for WasmSubType {
1371 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1372 Ok(Self {
1373 is_final: self.is_final,
1374 supertype: self.supertype,
1375 composite_type: self.composite_type.try_clone()?,
1376 })
1377 }
1378}
1379
1380impl fmt::Display for WasmSubType {
1381 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1382 if self.is_final && self.supertype.is_none() {
1383 fmt::Display::fmt(&self.composite_type, f)
1384 } else {
1385 write!(f, "(sub")?;
1386 if self.is_final {
1387 write!(f, " final")?;
1388 }
1389 if let Some(sup) = self.supertype {
1390 write!(f, " {sup}")?;
1391 }
1392 write!(f, " {})", self.composite_type)
1393 }
1394 }
1395}
1396
1397#[expect(missing_docs, reason = "self-describing functions")]
1401impl WasmSubType {
1402 #[inline]
1403 pub fn is_func(&self) -> bool {
1404 self.composite_type.inner.is_func() && !self.composite_type.shared
1405 }
1406
1407 #[inline]
1408 pub fn as_func(&self) -> Option<&WasmFuncType> {
1409 if self.composite_type.shared {
1410 None
1411 } else {
1412 self.composite_type.inner.as_func()
1413 }
1414 }
1415
1416 #[inline]
1417 pub fn unwrap_func(&self) -> &WasmFuncType {
1418 assert!(!self.composite_type.shared);
1419 self.composite_type.inner.unwrap_func()
1420 }
1421
1422 #[inline]
1423 pub fn is_array(&self) -> bool {
1424 self.composite_type.inner.is_array() && !self.composite_type.shared
1425 }
1426
1427 #[inline]
1428 pub fn as_array(&self) -> Option<&WasmArrayType> {
1429 if self.composite_type.shared {
1430 None
1431 } else {
1432 self.composite_type.inner.as_array()
1433 }
1434 }
1435
1436 #[inline]
1437 pub fn unwrap_array(&self) -> &WasmArrayType {
1438 assert!(!self.composite_type.shared);
1439 self.composite_type.inner.unwrap_array()
1440 }
1441
1442 #[inline]
1443 pub fn is_struct(&self) -> bool {
1444 self.composite_type.inner.is_struct() && !self.composite_type.shared
1445 }
1446
1447 #[inline]
1448 pub fn as_struct(&self) -> Option<&WasmStructType> {
1449 if self.composite_type.shared {
1450 None
1451 } else {
1452 self.composite_type.inner.as_struct()
1453 }
1454 }
1455
1456 #[inline]
1457 pub fn unwrap_struct(&self) -> &WasmStructType {
1458 assert!(!self.composite_type.shared);
1459 self.composite_type.inner.unwrap_struct()
1460 }
1461
1462 #[inline]
1463 pub fn is_cont(&self) -> bool {
1464 self.composite_type.inner.is_cont() && !self.composite_type.shared
1465 }
1466
1467 #[inline]
1468 pub fn as_cont(&self) -> Option<&WasmContType> {
1469 if self.composite_type.shared {
1470 None
1471 } else {
1472 self.composite_type.inner.as_cont()
1473 }
1474 }
1475
1476 #[inline]
1477 pub fn unwrap_cont(&self) -> &WasmContType {
1478 assert!(!self.composite_type.shared);
1479 self.composite_type.inner.unwrap_cont()
1480 }
1481
1482 #[inline]
1483 pub fn is_exn(&self) -> bool {
1484 self.composite_type.inner.is_exn() && !self.composite_type.shared
1485 }
1486
1487 #[inline]
1488 pub fn as_exn(&self) -> Option<&WasmExnType> {
1489 if self.composite_type.shared {
1490 None
1491 } else {
1492 self.composite_type.inner.as_exn()
1493 }
1494 }
1495
1496 #[inline]
1497 pub fn unwrap_exn(&self) -> &WasmExnType {
1498 assert!(!self.composite_type.shared);
1499 self.composite_type.inner.unwrap_exn()
1500 }
1501}
1502
1503impl TypeTrace for WasmSubType {
1504 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1505 where
1506 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1507 {
1508 if let Some(sup) = self.supertype {
1509 func(sup)?;
1510 }
1511 self.composite_type.trace(func)
1512 }
1513
1514 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1515 where
1516 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1517 {
1518 if let Some(sup) = self.supertype.as_mut() {
1519 func(sup)?;
1520 }
1521 self.composite_type.trace_mut(func)
1522 }
1523}
1524
1525#[derive(Debug, Default, Eq, PartialEq, Hash, Serialize, Deserialize)]
1536pub struct WasmRecGroup {
1537 #[serde(deserialize_with = "deserialize_boxed_slice")]
1539 pub types: Box<[WasmSubType]>,
1540}
1541
1542impl TypeTrace for WasmRecGroup {
1543 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1544 where
1545 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1546 {
1547 for ty in self.types.iter() {
1548 ty.trace(func)?;
1549 }
1550 Ok(())
1551 }
1552
1553 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1554 where
1555 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1556 {
1557 for ty in self.types.iter_mut() {
1558 ty.trace_mut(func)?;
1559 }
1560 Ok(())
1561 }
1562}
1563
1564macro_rules! entity_impl_with_try_clone {
1565 ( $ty:ident ) => {
1566 cranelift_entity::entity_impl!($ty);
1567
1568 impl TryClone for $ty {
1569 #[inline]
1570 fn try_clone(&self) -> Result<Self, $crate::error::OutOfMemory> {
1571 Ok(*self)
1572 }
1573 }
1574 };
1575}
1576
1577#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1579pub struct FuncIndex(u32);
1580entity_impl_with_try_clone!(FuncIndex);
1581
1582#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1584pub struct DefinedFuncIndex(u32);
1585entity_impl_with_try_clone!(DefinedFuncIndex);
1586
1587#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1589pub struct DefinedTableIndex(u32);
1590entity_impl_with_try_clone!(DefinedTableIndex);
1591
1592#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1594pub struct DefinedMemoryIndex(u32);
1595entity_impl_with_try_clone!(DefinedMemoryIndex);
1596
1597#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1599pub struct OwnedMemoryIndex(u32);
1600entity_impl_with_try_clone!(OwnedMemoryIndex);
1601
1602#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1604pub struct DefinedGlobalIndex(u32);
1605entity_impl_with_try_clone!(DefinedGlobalIndex);
1606
1607#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1609pub struct TableIndex(u32);
1610entity_impl_with_try_clone!(TableIndex);
1611
1612#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1614pub struct GlobalIndex(u32);
1615entity_impl_with_try_clone!(GlobalIndex);
1616
1617#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1619pub struct MemoryIndex(u32);
1620entity_impl_with_try_clone!(MemoryIndex);
1621
1622#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1625pub struct ModuleInternedRecGroupIndex(u32);
1626entity_impl_with_try_clone!(ModuleInternedRecGroupIndex);
1627
1628#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1631pub struct EngineInternedRecGroupIndex(u32);
1632entity_impl_with_try_clone!(EngineInternedRecGroupIndex);
1633
1634#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1636pub struct TypeIndex(u32);
1637entity_impl_with_try_clone!(TypeIndex);
1638
1639#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1645pub struct RecGroupRelativeTypeIndex(u32);
1646entity_impl_with_try_clone!(RecGroupRelativeTypeIndex);
1647
1648#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1656pub struct ModuleInternedTypeIndex(u32);
1657entity_impl_with_try_clone!(ModuleInternedTypeIndex);
1658
1659#[repr(transparent)] #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1668pub struct VMSharedTypeIndex(u32);
1669entity_impl_with_try_clone!(VMSharedTypeIndex);
1670
1671impl VMSharedTypeIndex {
1672 #[inline]
1674 pub fn new(value: u32) -> Self {
1675 assert_ne!(
1676 value,
1677 u32::MAX,
1678 "u32::MAX is reserved for the default value"
1679 );
1680 Self(value)
1681 }
1682
1683 #[inline]
1685 pub fn bits(&self) -> u32 {
1686 self.0
1687 }
1688}
1689
1690impl Default for VMSharedTypeIndex {
1691 #[inline]
1692 fn default() -> Self {
1693 Self(u32::MAX)
1694 }
1695}
1696
1697#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1699pub struct DataIndex(u32);
1700entity_impl_with_try_clone!(DataIndex);
1701
1702#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1713pub struct RuntimeDataIndex(u32);
1714entity_impl_with_try_clone!(RuntimeDataIndex);
1715
1716#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1718pub struct ElemIndex(u32);
1719entity_impl_with_try_clone!(ElemIndex);
1720
1721#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1726pub struct PassiveElemIndex(u32);
1727entity_impl_with_try_clone!(PassiveElemIndex);
1728
1729#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1731pub struct DefinedTagIndex(u32);
1732entity_impl_with_try_clone!(DefinedTagIndex);
1733
1734#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1736pub struct TagIndex(u32);
1737entity_impl_with_try_clone!(TagIndex);
1738
1739#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1744pub struct StaticModuleIndex(u32);
1745entity_impl_with_try_clone!(StaticModuleIndex);
1746
1747#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1749pub enum EntityIndex {
1750 Function(FuncIndex),
1752 Table(TableIndex),
1754 Memory(MemoryIndex),
1756 Global(GlobalIndex),
1758 Tag(TagIndex),
1760}
1761
1762impl From<FuncIndex> for EntityIndex {
1763 fn from(idx: FuncIndex) -> EntityIndex {
1764 EntityIndex::Function(idx)
1765 }
1766}
1767
1768impl From<TableIndex> for EntityIndex {
1769 fn from(idx: TableIndex) -> EntityIndex {
1770 EntityIndex::Table(idx)
1771 }
1772}
1773
1774impl From<MemoryIndex> for EntityIndex {
1775 fn from(idx: MemoryIndex) -> EntityIndex {
1776 EntityIndex::Memory(idx)
1777 }
1778}
1779
1780impl From<GlobalIndex> for EntityIndex {
1781 fn from(idx: GlobalIndex) -> EntityIndex {
1782 EntityIndex::Global(idx)
1783 }
1784}
1785
1786impl From<TagIndex> for EntityIndex {
1787 fn from(idx: TagIndex) -> EntityIndex {
1788 EntityIndex::Tag(idx)
1789 }
1790}
1791
1792#[derive(Clone, Debug, Serialize, Deserialize)]
1795pub enum EntityType {
1796 Global(Global),
1798 Memory(Memory),
1800 Tag(Tag),
1802 Table(Table),
1804 Function(EngineOrModuleTypeIndex),
1807}
1808
1809impl TypeTrace for EntityType {
1810 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1811 where
1812 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1813 {
1814 match self {
1815 Self::Global(g) => g.trace(func),
1816 Self::Table(t) => t.trace(func),
1817 Self::Function(idx) => func(*idx),
1818 Self::Memory(_) => Ok(()),
1819 Self::Tag(t) => t.trace(func),
1820 }
1821 }
1822
1823 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1824 where
1825 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1826 {
1827 match self {
1828 Self::Global(g) => g.trace_mut(func),
1829 Self::Table(t) => t.trace_mut(func),
1830 Self::Function(idx) => func(idx),
1831 Self::Memory(_) => Ok(()),
1832 Self::Tag(t) => t.trace_mut(func),
1833 }
1834 }
1835}
1836
1837impl EntityType {
1838 pub fn unwrap_global(&self) -> &Global {
1840 match self {
1841 EntityType::Global(g) => g,
1842 _ => panic!("not a global"),
1843 }
1844 }
1845
1846 pub fn unwrap_memory(&self) -> &Memory {
1848 match self {
1849 EntityType::Memory(g) => g,
1850 _ => panic!("not a memory"),
1851 }
1852 }
1853
1854 pub fn unwrap_tag(&self) -> &Tag {
1856 match self {
1857 EntityType::Tag(g) => g,
1858 _ => panic!("not a tag"),
1859 }
1860 }
1861
1862 pub fn unwrap_table(&self) -> &Table {
1864 match self {
1865 EntityType::Table(g) => g,
1866 _ => panic!("not a table"),
1867 }
1868 }
1869
1870 pub fn unwrap_func(&self) -> EngineOrModuleTypeIndex {
1872 match self {
1873 EntityType::Function(g) => *g,
1874 _ => panic!("not a func"),
1875 }
1876 }
1877}
1878
1879#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1887pub struct Global {
1888 pub wasm_ty: crate::WasmValType,
1890 pub mutability: bool,
1892}
1893
1894impl TypeTrace for Global {
1895 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1896 where
1897 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1898 {
1899 let Global {
1900 wasm_ty,
1901 mutability: _,
1902 } = self;
1903 wasm_ty.trace(func)
1904 }
1905
1906 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1907 where
1908 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1909 {
1910 let Global {
1911 wasm_ty,
1912 mutability: _,
1913 } = self;
1914 wasm_ty.trace_mut(func)
1915 }
1916}
1917
1918#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1922pub struct ConstExpr {
1923 ops: SmallVec<[ConstOp; 2]>,
1924}
1925
1926impl ConstExpr {
1927 pub fn new(ops: impl IntoIterator<Item = ConstOp>) -> Self {
1933 let ops = ops.into_iter().collect::<SmallVec<[ConstOp; 2]>>();
1934 assert!(!ops.is_empty());
1935 ConstExpr { ops }
1936 }
1937
1938 pub fn from_wasmparser(
1943 env: &dyn TypeConvert,
1944 expr: wasmparser::ConstExpr<'_>,
1945 ) -> WasmResult<(Self, SmallVec<[FuncIndex; 1]>)> {
1946 let mut iter = expr
1947 .get_operators_reader()
1948 .into_iter_with_offsets()
1949 .peekable();
1950
1951 let mut ops = SmallVec::<[ConstOp; 2]>::new();
1952 let mut escaped = SmallVec::<[FuncIndex; 1]>::new();
1953 while let Some(res) = iter.next() {
1954 let (op, offset) = res?;
1955
1956 if matches!(op, wasmparser::Operator::End) && iter.peek().is_none() {
1960 break;
1961 }
1962
1963 if let wasmparser::Operator::RefFunc { function_index } = &op {
1966 escaped.push(FuncIndex::from_u32(*function_index));
1967 }
1968
1969 ops.push(ConstOp::from_wasmparser(env, op, offset)?);
1970 }
1971 Ok((Self { ops }, escaped))
1972 }
1973
1974 #[inline]
1976 pub fn ops(&self) -> &[ConstOp] {
1977 &self.ops
1978 }
1979
1980 pub fn provably_nonzero_i32(&self) -> bool {
1990 match self.const_eval() {
1991 Some(GlobalConstValue::I32(x)) => x != 0,
1992
1993 _ => false,
1996 }
1997 }
1998
1999 pub fn const_eval(&self) -> Option<GlobalConstValue> {
2001 match self.ops() {
2004 [ConstOp::I32Const(x)] => Some(GlobalConstValue::I32(*x)),
2005 [ConstOp::I64Const(x)] => Some(GlobalConstValue::I64(*x)),
2006 [ConstOp::F32Const(x)] => Some(GlobalConstValue::F32(*x)),
2007 [ConstOp::F64Const(x)] => Some(GlobalConstValue::F64(*x)),
2008 [ConstOp::V128Const(x)] => Some(GlobalConstValue::V128(*x)),
2009 _ => None,
2010 }
2011 }
2012}
2013
2014#[expect(missing_docs, reason = "self-describing variants")]
2016#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
2017pub enum GlobalConstValue {
2018 I32(i32),
2019 I64(i64),
2020 F32(u32),
2021 F64(u64),
2022 V128(u128),
2023}
2024
2025#[expect(missing_docs, reason = "self-describing variants")]
2027#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
2028pub enum ConstOp {
2029 I32Const(i32),
2030 I64Const(i64),
2031 F32Const(u32),
2032 F64Const(u64),
2033 V128Const(u128),
2034 GlobalGet(GlobalIndex),
2035 RefI31,
2036 RefNull(WasmHeapType),
2037 RefFunc(FuncIndex),
2038 I32Add,
2039 I32Sub,
2040 I32Mul,
2041 I64Add,
2042 I64Sub,
2043 I64Mul,
2044 StructNew {
2045 struct_type_index: TypeIndex,
2046 },
2047 StructNewDefault {
2048 struct_type_index: TypeIndex,
2049 },
2050 ArrayNew {
2051 array_type_index: TypeIndex,
2052 },
2053 ArrayNewDefault {
2054 array_type_index: TypeIndex,
2055 },
2056 ArrayNewFixed {
2057 array_type_index: TypeIndex,
2058 array_size: u32,
2059 },
2060 ExternConvertAny,
2061 AnyConvertExtern,
2062}
2063
2064impl ConstOp {
2065 pub fn from_wasmparser(
2067 env: &dyn TypeConvert,
2068 op: wasmparser::Operator<'_>,
2069 offset: usize,
2070 ) -> WasmResult<Self> {
2071 use wasmparser::Operator as O;
2072 Ok(match op {
2073 O::I32Const { value } => Self::I32Const(value),
2074 O::I64Const { value } => Self::I64Const(value),
2075 O::F32Const { value } => Self::F32Const(value.bits()),
2076 O::F64Const { value } => Self::F64Const(value.bits()),
2077 O::V128Const { value } => Self::V128Const(u128::from_le_bytes(*value.bytes())),
2078 O::RefNull { hty } => Self::RefNull(env.convert_heap_type(hty)?),
2079 O::RefFunc { function_index } => Self::RefFunc(FuncIndex::from_u32(function_index)),
2080 O::GlobalGet { global_index } => Self::GlobalGet(GlobalIndex::from_u32(global_index)),
2081 O::RefI31 => Self::RefI31,
2082 O::I32Add => Self::I32Add,
2083 O::I32Sub => Self::I32Sub,
2084 O::I32Mul => Self::I32Mul,
2085 O::I64Add => Self::I64Add,
2086 O::I64Sub => Self::I64Sub,
2087 O::I64Mul => Self::I64Mul,
2088 O::StructNew { struct_type_index } => Self::StructNew {
2089 struct_type_index: TypeIndex::from_u32(struct_type_index),
2090 },
2091 O::StructNewDefault { struct_type_index } => Self::StructNewDefault {
2092 struct_type_index: TypeIndex::from_u32(struct_type_index),
2093 },
2094 O::ArrayNew { array_type_index } => Self::ArrayNew {
2095 array_type_index: TypeIndex::from_u32(array_type_index),
2096 },
2097 O::ArrayNewDefault { array_type_index } => Self::ArrayNewDefault {
2098 array_type_index: TypeIndex::from_u32(array_type_index),
2099 },
2100 O::ArrayNewFixed {
2101 array_type_index,
2102 array_size,
2103 } => Self::ArrayNewFixed {
2104 array_type_index: TypeIndex::from_u32(array_type_index),
2105 array_size,
2106 },
2107 O::ExternConvertAny => Self::ExternConvertAny,
2108 O::AnyConvertExtern => Self::AnyConvertExtern,
2109 op => {
2110 return Err(wasm_unsupported!(
2111 "unsupported opcode in const expression at offset {offset:#x}: {op:?}",
2112 ));
2113 }
2114 })
2115 }
2116}
2117
2118#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2120#[expect(missing_docs, reason = "self-describing variants")]
2121pub enum IndexType {
2122 I32,
2123 I64,
2124}
2125
2126#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2128#[expect(missing_docs, reason = "self-describing fields")]
2129pub struct Limits {
2130 pub min: u64,
2131 pub max: Option<u64>,
2132}
2133
2134#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2136pub struct Table {
2137 pub idx_type: IndexType,
2139 pub limits: Limits,
2142 pub ref_type: WasmRefType,
2144}
2145
2146impl TypeTrace for Table {
2147 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2148 where
2149 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2150 {
2151 let Table {
2152 ref_type: wasm_ty,
2153 idx_type: _,
2154 limits: _,
2155 } = self;
2156 wasm_ty.trace(func)
2157 }
2158
2159 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2160 where
2161 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2162 {
2163 let Table {
2164 ref_type: wasm_ty,
2165 idx_type: _,
2166 limits: _,
2167 } = self;
2168 wasm_ty.trace_mut(func)
2169 }
2170}
2171
2172#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2174pub struct Memory {
2175 pub idx_type: IndexType,
2177 pub limits: Limits,
2180 pub shared: bool,
2182 pub page_size_log2: u8,
2187}
2188
2189pub const WASM32_MAX_SIZE: u64 = 1 << 32;
2191
2192impl Memory {
2193 pub const DEFAULT_PAGE_SIZE: u32 = 0x10000;
2195
2196 pub const DEFAULT_PAGE_SIZE_LOG2: u8 = {
2198 let log2 = 16;
2199 assert!(1 << log2 == Memory::DEFAULT_PAGE_SIZE);
2200 log2
2201 };
2202
2203 pub fn minimum_byte_size(&self) -> Result<u64, SizeOverflow> {
2211 self.limits
2212 .min
2213 .checked_mul(self.page_size())
2214 .ok_or(SizeOverflow)
2215 }
2216
2217 pub fn maximum_byte_size(&self) -> Result<u64, SizeOverflow> {
2232 match self.limits.max {
2233 Some(max) => max.checked_mul(self.page_size()).ok_or(SizeOverflow),
2234 None => {
2235 let min = self.minimum_byte_size()?;
2236 Ok(min.max(self.max_size_based_on_index_type()))
2237 }
2238 }
2239 }
2240
2241 pub fn page_size(&self) -> u64 {
2243 debug_assert!(
2244 self.page_size_log2 == 16 || self.page_size_log2 == 0,
2245 "invalid page_size_log2: {}; must be 16 or 0",
2246 self.page_size_log2
2247 );
2248 1 << self.page_size_log2
2249 }
2250
2251 pub fn max_size_based_on_index_type(&self) -> u64 {
2256 match self.idx_type {
2257 IndexType::I64 =>
2258 {
2266 0_u64.wrapping_sub(self.page_size())
2267 }
2268 IndexType::I32 => WASM32_MAX_SIZE,
2269 }
2270 }
2271
2272 pub fn can_use_virtual_memory(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
2284 tunables.signals_based_traps && self.page_size_log2 >= host_page_size_log2
2285 }
2286
2287 pub fn can_elide_bounds_check(
2307 &self,
2308 memory_tunables: &MemoryTunables<'_>,
2309 host_page_size_log2: u8,
2310 ) -> bool {
2311 self.can_use_virtual_memory(memory_tunables.tunables(), host_page_size_log2)
2312 && self.idx_type == IndexType::I32
2313 && memory_tunables.reservation() + memory_tunables.guard_size() >= (1 << 32)
2314 }
2315
2316 pub fn static_heap_size(&self) -> Option<u64> {
2320 let min = self.minimum_byte_size().ok()?;
2321 let max = self.maximum_byte_size().ok()?;
2322 if min == max { Some(min) } else { None }
2323 }
2324
2325 pub fn memory_may_move(&self, memory_tunables: &MemoryTunables<'_>) -> bool {
2332 if self.shared {
2336 return false;
2337 }
2338
2339 if !memory_tunables.may_move() {
2342 return false;
2343 }
2344
2345 if self.limits.max.is_some_and(|max| self.limits.min == max) {
2348 return false;
2349 }
2350
2351 let max = self.maximum_byte_size().unwrap_or(u64::MAX);
2354 max > memory_tunables.reservation()
2355 }
2356
2357 pub fn allow_growth_to(&self, size: usize) -> bool {
2367 if self.page_size_log2 != 0 {
2368 return true;
2369 }
2370 match self.idx_type {
2371 IndexType::I32 => size < 0xffff_ffff,
2380
2381 IndexType::I64 => true,
2384 }
2385 }
2386}
2387
2388#[derive(Copy, Clone, Debug)]
2389#[expect(missing_docs, reason = "self-describing error struct")]
2390pub struct SizeOverflow;
2391
2392impl fmt::Display for SizeOverflow {
2393 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2394 f.write_str("size overflow calculating memory size")
2395 }
2396}
2397
2398impl core::error::Error for SizeOverflow {}
2399
2400impl From<wasmparser::MemoryType> for Memory {
2401 fn from(ty: wasmparser::MemoryType) -> Memory {
2402 let idx_type = match ty.memory64 {
2403 false => IndexType::I32,
2404 true => IndexType::I64,
2405 };
2406 let limits = Limits {
2407 min: ty.initial,
2408 max: ty.maximum,
2409 };
2410 let page_size_log2 = u8::try_from(ty.page_size_log2.unwrap_or(16)).unwrap();
2411 debug_assert!(
2412 page_size_log2 == 16 || page_size_log2 == 0,
2413 "invalid page_size_log2: {page_size_log2}; must be 16 or 0"
2414 );
2415 Memory {
2416 idx_type,
2417 limits,
2418 shared: ty.shared,
2419 page_size_log2,
2420 }
2421 }
2422}
2423
2424#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2426pub struct Tag {
2427 pub signature: EngineOrModuleTypeIndex,
2429 pub exception: EngineOrModuleTypeIndex,
2431}
2432
2433impl TypeTrace for Tag {
2434 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2435 where
2436 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2437 {
2438 func(self.signature)?;
2439 func(self.exception)?;
2440 Ok(())
2441 }
2442
2443 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2444 where
2445 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2446 {
2447 func(&mut self.signature)?;
2448 func(&mut self.exception)?;
2449 Ok(())
2450 }
2451}
2452
2453#[expect(missing_docs, reason = "self-describing functions")]
2455pub trait TypeConvert {
2456 fn convert_global_type(&self, ty: &wasmparser::GlobalType) -> WasmResult<Global> {
2458 Ok(Global {
2459 wasm_ty: self.convert_valtype(ty.content_type)?,
2460 mutability: ty.mutable,
2461 })
2462 }
2463
2464 fn convert_table_type(&self, ty: &wasmparser::TableType) -> WasmResult<Table> {
2466 let idx_type = match ty.table64 {
2467 false => IndexType::I32,
2468 true => IndexType::I64,
2469 };
2470 let limits = Limits {
2471 min: ty.initial,
2472 max: ty.maximum,
2473 };
2474 Ok(Table {
2475 idx_type,
2476 limits,
2477 ref_type: self.convert_ref_type(ty.element_type)?,
2478 })
2479 }
2480
2481 fn convert_sub_type(&self, ty: &wasmparser::SubType) -> WasmResult<WasmSubType> {
2482 Ok(WasmSubType {
2483 is_final: ty.is_final,
2484 supertype: ty.supertype_idx.map(|i| self.lookup_type_index(i.unpack())),
2485 composite_type: self.convert_composite_type(&ty.composite_type)?,
2486 })
2487 }
2488
2489 fn convert_composite_type(
2490 &self,
2491 ty: &wasmparser::CompositeType,
2492 ) -> WasmResult<WasmCompositeType> {
2493 let inner = match &ty.inner {
2494 wasmparser::CompositeInnerType::Func(f) => {
2495 WasmCompositeInnerType::Func(self.convert_func_type(f)?)
2496 }
2497 wasmparser::CompositeInnerType::Array(a) => {
2498 WasmCompositeInnerType::Array(self.convert_array_type(a)?)
2499 }
2500 wasmparser::CompositeInnerType::Struct(s) => {
2501 WasmCompositeInnerType::Struct(self.convert_struct_type(s)?)
2502 }
2503 wasmparser::CompositeInnerType::Cont(c) => {
2504 WasmCompositeInnerType::Cont(self.convert_cont_type(c))
2505 }
2506 };
2507 Ok(WasmCompositeType {
2508 inner,
2509 shared: ty.shared,
2510 })
2511 }
2512
2513 fn convert_cont_type(&self, ty: &wasmparser::ContType) -> WasmContType {
2515 if let WasmHeapType::ConcreteFunc(sigidx) = self.lookup_heap_type(ty.0.unpack()) {
2516 WasmContType::new(sigidx)
2517 } else {
2518 panic!("Failed to extract signature index for continuation type.")
2519 }
2520 }
2521
2522 fn convert_struct_type(&self, ty: &wasmparser::StructType) -> WasmResult<WasmStructType> {
2523 Ok(WasmStructType {
2524 fields: ty
2525 .fields
2526 .iter()
2527 .map(|f| self.convert_field_type(f))
2528 .collect::<WasmResult<_>>()?,
2529 })
2530 }
2531
2532 fn convert_array_type(&self, ty: &wasmparser::ArrayType) -> WasmResult<WasmArrayType> {
2533 Ok(WasmArrayType(self.convert_field_type(&ty.0)?))
2534 }
2535
2536 fn convert_field_type(&self, ty: &wasmparser::FieldType) -> WasmResult<WasmFieldType> {
2537 Ok(WasmFieldType {
2538 element_type: self.convert_storage_type(&ty.element_type)?,
2539 mutable: ty.mutable,
2540 })
2541 }
2542
2543 fn convert_storage_type(&self, ty: &wasmparser::StorageType) -> WasmResult<WasmStorageType> {
2544 Ok(match ty {
2545 wasmparser::StorageType::I8 => WasmStorageType::I8,
2546 wasmparser::StorageType::I16 => WasmStorageType::I16,
2547 wasmparser::StorageType::Val(v) => WasmStorageType::Val(self.convert_valtype(*v)?),
2548 })
2549 }
2550
2551 fn convert_func_type(&self, ty: &wasmparser::FuncType) -> WasmResult<WasmFuncType> {
2553 let params = ty
2554 .params()
2555 .iter()
2556 .map(|t| self.convert_valtype(*t))
2557 .collect::<WasmResult<Vec<_>>>()?;
2558 let results = ty
2559 .results()
2560 .iter()
2561 .map(|t| self.convert_valtype(*t))
2562 .collect::<WasmResult<Vec<_>>>()?;
2563 Ok(WasmFuncType::new(params, results).panic_on_oom())
2564 }
2565
2566 fn convert_valtype(&self, ty: wasmparser::ValType) -> WasmResult<WasmValType> {
2568 Ok(match ty {
2569 wasmparser::ValType::I32 => WasmValType::I32,
2570 wasmparser::ValType::I64 => WasmValType::I64,
2571 wasmparser::ValType::F32 => WasmValType::F32,
2572 wasmparser::ValType::F64 => WasmValType::F64,
2573 wasmparser::ValType::V128 => WasmValType::V128,
2574 wasmparser::ValType::Ref(t) => WasmValType::Ref(self.convert_ref_type(t)?),
2575 })
2576 }
2577
2578 fn convert_ref_type(&self, ty: wasmparser::RefType) -> WasmResult<WasmRefType> {
2580 Ok(WasmRefType {
2581 nullable: ty.is_nullable(),
2582 heap_type: self.convert_heap_type(ty.heap_type())?,
2583 })
2584 }
2585
2586 fn convert_heap_type(&self, ty: wasmparser::HeapType) -> WasmResult<WasmHeapType> {
2588 Ok(match ty {
2589 wasmparser::HeapType::Concrete(i) => self.lookup_heap_type(i),
2590 wasmparser::HeapType::Abstract { ty, shared: false } => match ty {
2591 wasmparser::AbstractHeapType::Extern => WasmHeapType::Extern,
2592 wasmparser::AbstractHeapType::NoExtern => WasmHeapType::NoExtern,
2593 wasmparser::AbstractHeapType::Func => WasmHeapType::Func,
2594 wasmparser::AbstractHeapType::NoFunc => WasmHeapType::NoFunc,
2595 wasmparser::AbstractHeapType::Any => WasmHeapType::Any,
2596 wasmparser::AbstractHeapType::Eq => WasmHeapType::Eq,
2597 wasmparser::AbstractHeapType::I31 => WasmHeapType::I31,
2598 wasmparser::AbstractHeapType::Array => WasmHeapType::Array,
2599 wasmparser::AbstractHeapType::Struct => WasmHeapType::Struct,
2600 wasmparser::AbstractHeapType::None => WasmHeapType::None,
2601 wasmparser::AbstractHeapType::Cont => WasmHeapType::Cont,
2602 wasmparser::AbstractHeapType::NoCont => WasmHeapType::NoCont,
2603 wasmparser::AbstractHeapType::Exn => WasmHeapType::Exn,
2604 wasmparser::AbstractHeapType::NoExn => WasmHeapType::NoExn,
2605 },
2606 _ => return Err(wasm_unsupported!("unsupported heap type {ty:?}")),
2607 })
2608 }
2609
2610 fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType;
2613
2614 fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex;
2617}
2618
2619#[cfg(test)]
2620mod tests {
2621 use super::*;
2622
2623 #[test]
2624 fn wasm_func_type_new() -> Result<()> {
2625 let i32 = WasmValType::I32;
2626 let anyref = WasmValType::Ref(WasmRefType {
2627 nullable: true,
2628 heap_type: WasmHeapType::Any,
2629 });
2630 let ty = WasmFuncType::new([i32, i32, anyref, anyref], [i32, anyref])?;
2631 assert_eq!(ty.params(), &[i32, i32, anyref, anyref]);
2632 assert_eq!(ty.non_i31_gc_ref_params_count(), 2);
2633 assert_eq!(ty.results(), &[i32, anyref]);
2634 assert_eq!(ty.non_i31_gc_ref_results_count(), 1);
2635 Ok(())
2636 }
2637}