1use crate::{Tunables, WasmResult, wasm_unsupported};
2use alloc::borrow::Cow;
3use alloc::boxed::Box;
4use core::{fmt, ops::Range};
5use cranelift_entity::entity_impl;
6use serde_derive::{Deserialize, Serialize};
7use smallvec::SmallVec;
8
9pub trait TypeTrace {
12 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
16 where
17 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>;
18
19 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
25 where
26 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>;
27
28 fn trace_engine_indices<F, E>(&self, func: &mut F) -> Result<(), E>
30 where
31 F: FnMut(VMSharedTypeIndex) -> Result<(), E>,
32 {
33 self.trace(&mut |idx| match idx {
34 EngineOrModuleTypeIndex::Engine(idx) => func(idx),
35 EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
36 })
37 }
38
39 fn canonicalize_for_runtime_usage<F>(&mut self, module_to_engine: &mut F)
50 where
51 F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
52 {
53 self.trace_mut::<_, ()>(&mut |idx| match idx {
54 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
55 EngineOrModuleTypeIndex::Module(module_index) => {
56 let engine_index = module_to_engine(*module_index);
57 *idx = EngineOrModuleTypeIndex::Engine(engine_index);
58 Ok(())
59 }
60 EngineOrModuleTypeIndex::RecGroup(_) => {
61 panic!("should not already be canonicalized for hash consing")
62 }
63 })
64 .unwrap()
65 }
66
67 fn is_canonicalized_for_runtime_usage(&self) -> bool {
69 self.trace(&mut |idx| match idx {
70 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
71 EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Err(()),
72 })
73 .is_ok()
74 }
75
76 fn canonicalize_for_hash_consing<F>(
87 &mut self,
88 rec_group_range: Range<ModuleInternedTypeIndex>,
89 module_to_engine: &mut F,
90 ) where
91 F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
92 {
93 self.trace_mut::<_, ()>(&mut |idx| match *idx {
94 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
95 EngineOrModuleTypeIndex::Module(module_index) => {
96 *idx = if rec_group_range.start <= module_index {
97 debug_assert!(module_index < rec_group_range.end);
100 let relative = module_index.as_u32() - rec_group_range.start.as_u32();
101 let relative = RecGroupRelativeTypeIndex::from_u32(relative);
102 EngineOrModuleTypeIndex::RecGroup(relative)
103 } else {
104 debug_assert!(module_index < rec_group_range.start);
107 EngineOrModuleTypeIndex::Engine(module_to_engine(module_index))
108 };
109 Ok(())
110 }
111 EngineOrModuleTypeIndex::RecGroup(_) => {
112 panic!("should not already be canonicalized for hash consing")
113 }
114 })
115 .unwrap()
116 }
117
118 fn is_canonicalized_for_hash_consing(&self) -> bool {
120 self.trace(&mut |idx| match idx {
121 EngineOrModuleTypeIndex::Engine(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
122 EngineOrModuleTypeIndex::Module(_) => Err(()),
123 })
124 .is_ok()
125 }
126}
127
128#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
130pub enum WasmValType {
131 I32,
133 I64,
135 F32,
137 F64,
139 V128,
141 Ref(WasmRefType),
143}
144
145impl fmt::Display for WasmValType {
146 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
147 match self {
148 WasmValType::I32 => write!(f, "i32"),
149 WasmValType::I64 => write!(f, "i64"),
150 WasmValType::F32 => write!(f, "f32"),
151 WasmValType::F64 => write!(f, "f64"),
152 WasmValType::V128 => write!(f, "v128"),
153 WasmValType::Ref(rt) => write!(f, "{rt}"),
154 }
155 }
156}
157
158impl TypeTrace for WasmValType {
159 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
160 where
161 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
162 {
163 match self {
164 WasmValType::Ref(r) => r.trace(func),
165 WasmValType::I32
166 | WasmValType::I64
167 | WasmValType::F32
168 | WasmValType::F64
169 | WasmValType::V128 => Ok(()),
170 }
171 }
172
173 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
174 where
175 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
176 {
177 match self {
178 WasmValType::Ref(r) => r.trace_mut(func),
179 WasmValType::I32
180 | WasmValType::I64
181 | WasmValType::F32
182 | WasmValType::F64
183 | WasmValType::V128 => Ok(()),
184 }
185 }
186}
187
188impl WasmValType {
189 #[inline]
191 pub fn is_vmgcref_type(&self) -> bool {
192 match self {
193 WasmValType::Ref(r) => r.is_vmgcref_type(),
194 _ => false,
195 }
196 }
197
198 #[inline]
204 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
205 match self {
206 WasmValType::Ref(r) => r.is_vmgcref_type_and_not_i31(),
207 _ => false,
208 }
209 }
210
211 fn trampoline_type(&self) -> Self {
212 match self {
213 WasmValType::Ref(r) => WasmValType::Ref(WasmRefType {
214 nullable: true,
215 heap_type: r.heap_type.top().into(),
216 }),
217 WasmValType::I32
218 | WasmValType::I64
219 | WasmValType::F32
220 | WasmValType::F64
221 | WasmValType::V128 => *self,
222 }
223 }
224
225 pub fn int_from_bits(bits: u8) -> Self {
229 match bits {
230 32 => Self::I32,
231 64 => Self::I64,
232 size => panic!("invalid int bits for WasmValType: {size}"),
233 }
234 }
235
236 pub fn unwrap_ref_type(&self) -> WasmRefType {
240 match self {
241 WasmValType::Ref(ref_type) => *ref_type,
242 _ => panic!("Called WasmValType::unwrap_ref_type on non-reference type"),
243 }
244 }
245}
246
247#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
249pub struct WasmRefType {
250 pub nullable: bool,
252 pub heap_type: WasmHeapType,
254}
255
256impl TypeTrace for WasmRefType {
257 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
258 where
259 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
260 {
261 self.heap_type.trace(func)
262 }
263
264 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
265 where
266 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
267 {
268 self.heap_type.trace_mut(func)
269 }
270}
271
272impl WasmRefType {
273 pub const EXTERNREF: WasmRefType = WasmRefType {
275 nullable: true,
276 heap_type: WasmHeapType::Extern,
277 };
278 pub const FUNCREF: WasmRefType = WasmRefType {
280 nullable: true,
281 heap_type: WasmHeapType::Func,
282 };
283
284 #[inline]
286 pub fn is_vmgcref_type(&self) -> bool {
287 self.heap_type.is_vmgcref_type()
288 }
289
290 #[inline]
296 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
297 self.heap_type.is_vmgcref_type_and_not_i31()
298 }
299}
300
301impl fmt::Display for WasmRefType {
302 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
303 match *self {
304 Self::FUNCREF => write!(f, "funcref"),
305 Self::EXTERNREF => write!(f, "externref"),
306 _ => {
307 if self.nullable {
308 write!(f, "(ref null {})", self.heap_type)
309 } else {
310 write!(f, "(ref {})", self.heap_type)
311 }
312 }
313 }
314 }
315}
316
317#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
322pub enum EngineOrModuleTypeIndex {
323 Engine(VMSharedTypeIndex),
326
327 Module(ModuleInternedTypeIndex),
330
331 RecGroup(RecGroupRelativeTypeIndex),
335}
336
337impl From<ModuleInternedTypeIndex> for EngineOrModuleTypeIndex {
338 #[inline]
339 fn from(i: ModuleInternedTypeIndex) -> Self {
340 Self::Module(i)
341 }
342}
343
344impl From<VMSharedTypeIndex> for EngineOrModuleTypeIndex {
345 #[inline]
346 fn from(i: VMSharedTypeIndex) -> Self {
347 Self::Engine(i)
348 }
349}
350
351impl From<RecGroupRelativeTypeIndex> for EngineOrModuleTypeIndex {
352 #[inline]
353 fn from(i: RecGroupRelativeTypeIndex) -> Self {
354 Self::RecGroup(i)
355 }
356}
357
358impl fmt::Display for EngineOrModuleTypeIndex {
359 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360 match self {
361 Self::Engine(i) => write!(f, "(engine {})", i.bits()),
362 Self::Module(i) => write!(f, "(module {})", i.as_u32()),
363 Self::RecGroup(i) => write!(f, "(recgroup {})", i.as_u32()),
364 }
365 }
366}
367
368impl EngineOrModuleTypeIndex {
369 pub fn is_engine_type_index(self) -> bool {
371 matches!(self, Self::Engine(_))
372 }
373
374 pub fn as_engine_type_index(self) -> Option<VMSharedTypeIndex> {
376 match self {
377 Self::Engine(e) => Some(e),
378 Self::RecGroup(_) | Self::Module(_) => None,
379 }
380 }
381
382 #[track_caller]
384 pub fn unwrap_engine_type_index(self) -> VMSharedTypeIndex {
385 match self.as_engine_type_index() {
386 Some(x) => x,
387 None => panic!("`unwrap_engine_type_index` on {self:?}"),
388 }
389 }
390
391 pub fn is_module_type_index(self) -> bool {
393 matches!(self, Self::Module(_))
394 }
395
396 pub fn as_module_type_index(self) -> Option<ModuleInternedTypeIndex> {
398 match self {
399 Self::Module(e) => Some(e),
400 Self::RecGroup(_) | Self::Engine(_) => None,
401 }
402 }
403
404 #[track_caller]
406 pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
407 match self.as_module_type_index() {
408 Some(x) => x,
409 None => panic!("`unwrap_module_type_index` on {self:?}"),
410 }
411 }
412
413 pub fn is_rec_group_type_index(self) -> bool {
415 matches!(self, Self::RecGroup(_))
416 }
417
418 pub fn as_rec_group_type_index(self) -> Option<RecGroupRelativeTypeIndex> {
420 match self {
421 Self::RecGroup(r) => Some(r),
422 Self::Module(_) | Self::Engine(_) => None,
423 }
424 }
425
426 #[track_caller]
428 pub fn unwrap_rec_group_type_index(self) -> RecGroupRelativeTypeIndex {
429 match self.as_rec_group_type_index() {
430 Some(x) => x,
431 None => panic!("`unwrap_rec_group_type_index` on {self:?}"),
432 }
433 }
434}
435
436#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
438#[expect(missing_docs, reason = "self-describing variants")]
439pub enum WasmHeapType {
440 Extern,
442 NoExtern,
443
444 Func,
446 ConcreteFunc(EngineOrModuleTypeIndex),
447 NoFunc,
448
449 Exn,
451 ConcreteExn(EngineOrModuleTypeIndex),
452 NoExn,
453
454 Cont,
456 ConcreteCont(EngineOrModuleTypeIndex),
457 NoCont,
458
459 Any,
461 Eq,
462 I31,
463 Array,
464 ConcreteArray(EngineOrModuleTypeIndex),
465 Struct,
466 ConcreteStruct(EngineOrModuleTypeIndex),
467 None,
468}
469
470impl From<WasmHeapTopType> for WasmHeapType {
471 #[inline]
472 fn from(value: WasmHeapTopType) -> Self {
473 match value {
474 WasmHeapTopType::Extern => Self::Extern,
475 WasmHeapTopType::Any => Self::Any,
476 WasmHeapTopType::Func => Self::Func,
477 WasmHeapTopType::Cont => Self::Cont,
478 WasmHeapTopType::Exn => Self::Exn,
479 }
480 }
481}
482
483impl From<WasmHeapBottomType> for WasmHeapType {
484 #[inline]
485 fn from(value: WasmHeapBottomType) -> Self {
486 match value {
487 WasmHeapBottomType::NoExtern => Self::NoExtern,
488 WasmHeapBottomType::None => Self::None,
489 WasmHeapBottomType::NoFunc => Self::NoFunc,
490 WasmHeapBottomType::NoCont => Self::NoCont,
491 WasmHeapBottomType::NoExn => Self::NoExn,
492 }
493 }
494}
495
496impl fmt::Display for WasmHeapType {
497 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
498 match self {
499 Self::Extern => write!(f, "extern"),
500 Self::NoExtern => write!(f, "noextern"),
501 Self::Func => write!(f, "func"),
502 Self::ConcreteFunc(i) => write!(f, "func {i}"),
503 Self::NoFunc => write!(f, "nofunc"),
504 Self::Cont => write!(f, "cont"),
505 Self::ConcreteCont(i) => write!(f, "cont {i}"),
506 Self::NoCont => write!(f, "nocont"),
507 Self::Any => write!(f, "any"),
508 Self::Eq => write!(f, "eq"),
509 Self::I31 => write!(f, "i31"),
510 Self::Array => write!(f, "array"),
511 Self::ConcreteArray(i) => write!(f, "array {i}"),
512 Self::Struct => write!(f, "struct"),
513 Self::ConcreteStruct(i) => write!(f, "struct {i}"),
514 Self::Exn => write!(f, "exn"),
515 Self::ConcreteExn(i) => write!(f, "exn {i}"),
516 Self::NoExn => write!(f, "noexn"),
517 Self::None => write!(f, "none"),
518 }
519 }
520}
521
522impl TypeTrace for WasmHeapType {
523 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
524 where
525 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
526 {
527 match *self {
528 Self::ConcreteArray(i) => func(i),
529 Self::ConcreteFunc(i) => func(i),
530 Self::ConcreteStruct(i) => func(i),
531 Self::ConcreteCont(i) => func(i),
532 _ => Ok(()),
533 }
534 }
535
536 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
537 where
538 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
539 {
540 match self {
541 Self::ConcreteArray(i) => func(i),
542 Self::ConcreteFunc(i) => func(i),
543 Self::ConcreteStruct(i) => func(i),
544 Self::ConcreteCont(i) => func(i),
545 _ => Ok(()),
546 }
547 }
548}
549
550impl WasmHeapType {
551 #[inline]
553 pub fn is_vmgcref_type(&self) -> bool {
554 match self.top() {
555 WasmHeapTopType::Any | WasmHeapTopType::Extern | WasmHeapTopType::Exn => true,
559
560 WasmHeapTopType::Func => false,
562 WasmHeapTopType::Cont => false,
563 }
564 }
565
566 #[inline]
572 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
573 self.is_vmgcref_type() && *self != Self::I31
574 }
575
576 #[inline]
578 pub fn is_top(&self) -> bool {
579 *self == Self::from(self.top())
580 }
581
582 #[inline]
584 pub fn top(&self) -> WasmHeapTopType {
585 match self {
586 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapTopType::Extern,
587
588 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
589 WasmHeapTopType::Func
590 }
591
592 WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
593 WasmHeapTopType::Cont
594 }
595
596 WasmHeapType::Exn | WasmHeapType::ConcreteExn(_) | WasmHeapType::NoExn => {
597 WasmHeapTopType::Exn
598 }
599
600 WasmHeapType::Any
601 | WasmHeapType::Eq
602 | WasmHeapType::I31
603 | WasmHeapType::Array
604 | WasmHeapType::ConcreteArray(_)
605 | WasmHeapType::Struct
606 | WasmHeapType::ConcreteStruct(_)
607 | WasmHeapType::None => WasmHeapTopType::Any,
608 }
609 }
610
611 #[inline]
613 pub fn is_bottom(&self) -> bool {
614 *self == Self::from(self.bottom())
615 }
616
617 #[inline]
619 pub fn bottom(&self) -> WasmHeapBottomType {
620 match self {
621 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapBottomType::NoExtern,
622
623 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
624 WasmHeapBottomType::NoFunc
625 }
626
627 WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
628 WasmHeapBottomType::NoCont
629 }
630
631 WasmHeapType::Exn | WasmHeapType::ConcreteExn(_) | WasmHeapType::NoExn => {
632 WasmHeapBottomType::NoExn
633 }
634
635 WasmHeapType::Any
636 | WasmHeapType::Eq
637 | WasmHeapType::I31
638 | WasmHeapType::Array
639 | WasmHeapType::ConcreteArray(_)
640 | WasmHeapType::Struct
641 | WasmHeapType::ConcreteStruct(_)
642 | WasmHeapType::None => WasmHeapBottomType::None,
643 }
644 }
645}
646
647#[derive(Debug, Clone, Copy, Eq, PartialEq)]
649pub enum WasmHeapTopType {
650 Extern,
652 Any,
654 Func,
656 Exn,
658 Cont,
660}
661
662#[derive(Debug, Clone, Copy, Eq, PartialEq)]
664pub enum WasmHeapBottomType {
665 NoExtern,
667 None,
669 NoFunc,
671 NoExn,
673 NoCont,
675}
676
677#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
679pub struct WasmFuncType {
680 params: Box<[WasmValType]>,
681 non_i31_gc_ref_params_count: usize,
682 returns: Box<[WasmValType]>,
683 non_i31_gc_ref_returns_count: usize,
684}
685
686impl fmt::Display for WasmFuncType {
687 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
688 write!(f, "(func")?;
689 if !self.params.is_empty() {
690 write!(f, " (param")?;
691 for p in self.params.iter() {
692 write!(f, " {p}")?;
693 }
694 write!(f, ")")?;
695 }
696 if !self.returns.is_empty() {
697 write!(f, " (result")?;
698 for r in self.returns.iter() {
699 write!(f, " {r}")?;
700 }
701 write!(f, ")")?;
702 }
703 write!(f, ")")
704 }
705}
706
707impl TypeTrace for WasmFuncType {
708 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
709 where
710 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
711 {
712 for p in self.params.iter() {
713 p.trace(func)?;
714 }
715 for r in self.returns.iter() {
716 r.trace(func)?;
717 }
718 Ok(())
719 }
720
721 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
722 where
723 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
724 {
725 for p in self.params.iter_mut() {
726 p.trace_mut(func)?;
727 }
728 for r in self.returns.iter_mut() {
729 r.trace_mut(func)?;
730 }
731 Ok(())
732 }
733}
734
735impl WasmFuncType {
736 #[inline]
738 pub fn new(params: Box<[WasmValType]>, returns: Box<[WasmValType]>) -> Self {
739 let non_i31_gc_ref_params_count = params
740 .iter()
741 .filter(|p| p.is_vmgcref_type_and_not_i31())
742 .count();
743 let non_i31_gc_ref_returns_count = returns
744 .iter()
745 .filter(|r| r.is_vmgcref_type_and_not_i31())
746 .count();
747 WasmFuncType {
748 params,
749 non_i31_gc_ref_params_count,
750 returns,
751 non_i31_gc_ref_returns_count,
752 }
753 }
754
755 #[inline]
757 pub fn params(&self) -> &[WasmValType] {
758 &self.params
759 }
760
761 #[inline]
763 pub fn non_i31_gc_ref_params_count(&self) -> usize {
764 self.non_i31_gc_ref_params_count
765 }
766
767 #[inline]
769 pub fn returns(&self) -> &[WasmValType] {
770 &self.returns
771 }
772
773 #[inline]
775 pub fn non_i31_gc_ref_returns_count(&self) -> usize {
776 self.non_i31_gc_ref_returns_count
777 }
778
779 pub fn is_trampoline_type(&self) -> bool {
781 self.params().iter().all(|p| *p == p.trampoline_type())
782 && self.returns().iter().all(|r| *r == r.trampoline_type())
783 }
784
785 pub fn trampoline_type(&self) -> Cow<'_, Self> {
811 if self.is_trampoline_type() {
812 return Cow::Borrowed(self);
813 }
814
815 Cow::Owned(Self::new(
816 self.params().iter().map(|p| p.trampoline_type()).collect(),
817 self.returns().iter().map(|r| r.trampoline_type()).collect(),
818 ))
819 }
820}
821
822#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
824pub struct WasmContType(EngineOrModuleTypeIndex);
825
826impl fmt::Display for WasmContType {
827 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
828 write!(f, "(cont {})", self.0)
829 }
830}
831
832impl WasmContType {
833 pub fn new(idx: EngineOrModuleTypeIndex) -> Self {
835 WasmContType(idx)
836 }
837
838 pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
840 match self.0 {
841 EngineOrModuleTypeIndex::Engine(_) => panic!("not module interned"),
842 EngineOrModuleTypeIndex::Module(idx) => idx,
843 EngineOrModuleTypeIndex::RecGroup(_) => todo!(),
844 }
845 }
846}
847
848impl TypeTrace for WasmContType {
849 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
850 where
851 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
852 {
853 func(self.0)
854 }
855
856 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
857 where
858 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
859 {
860 func(&mut self.0)
861 }
862}
863
864#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
889pub struct WasmExnType {
890 pub func_ty: EngineOrModuleTypeIndex,
894 pub fields: Box<[WasmFieldType]>,
901}
902
903impl fmt::Display for WasmExnType {
904 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
905 write!(f, "(exn ({})", self.func_ty)?;
906 for ty in self.fields.iter() {
907 write!(f, " {ty}")?;
908 }
909 write!(f, ")")
910 }
911}
912
913impl TypeTrace for WasmExnType {
914 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
915 where
916 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
917 {
918 func(self.func_ty)?;
919 for f in self.fields.iter() {
920 f.trace(func)?;
921 }
922 Ok(())
923 }
924
925 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
926 where
927 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
928 {
929 func(&mut self.func_ty)?;
930 for f in self.fields.iter_mut() {
931 f.trace_mut(func)?;
932 }
933 Ok(())
934 }
935}
936
937#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
939pub enum WasmStorageType {
940 I8,
942 I16,
944 Val(WasmValType),
946}
947
948impl fmt::Display for WasmStorageType {
949 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
950 match self {
951 WasmStorageType::I8 => write!(f, "i8"),
952 WasmStorageType::I16 => write!(f, "i16"),
953 WasmStorageType::Val(v) => fmt::Display::fmt(v, f),
954 }
955 }
956}
957
958impl TypeTrace for WasmStorageType {
959 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
960 where
961 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
962 {
963 match self {
964 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
965 WasmStorageType::Val(v) => v.trace(func),
966 }
967 }
968
969 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
970 where
971 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
972 {
973 match self {
974 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
975 WasmStorageType::Val(v) => v.trace_mut(func),
976 }
977 }
978}
979
980impl WasmStorageType {
981 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
987 match self {
988 WasmStorageType::I8 | WasmStorageType::I16 => false,
989 WasmStorageType::Val(v) => v.is_vmgcref_type_and_not_i31(),
990 }
991 }
992}
993
994#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
996pub struct WasmFieldType {
997 pub element_type: WasmStorageType,
999
1000 pub mutable: bool,
1002}
1003
1004impl fmt::Display for WasmFieldType {
1005 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1006 if self.mutable {
1007 write!(f, "(mut {})", self.element_type)
1008 } else {
1009 fmt::Display::fmt(&self.element_type, f)
1010 }
1011 }
1012}
1013
1014impl TypeTrace for WasmFieldType {
1015 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1016 where
1017 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1018 {
1019 self.element_type.trace(func)
1020 }
1021
1022 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1023 where
1024 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1025 {
1026 self.element_type.trace_mut(func)
1027 }
1028}
1029
1030#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1032pub struct WasmArrayType(pub WasmFieldType);
1033
1034impl fmt::Display for WasmArrayType {
1035 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1036 write!(f, "(array {})", self.0)
1037 }
1038}
1039
1040impl TypeTrace for WasmArrayType {
1041 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1042 where
1043 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1044 {
1045 self.0.trace(func)
1046 }
1047
1048 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1049 where
1050 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1051 {
1052 self.0.trace_mut(func)
1053 }
1054}
1055
1056#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1058pub struct WasmStructType {
1059 pub fields: Box<[WasmFieldType]>,
1061}
1062
1063impl fmt::Display for WasmStructType {
1064 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1065 write!(f, "(struct")?;
1066 for ty in self.fields.iter() {
1067 write!(f, " {ty}")?;
1068 }
1069 write!(f, ")")
1070 }
1071}
1072
1073impl TypeTrace for WasmStructType {
1074 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1075 where
1076 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1077 {
1078 for f in self.fields.iter() {
1079 f.trace(func)?;
1080 }
1081 Ok(())
1082 }
1083
1084 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1085 where
1086 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1087 {
1088 for f in self.fields.iter_mut() {
1089 f.trace_mut(func)?;
1090 }
1091 Ok(())
1092 }
1093}
1094
1095#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1096#[expect(missing_docs, reason = "self-describing type")]
1097pub struct WasmCompositeType {
1098 pub inner: WasmCompositeInnerType,
1100 pub shared: bool,
1103}
1104
1105impl fmt::Display for WasmCompositeType {
1106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1107 if self.shared {
1108 write!(f, "(shared ")?;
1109 }
1110 fmt::Display::fmt(&self.inner, f)?;
1111 if self.shared {
1112 write!(f, ")")?;
1113 }
1114 Ok(())
1115 }
1116}
1117
1118#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1120#[expect(missing_docs, reason = "self-describing variants")]
1121pub enum WasmCompositeInnerType {
1122 Array(WasmArrayType),
1123 Func(WasmFuncType),
1124 Struct(WasmStructType),
1125 Cont(WasmContType),
1126 Exn(WasmExnType),
1127}
1128
1129impl fmt::Display for WasmCompositeInnerType {
1130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1131 match self {
1132 Self::Array(ty) => fmt::Display::fmt(ty, f),
1133 Self::Func(ty) => fmt::Display::fmt(ty, f),
1134 Self::Struct(ty) => fmt::Display::fmt(ty, f),
1135 Self::Cont(ty) => fmt::Display::fmt(ty, f),
1136 Self::Exn(ty) => fmt::Display::fmt(ty, f),
1137 }
1138 }
1139}
1140
1141#[expect(missing_docs, reason = "self-describing functions")]
1142impl WasmCompositeInnerType {
1143 #[inline]
1144 pub fn is_array(&self) -> bool {
1145 matches!(self, Self::Array(_))
1146 }
1147
1148 #[inline]
1149 pub fn as_array(&self) -> Option<&WasmArrayType> {
1150 match self {
1151 Self::Array(f) => Some(f),
1152 _ => None,
1153 }
1154 }
1155
1156 #[inline]
1157 pub fn unwrap_array(&self) -> &WasmArrayType {
1158 self.as_array().unwrap()
1159 }
1160
1161 #[inline]
1162 pub fn is_func(&self) -> bool {
1163 matches!(self, Self::Func(_))
1164 }
1165
1166 #[inline]
1167 pub fn as_func(&self) -> Option<&WasmFuncType> {
1168 match self {
1169 Self::Func(f) => Some(f),
1170 _ => None,
1171 }
1172 }
1173
1174 #[inline]
1175 pub fn unwrap_func(&self) -> &WasmFuncType {
1176 self.as_func().unwrap()
1177 }
1178
1179 #[inline]
1180 pub fn is_struct(&self) -> bool {
1181 matches!(self, Self::Struct(_))
1182 }
1183
1184 #[inline]
1185 pub fn as_struct(&self) -> Option<&WasmStructType> {
1186 match self {
1187 Self::Struct(f) => Some(f),
1188 _ => None,
1189 }
1190 }
1191
1192 #[inline]
1193 pub fn unwrap_struct(&self) -> &WasmStructType {
1194 self.as_struct().unwrap()
1195 }
1196
1197 #[inline]
1198 pub fn is_cont(&self) -> bool {
1199 matches!(self, Self::Cont(_))
1200 }
1201
1202 #[inline]
1203 pub fn as_cont(&self) -> Option<&WasmContType> {
1204 match self {
1205 Self::Cont(f) => Some(f),
1206 _ => None,
1207 }
1208 }
1209
1210 #[inline]
1211 pub fn unwrap_cont(&self) -> &WasmContType {
1212 self.as_cont().unwrap()
1213 }
1214
1215 #[inline]
1216 pub fn is_exn(&self) -> bool {
1217 matches!(self, Self::Exn(_))
1218 }
1219
1220 #[inline]
1221 pub fn as_exn(&self) -> Option<&WasmExnType> {
1222 match self {
1223 Self::Exn(f) => Some(f),
1224 _ => None,
1225 }
1226 }
1227
1228 #[inline]
1229 pub fn unwrap_exn(&self) -> &WasmExnType {
1230 self.as_exn().unwrap()
1231 }
1232}
1233
1234impl TypeTrace for WasmCompositeType {
1235 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1236 where
1237 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1238 {
1239 match &self.inner {
1240 WasmCompositeInnerType::Array(a) => a.trace(func),
1241 WasmCompositeInnerType::Func(f) => f.trace(func),
1242 WasmCompositeInnerType::Struct(a) => a.trace(func),
1243 WasmCompositeInnerType::Cont(c) => c.trace(func),
1244 WasmCompositeInnerType::Exn(e) => e.trace(func),
1245 }
1246 }
1247
1248 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1249 where
1250 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1251 {
1252 match &mut self.inner {
1253 WasmCompositeInnerType::Array(a) => a.trace_mut(func),
1254 WasmCompositeInnerType::Func(f) => f.trace_mut(func),
1255 WasmCompositeInnerType::Struct(a) => a.trace_mut(func),
1256 WasmCompositeInnerType::Cont(c) => c.trace_mut(func),
1257 WasmCompositeInnerType::Exn(e) => e.trace_mut(func),
1258 }
1259 }
1260}
1261
1262#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1264pub struct WasmSubType {
1265 pub is_final: bool,
1268
1269 pub supertype: Option<EngineOrModuleTypeIndex>,
1271
1272 pub composite_type: WasmCompositeType,
1274}
1275
1276impl fmt::Display for WasmSubType {
1277 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1278 if self.is_final && self.supertype.is_none() {
1279 fmt::Display::fmt(&self.composite_type, f)
1280 } else {
1281 write!(f, "(sub")?;
1282 if self.is_final {
1283 write!(f, " final")?;
1284 }
1285 if let Some(sup) = self.supertype {
1286 write!(f, " {sup}")?;
1287 }
1288 write!(f, " {})", self.composite_type)
1289 }
1290 }
1291}
1292
1293#[expect(missing_docs, reason = "self-describing functions")]
1297impl WasmSubType {
1298 #[inline]
1299 pub fn is_func(&self) -> bool {
1300 self.composite_type.inner.is_func() && !self.composite_type.shared
1301 }
1302
1303 #[inline]
1304 pub fn as_func(&self) -> Option<&WasmFuncType> {
1305 if self.composite_type.shared {
1306 None
1307 } else {
1308 self.composite_type.inner.as_func()
1309 }
1310 }
1311
1312 #[inline]
1313 pub fn unwrap_func(&self) -> &WasmFuncType {
1314 assert!(!self.composite_type.shared);
1315 self.composite_type.inner.unwrap_func()
1316 }
1317
1318 #[inline]
1319 pub fn is_array(&self) -> bool {
1320 self.composite_type.inner.is_array() && !self.composite_type.shared
1321 }
1322
1323 #[inline]
1324 pub fn as_array(&self) -> Option<&WasmArrayType> {
1325 if self.composite_type.shared {
1326 None
1327 } else {
1328 self.composite_type.inner.as_array()
1329 }
1330 }
1331
1332 #[inline]
1333 pub fn unwrap_array(&self) -> &WasmArrayType {
1334 assert!(!self.composite_type.shared);
1335 self.composite_type.inner.unwrap_array()
1336 }
1337
1338 #[inline]
1339 pub fn is_struct(&self) -> bool {
1340 self.composite_type.inner.is_struct() && !self.composite_type.shared
1341 }
1342
1343 #[inline]
1344 pub fn as_struct(&self) -> Option<&WasmStructType> {
1345 if self.composite_type.shared {
1346 None
1347 } else {
1348 self.composite_type.inner.as_struct()
1349 }
1350 }
1351
1352 #[inline]
1353 pub fn unwrap_struct(&self) -> &WasmStructType {
1354 assert!(!self.composite_type.shared);
1355 self.composite_type.inner.unwrap_struct()
1356 }
1357
1358 #[inline]
1359 pub fn is_cont(&self) -> bool {
1360 self.composite_type.inner.is_cont() && !self.composite_type.shared
1361 }
1362
1363 #[inline]
1364 pub fn as_cont(&self) -> Option<&WasmContType> {
1365 if self.composite_type.shared {
1366 None
1367 } else {
1368 self.composite_type.inner.as_cont()
1369 }
1370 }
1371
1372 #[inline]
1373 pub fn unwrap_cont(&self) -> &WasmContType {
1374 assert!(!self.composite_type.shared);
1375 self.composite_type.inner.unwrap_cont()
1376 }
1377
1378 #[inline]
1379 pub fn is_exn(&self) -> bool {
1380 self.composite_type.inner.is_exn() && !self.composite_type.shared
1381 }
1382
1383 #[inline]
1384 pub fn as_exn(&self) -> Option<&WasmExnType> {
1385 if self.composite_type.shared {
1386 None
1387 } else {
1388 self.composite_type.inner.as_exn()
1389 }
1390 }
1391
1392 #[inline]
1393 pub fn unwrap_exn(&self) -> &WasmExnType {
1394 assert!(!self.composite_type.shared);
1395 self.composite_type.inner.unwrap_exn()
1396 }
1397}
1398
1399impl TypeTrace for WasmSubType {
1400 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1401 where
1402 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1403 {
1404 if let Some(sup) = self.supertype {
1405 func(sup)?;
1406 }
1407 self.composite_type.trace(func)
1408 }
1409
1410 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1411 where
1412 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1413 {
1414 if let Some(sup) = self.supertype.as_mut() {
1415 func(sup)?;
1416 }
1417 self.composite_type.trace_mut(func)
1418 }
1419}
1420
1421#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1432pub struct WasmRecGroup {
1433 pub types: Box<[WasmSubType]>,
1435}
1436
1437impl TypeTrace for WasmRecGroup {
1438 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1439 where
1440 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1441 {
1442 for ty in self.types.iter() {
1443 ty.trace(func)?;
1444 }
1445 Ok(())
1446 }
1447
1448 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1449 where
1450 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1451 {
1452 for ty in self.types.iter_mut() {
1453 ty.trace_mut(func)?;
1454 }
1455 Ok(())
1456 }
1457}
1458
1459#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1461pub struct FuncIndex(u32);
1462entity_impl!(FuncIndex);
1463
1464#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1466pub struct DefinedFuncIndex(u32);
1467entity_impl!(DefinedFuncIndex);
1468
1469#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1471pub struct DefinedTableIndex(u32);
1472entity_impl!(DefinedTableIndex);
1473
1474#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1476pub struct DefinedMemoryIndex(u32);
1477entity_impl!(DefinedMemoryIndex);
1478
1479#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1481pub struct OwnedMemoryIndex(u32);
1482entity_impl!(OwnedMemoryIndex);
1483
1484#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1486pub struct DefinedGlobalIndex(u32);
1487entity_impl!(DefinedGlobalIndex);
1488
1489#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1491pub struct TableIndex(u32);
1492entity_impl!(TableIndex);
1493
1494#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1496pub struct GlobalIndex(u32);
1497entity_impl!(GlobalIndex);
1498
1499#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1501pub struct MemoryIndex(u32);
1502entity_impl!(MemoryIndex);
1503
1504#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1507pub struct ModuleInternedRecGroupIndex(u32);
1508entity_impl!(ModuleInternedRecGroupIndex);
1509
1510#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1513pub struct EngineInternedRecGroupIndex(u32);
1514entity_impl!(EngineInternedRecGroupIndex);
1515
1516#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1518pub struct TypeIndex(u32);
1519entity_impl!(TypeIndex);
1520
1521#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1527pub struct RecGroupRelativeTypeIndex(u32);
1528entity_impl!(RecGroupRelativeTypeIndex);
1529
1530#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1538pub struct ModuleInternedTypeIndex(u32);
1539entity_impl!(ModuleInternedTypeIndex);
1540
1541#[repr(transparent)] #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1550pub struct VMSharedTypeIndex(u32);
1551entity_impl!(VMSharedTypeIndex);
1552
1553impl VMSharedTypeIndex {
1554 #[inline]
1556 pub fn new(value: u32) -> Self {
1557 assert_ne!(
1558 value,
1559 u32::MAX,
1560 "u32::MAX is reserved for the default value"
1561 );
1562 Self(value)
1563 }
1564
1565 #[inline]
1567 pub fn bits(&self) -> u32 {
1568 self.0
1569 }
1570}
1571
1572impl Default for VMSharedTypeIndex {
1573 #[inline]
1574 fn default() -> Self {
1575 Self(u32::MAX)
1576 }
1577}
1578
1579#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1581pub struct DataIndex(u32);
1582entity_impl!(DataIndex);
1583
1584#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1586pub struct ElemIndex(u32);
1587entity_impl!(ElemIndex);
1588
1589#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1591pub struct DefinedTagIndex(u32);
1592entity_impl!(DefinedTagIndex);
1593
1594#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1596pub struct TagIndex(u32);
1597entity_impl!(TagIndex);
1598
1599#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1604pub struct StaticModuleIndex(u32);
1605entity_impl!(StaticModuleIndex);
1606
1607#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1609pub enum EntityIndex {
1610 Function(FuncIndex),
1612 Table(TableIndex),
1614 Memory(MemoryIndex),
1616 Global(GlobalIndex),
1618 Tag(TagIndex),
1620}
1621
1622impl From<FuncIndex> for EntityIndex {
1623 fn from(idx: FuncIndex) -> EntityIndex {
1624 EntityIndex::Function(idx)
1625 }
1626}
1627
1628impl From<TableIndex> for EntityIndex {
1629 fn from(idx: TableIndex) -> EntityIndex {
1630 EntityIndex::Table(idx)
1631 }
1632}
1633
1634impl From<MemoryIndex> for EntityIndex {
1635 fn from(idx: MemoryIndex) -> EntityIndex {
1636 EntityIndex::Memory(idx)
1637 }
1638}
1639
1640impl From<GlobalIndex> for EntityIndex {
1641 fn from(idx: GlobalIndex) -> EntityIndex {
1642 EntityIndex::Global(idx)
1643 }
1644}
1645
1646impl From<TagIndex> for EntityIndex {
1647 fn from(idx: TagIndex) -> EntityIndex {
1648 EntityIndex::Tag(idx)
1649 }
1650}
1651
1652#[derive(Clone, Debug, Serialize, Deserialize)]
1655pub enum EntityType {
1656 Global(Global),
1658 Memory(Memory),
1660 Tag(Tag),
1662 Table(Table),
1664 Function(EngineOrModuleTypeIndex),
1667}
1668
1669impl TypeTrace for EntityType {
1670 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1671 where
1672 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1673 {
1674 match self {
1675 Self::Global(g) => g.trace(func),
1676 Self::Table(t) => t.trace(func),
1677 Self::Function(idx) => func(*idx),
1678 Self::Memory(_) => Ok(()),
1679 Self::Tag(t) => t.trace(func),
1680 }
1681 }
1682
1683 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1684 where
1685 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1686 {
1687 match self {
1688 Self::Global(g) => g.trace_mut(func),
1689 Self::Table(t) => t.trace_mut(func),
1690 Self::Function(idx) => func(idx),
1691 Self::Memory(_) => Ok(()),
1692 Self::Tag(t) => t.trace_mut(func),
1693 }
1694 }
1695}
1696
1697impl EntityType {
1698 pub fn unwrap_global(&self) -> &Global {
1700 match self {
1701 EntityType::Global(g) => g,
1702 _ => panic!("not a global"),
1703 }
1704 }
1705
1706 pub fn unwrap_memory(&self) -> &Memory {
1708 match self {
1709 EntityType::Memory(g) => g,
1710 _ => panic!("not a memory"),
1711 }
1712 }
1713
1714 pub fn unwrap_tag(&self) -> &Tag {
1716 match self {
1717 EntityType::Tag(g) => g,
1718 _ => panic!("not a tag"),
1719 }
1720 }
1721
1722 pub fn unwrap_table(&self) -> &Table {
1724 match self {
1725 EntityType::Table(g) => g,
1726 _ => panic!("not a table"),
1727 }
1728 }
1729
1730 pub fn unwrap_func(&self) -> EngineOrModuleTypeIndex {
1732 match self {
1733 EntityType::Function(g) => *g,
1734 _ => panic!("not a func"),
1735 }
1736 }
1737}
1738
1739#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1747pub struct Global {
1748 pub wasm_ty: crate::WasmValType,
1750 pub mutability: bool,
1752}
1753
1754impl TypeTrace for Global {
1755 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1756 where
1757 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1758 {
1759 let Global {
1760 wasm_ty,
1761 mutability: _,
1762 } = self;
1763 wasm_ty.trace(func)
1764 }
1765
1766 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1767 where
1768 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1769 {
1770 let Global {
1771 wasm_ty,
1772 mutability: _,
1773 } = self;
1774 wasm_ty.trace_mut(func)
1775 }
1776}
1777
1778#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1782pub struct ConstExpr {
1783 ops: SmallVec<[ConstOp; 2]>,
1784}
1785
1786impl ConstExpr {
1787 pub fn new(ops: impl IntoIterator<Item = ConstOp>) -> Self {
1793 let ops = ops.into_iter().collect::<SmallVec<[ConstOp; 2]>>();
1794 assert!(!ops.is_empty());
1795 ConstExpr { ops }
1796 }
1797
1798 pub fn from_wasmparser(
1803 expr: wasmparser::ConstExpr<'_>,
1804 ) -> WasmResult<(Self, SmallVec<[FuncIndex; 1]>)> {
1805 let mut iter = expr
1806 .get_operators_reader()
1807 .into_iter_with_offsets()
1808 .peekable();
1809
1810 let mut ops = SmallVec::<[ConstOp; 2]>::new();
1811 let mut escaped = SmallVec::<[FuncIndex; 1]>::new();
1812 while let Some(res) = iter.next() {
1813 let (op, offset) = res?;
1814
1815 if matches!(op, wasmparser::Operator::End) && iter.peek().is_none() {
1819 break;
1820 }
1821
1822 if let wasmparser::Operator::RefFunc { function_index } = &op {
1825 escaped.push(FuncIndex::from_u32(*function_index));
1826 }
1827
1828 ops.push(ConstOp::from_wasmparser(op, offset)?);
1829 }
1830 Ok((Self { ops }, escaped))
1831 }
1832
1833 pub fn ops(&self) -> &[ConstOp] {
1835 &self.ops
1836 }
1837
1838 pub fn provably_nonzero_i32(&self) -> bool {
1848 assert!(self.ops.len() > 0);
1849 if self.ops.len() > 1 {
1850 return false;
1853 }
1854 match self.ops[0] {
1856 ConstOp::I32Const(0) => false,
1858 ConstOp::I32Const(_) => true,
1861 _ => false,
1863 }
1864 }
1865}
1866
1867#[expect(missing_docs, reason = "self-describing variants")]
1869#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1870pub enum ConstOp {
1871 I32Const(i32),
1872 I64Const(i64),
1873 F32Const(u32),
1874 F64Const(u64),
1875 V128Const(u128),
1876 GlobalGet(GlobalIndex),
1877 RefI31,
1878 RefNull,
1879 RefFunc(FuncIndex),
1880 I32Add,
1881 I32Sub,
1882 I32Mul,
1883 I64Add,
1884 I64Sub,
1885 I64Mul,
1886 StructNew {
1887 struct_type_index: TypeIndex,
1888 },
1889 StructNewDefault {
1890 struct_type_index: TypeIndex,
1891 },
1892 ArrayNew {
1893 array_type_index: TypeIndex,
1894 },
1895 ArrayNewDefault {
1896 array_type_index: TypeIndex,
1897 },
1898 ArrayNewFixed {
1899 array_type_index: TypeIndex,
1900 array_size: u32,
1901 },
1902 ExternConvertAny,
1903 AnyConvertExtern,
1904}
1905
1906impl ConstOp {
1907 pub fn from_wasmparser(op: wasmparser::Operator<'_>, offset: usize) -> WasmResult<Self> {
1909 use wasmparser::Operator as O;
1910 Ok(match op {
1911 O::I32Const { value } => Self::I32Const(value),
1912 O::I64Const { value } => Self::I64Const(value),
1913 O::F32Const { value } => Self::F32Const(value.bits()),
1914 O::F64Const { value } => Self::F64Const(value.bits()),
1915 O::V128Const { value } => Self::V128Const(u128::from_le_bytes(*value.bytes())),
1916 O::RefNull { hty: _ } => Self::RefNull,
1917 O::RefFunc { function_index } => Self::RefFunc(FuncIndex::from_u32(function_index)),
1918 O::GlobalGet { global_index } => Self::GlobalGet(GlobalIndex::from_u32(global_index)),
1919 O::RefI31 => Self::RefI31,
1920 O::I32Add => Self::I32Add,
1921 O::I32Sub => Self::I32Sub,
1922 O::I32Mul => Self::I32Mul,
1923 O::I64Add => Self::I64Add,
1924 O::I64Sub => Self::I64Sub,
1925 O::I64Mul => Self::I64Mul,
1926 O::StructNew { struct_type_index } => Self::StructNew {
1927 struct_type_index: TypeIndex::from_u32(struct_type_index),
1928 },
1929 O::StructNewDefault { struct_type_index } => Self::StructNewDefault {
1930 struct_type_index: TypeIndex::from_u32(struct_type_index),
1931 },
1932 O::ArrayNew { array_type_index } => Self::ArrayNew {
1933 array_type_index: TypeIndex::from_u32(array_type_index),
1934 },
1935 O::ArrayNewDefault { array_type_index } => Self::ArrayNewDefault {
1936 array_type_index: TypeIndex::from_u32(array_type_index),
1937 },
1938 O::ArrayNewFixed {
1939 array_type_index,
1940 array_size,
1941 } => Self::ArrayNewFixed {
1942 array_type_index: TypeIndex::from_u32(array_type_index),
1943 array_size,
1944 },
1945 O::ExternConvertAny => Self::ExternConvertAny,
1946 O::AnyConvertExtern => Self::AnyConvertExtern,
1947 op => {
1948 return Err(wasm_unsupported!(
1949 "unsupported opcode in const expression at offset {offset:#x}: {op:?}",
1950 ));
1951 }
1952 })
1953 }
1954}
1955
1956#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1958#[expect(missing_docs, reason = "self-describing variants")]
1959pub enum IndexType {
1960 I32,
1961 I64,
1962}
1963
1964#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1966#[expect(missing_docs, reason = "self-describing fields")]
1967pub struct Limits {
1968 pub min: u64,
1969 pub max: Option<u64>,
1970}
1971
1972#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1974pub struct Table {
1975 pub idx_type: IndexType,
1977 pub limits: Limits,
1980 pub ref_type: WasmRefType,
1982}
1983
1984impl TypeTrace for Table {
1985 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1986 where
1987 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1988 {
1989 let Table {
1990 ref_type: wasm_ty,
1991 idx_type: _,
1992 limits: _,
1993 } = self;
1994 wasm_ty.trace(func)
1995 }
1996
1997 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1998 where
1999 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2000 {
2001 let Table {
2002 ref_type: wasm_ty,
2003 idx_type: _,
2004 limits: _,
2005 } = self;
2006 wasm_ty.trace_mut(func)
2007 }
2008}
2009
2010#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2012pub struct Memory {
2013 pub idx_type: IndexType,
2015 pub limits: Limits,
2018 pub shared: bool,
2020 pub page_size_log2: u8,
2025}
2026
2027pub const WASM32_MAX_SIZE: u64 = 1 << 32;
2029
2030impl Memory {
2031 pub const DEFAULT_PAGE_SIZE: u32 = 0x10000;
2033
2034 pub const DEFAULT_PAGE_SIZE_LOG2: u8 = {
2036 let log2 = 16;
2037 assert!(1 << log2 == Memory::DEFAULT_PAGE_SIZE);
2038 log2
2039 };
2040
2041 pub fn minimum_byte_size(&self) -> Result<u64, SizeOverflow> {
2049 self.limits
2050 .min
2051 .checked_mul(self.page_size())
2052 .ok_or(SizeOverflow)
2053 }
2054
2055 pub fn maximum_byte_size(&self) -> Result<u64, SizeOverflow> {
2070 match self.limits.max {
2071 Some(max) => max.checked_mul(self.page_size()).ok_or(SizeOverflow),
2072 None => {
2073 let min = self.minimum_byte_size()?;
2074 Ok(min.max(self.max_size_based_on_index_type()))
2075 }
2076 }
2077 }
2078
2079 pub fn page_size(&self) -> u64 {
2081 debug_assert!(
2082 self.page_size_log2 == 16 || self.page_size_log2 == 0,
2083 "invalid page_size_log2: {}; must be 16 or 0",
2084 self.page_size_log2
2085 );
2086 1 << self.page_size_log2
2087 }
2088
2089 pub fn max_size_based_on_index_type(&self) -> u64 {
2094 match self.idx_type {
2095 IndexType::I64 =>
2096 {
2104 0_u64.wrapping_sub(self.page_size())
2105 }
2106 IndexType::I32 => WASM32_MAX_SIZE,
2107 }
2108 }
2109
2110 pub fn can_use_virtual_memory(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
2122 tunables.signals_based_traps && self.page_size_log2 >= host_page_size_log2
2123 }
2124
2125 pub fn can_elide_bounds_check(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
2145 self.can_use_virtual_memory(tunables, host_page_size_log2)
2146 && self.idx_type == IndexType::I32
2147 && tunables.memory_reservation >= (1 << 32)
2148 }
2149
2150 pub fn static_heap_size(&self) -> Option<u64> {
2154 let min = self.minimum_byte_size().ok()?;
2155 let max = self.maximum_byte_size().ok()?;
2156 if min == max { Some(min) } else { None }
2157 }
2158
2159 pub fn memory_may_move(&self, tunables: &Tunables) -> bool {
2166 if self.shared {
2170 return false;
2171 }
2172
2173 if !tunables.memory_may_move {
2176 return false;
2177 }
2178
2179 if self.limits.max.is_some_and(|max| self.limits.min == max) {
2182 return false;
2183 }
2184
2185 let max = self.maximum_byte_size().unwrap_or(u64::MAX);
2188 max > tunables.memory_reservation
2189 }
2190}
2191
2192#[derive(Copy, Clone, Debug)]
2193#[expect(missing_docs, reason = "self-describing error struct")]
2194pub struct SizeOverflow;
2195
2196impl fmt::Display for SizeOverflow {
2197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2198 f.write_str("size overflow calculating memory size")
2199 }
2200}
2201
2202impl core::error::Error for SizeOverflow {}
2203
2204impl From<wasmparser::MemoryType> for Memory {
2205 fn from(ty: wasmparser::MemoryType) -> Memory {
2206 let idx_type = match ty.memory64 {
2207 false => IndexType::I32,
2208 true => IndexType::I64,
2209 };
2210 let limits = Limits {
2211 min: ty.initial,
2212 max: ty.maximum,
2213 };
2214 let page_size_log2 = u8::try_from(ty.page_size_log2.unwrap_or(16)).unwrap();
2215 debug_assert!(
2216 page_size_log2 == 16 || page_size_log2 == 0,
2217 "invalid page_size_log2: {page_size_log2}; must be 16 or 0"
2218 );
2219 Memory {
2220 idx_type,
2221 limits,
2222 shared: ty.shared,
2223 page_size_log2,
2224 }
2225 }
2226}
2227
2228#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2230pub struct Tag {
2231 pub signature: EngineOrModuleTypeIndex,
2233}
2234
2235impl TypeTrace for Tag {
2236 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2237 where
2238 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2239 {
2240 func(self.signature)
2241 }
2242
2243 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2244 where
2245 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2246 {
2247 func(&mut self.signature)
2248 }
2249}
2250
2251#[expect(missing_docs, reason = "self-describing functions")]
2253pub trait TypeConvert {
2254 fn convert_global_type(&self, ty: &wasmparser::GlobalType) -> WasmResult<Global> {
2256 Ok(Global {
2257 wasm_ty: self.convert_valtype(ty.content_type)?,
2258 mutability: ty.mutable,
2259 })
2260 }
2261
2262 fn convert_table_type(&self, ty: &wasmparser::TableType) -> WasmResult<Table> {
2264 let idx_type = match ty.table64 {
2265 false => IndexType::I32,
2266 true => IndexType::I64,
2267 };
2268 let limits = Limits {
2269 min: ty.initial,
2270 max: ty.maximum,
2271 };
2272 Ok(Table {
2273 idx_type,
2274 limits,
2275 ref_type: self.convert_ref_type(ty.element_type)?,
2276 })
2277 }
2278
2279 fn convert_sub_type(&self, ty: &wasmparser::SubType) -> WasmResult<WasmSubType> {
2280 Ok(WasmSubType {
2281 is_final: ty.is_final,
2282 supertype: ty.supertype_idx.map(|i| self.lookup_type_index(i.unpack())),
2283 composite_type: self.convert_composite_type(&ty.composite_type)?,
2284 })
2285 }
2286
2287 fn convert_composite_type(
2288 &self,
2289 ty: &wasmparser::CompositeType,
2290 ) -> WasmResult<WasmCompositeType> {
2291 let inner = match &ty.inner {
2292 wasmparser::CompositeInnerType::Func(f) => {
2293 WasmCompositeInnerType::Func(self.convert_func_type(f)?)
2294 }
2295 wasmparser::CompositeInnerType::Array(a) => {
2296 WasmCompositeInnerType::Array(self.convert_array_type(a)?)
2297 }
2298 wasmparser::CompositeInnerType::Struct(s) => {
2299 WasmCompositeInnerType::Struct(self.convert_struct_type(s)?)
2300 }
2301 wasmparser::CompositeInnerType::Cont(c) => {
2302 WasmCompositeInnerType::Cont(self.convert_cont_type(c))
2303 }
2304 };
2305 Ok(WasmCompositeType {
2306 inner,
2307 shared: ty.shared,
2308 })
2309 }
2310
2311 fn convert_cont_type(&self, ty: &wasmparser::ContType) -> WasmContType {
2313 if let WasmHeapType::ConcreteFunc(sigidx) = self.lookup_heap_type(ty.0.unpack()) {
2314 WasmContType::new(sigidx)
2315 } else {
2316 panic!("Failed to extract signature index for continuation type.")
2317 }
2318 }
2319
2320 fn convert_struct_type(&self, ty: &wasmparser::StructType) -> WasmResult<WasmStructType> {
2321 Ok(WasmStructType {
2322 fields: ty
2323 .fields
2324 .iter()
2325 .map(|f| self.convert_field_type(f))
2326 .collect::<WasmResult<_>>()?,
2327 })
2328 }
2329
2330 fn convert_array_type(&self, ty: &wasmparser::ArrayType) -> WasmResult<WasmArrayType> {
2331 Ok(WasmArrayType(self.convert_field_type(&ty.0)?))
2332 }
2333
2334 fn convert_field_type(&self, ty: &wasmparser::FieldType) -> WasmResult<WasmFieldType> {
2335 Ok(WasmFieldType {
2336 element_type: self.convert_storage_type(&ty.element_type)?,
2337 mutable: ty.mutable,
2338 })
2339 }
2340
2341 fn convert_storage_type(&self, ty: &wasmparser::StorageType) -> WasmResult<WasmStorageType> {
2342 Ok(match ty {
2343 wasmparser::StorageType::I8 => WasmStorageType::I8,
2344 wasmparser::StorageType::I16 => WasmStorageType::I16,
2345 wasmparser::StorageType::Val(v) => WasmStorageType::Val(self.convert_valtype(*v)?),
2346 })
2347 }
2348
2349 fn convert_func_type(&self, ty: &wasmparser::FuncType) -> WasmResult<WasmFuncType> {
2351 let params = ty
2352 .params()
2353 .iter()
2354 .map(|t| self.convert_valtype(*t))
2355 .collect::<WasmResult<_>>()?;
2356 let results = ty
2357 .results()
2358 .iter()
2359 .map(|t| self.convert_valtype(*t))
2360 .collect::<WasmResult<_>>()?;
2361 Ok(WasmFuncType::new(params, results))
2362 }
2363
2364 fn convert_valtype(&self, ty: wasmparser::ValType) -> WasmResult<WasmValType> {
2366 Ok(match ty {
2367 wasmparser::ValType::I32 => WasmValType::I32,
2368 wasmparser::ValType::I64 => WasmValType::I64,
2369 wasmparser::ValType::F32 => WasmValType::F32,
2370 wasmparser::ValType::F64 => WasmValType::F64,
2371 wasmparser::ValType::V128 => WasmValType::V128,
2372 wasmparser::ValType::Ref(t) => WasmValType::Ref(self.convert_ref_type(t)?),
2373 })
2374 }
2375
2376 fn convert_ref_type(&self, ty: wasmparser::RefType) -> WasmResult<WasmRefType> {
2378 Ok(WasmRefType {
2379 nullable: ty.is_nullable(),
2380 heap_type: self.convert_heap_type(ty.heap_type())?,
2381 })
2382 }
2383
2384 fn convert_heap_type(&self, ty: wasmparser::HeapType) -> WasmResult<WasmHeapType> {
2386 Ok(match ty {
2387 wasmparser::HeapType::Concrete(i) => self.lookup_heap_type(i),
2388 wasmparser::HeapType::Abstract { ty, shared: false } => match ty {
2389 wasmparser::AbstractHeapType::Extern => WasmHeapType::Extern,
2390 wasmparser::AbstractHeapType::NoExtern => WasmHeapType::NoExtern,
2391 wasmparser::AbstractHeapType::Func => WasmHeapType::Func,
2392 wasmparser::AbstractHeapType::NoFunc => WasmHeapType::NoFunc,
2393 wasmparser::AbstractHeapType::Any => WasmHeapType::Any,
2394 wasmparser::AbstractHeapType::Eq => WasmHeapType::Eq,
2395 wasmparser::AbstractHeapType::I31 => WasmHeapType::I31,
2396 wasmparser::AbstractHeapType::Array => WasmHeapType::Array,
2397 wasmparser::AbstractHeapType::Struct => WasmHeapType::Struct,
2398 wasmparser::AbstractHeapType::None => WasmHeapType::None,
2399 wasmparser::AbstractHeapType::Cont => WasmHeapType::Cont,
2400 wasmparser::AbstractHeapType::NoCont => WasmHeapType::NoCont,
2401 wasmparser::AbstractHeapType::Exn => WasmHeapType::Exn,
2402 wasmparser::AbstractHeapType::NoExn => WasmHeapType::NoExn,
2403 },
2404 _ => return Err(wasm_unsupported!("unsupported heap type {ty:?}")),
2405 })
2406 }
2407
2408 fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType;
2411
2412 fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex;
2415}