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 #[inline]
376 pub fn as_engine_type_index(self) -> Option<VMSharedTypeIndex> {
377 match self {
378 Self::Engine(e) => Some(e),
379 Self::RecGroup(_) | Self::Module(_) => None,
380 }
381 }
382
383 #[track_caller]
385 #[inline]
386 pub fn unwrap_engine_type_index(self) -> VMSharedTypeIndex {
387 match self.as_engine_type_index() {
388 Some(x) => x,
389 None => panic!("`unwrap_engine_type_index` on {self:?}"),
390 }
391 }
392
393 pub fn is_module_type_index(self) -> bool {
395 matches!(self, Self::Module(_))
396 }
397
398 pub fn as_module_type_index(self) -> Option<ModuleInternedTypeIndex> {
400 match self {
401 Self::Module(e) => Some(e),
402 Self::RecGroup(_) | Self::Engine(_) => None,
403 }
404 }
405
406 #[track_caller]
408 pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
409 match self.as_module_type_index() {
410 Some(x) => x,
411 None => panic!("`unwrap_module_type_index` on {self:?}"),
412 }
413 }
414
415 pub fn is_rec_group_type_index(self) -> bool {
417 matches!(self, Self::RecGroup(_))
418 }
419
420 pub fn as_rec_group_type_index(self) -> Option<RecGroupRelativeTypeIndex> {
422 match self {
423 Self::RecGroup(r) => Some(r),
424 Self::Module(_) | Self::Engine(_) => None,
425 }
426 }
427
428 #[track_caller]
430 pub fn unwrap_rec_group_type_index(self) -> RecGroupRelativeTypeIndex {
431 match self.as_rec_group_type_index() {
432 Some(x) => x,
433 None => panic!("`unwrap_rec_group_type_index` on {self:?}"),
434 }
435 }
436}
437
438#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
440#[expect(missing_docs, reason = "self-describing variants")]
441pub enum WasmHeapType {
442 Extern,
444 NoExtern,
445
446 Func,
448 ConcreteFunc(EngineOrModuleTypeIndex),
449 NoFunc,
450
451 Exn,
453 ConcreteExn(EngineOrModuleTypeIndex),
454 NoExn,
455
456 Cont,
458 ConcreteCont(EngineOrModuleTypeIndex),
459 NoCont,
460
461 Any,
463 Eq,
464 I31,
465 Array,
466 ConcreteArray(EngineOrModuleTypeIndex),
467 Struct,
468 ConcreteStruct(EngineOrModuleTypeIndex),
469 None,
470}
471
472impl From<WasmHeapTopType> for WasmHeapType {
473 #[inline]
474 fn from(value: WasmHeapTopType) -> Self {
475 match value {
476 WasmHeapTopType::Extern => Self::Extern,
477 WasmHeapTopType::Any => Self::Any,
478 WasmHeapTopType::Func => Self::Func,
479 WasmHeapTopType::Cont => Self::Cont,
480 WasmHeapTopType::Exn => Self::Exn,
481 }
482 }
483}
484
485impl From<WasmHeapBottomType> for WasmHeapType {
486 #[inline]
487 fn from(value: WasmHeapBottomType) -> Self {
488 match value {
489 WasmHeapBottomType::NoExtern => Self::NoExtern,
490 WasmHeapBottomType::None => Self::None,
491 WasmHeapBottomType::NoFunc => Self::NoFunc,
492 WasmHeapBottomType::NoCont => Self::NoCont,
493 WasmHeapBottomType::NoExn => Self::NoExn,
494 }
495 }
496}
497
498impl fmt::Display for WasmHeapType {
499 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
500 match self {
501 Self::Extern => write!(f, "extern"),
502 Self::NoExtern => write!(f, "noextern"),
503 Self::Func => write!(f, "func"),
504 Self::ConcreteFunc(i) => write!(f, "func {i}"),
505 Self::NoFunc => write!(f, "nofunc"),
506 Self::Cont => write!(f, "cont"),
507 Self::ConcreteCont(i) => write!(f, "cont {i}"),
508 Self::NoCont => write!(f, "nocont"),
509 Self::Any => write!(f, "any"),
510 Self::Eq => write!(f, "eq"),
511 Self::I31 => write!(f, "i31"),
512 Self::Array => write!(f, "array"),
513 Self::ConcreteArray(i) => write!(f, "array {i}"),
514 Self::Struct => write!(f, "struct"),
515 Self::ConcreteStruct(i) => write!(f, "struct {i}"),
516 Self::Exn => write!(f, "exn"),
517 Self::ConcreteExn(i) => write!(f, "exn {i}"),
518 Self::NoExn => write!(f, "noexn"),
519 Self::None => write!(f, "none"),
520 }
521 }
522}
523
524impl TypeTrace for WasmHeapType {
525 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
526 where
527 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
528 {
529 match *self {
530 Self::ConcreteArray(i) => func(i),
531 Self::ConcreteFunc(i) => func(i),
532 Self::ConcreteStruct(i) => func(i),
533 Self::ConcreteCont(i) => func(i),
534 _ => Ok(()),
535 }
536 }
537
538 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
539 where
540 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
541 {
542 match self {
543 Self::ConcreteArray(i) => func(i),
544 Self::ConcreteFunc(i) => func(i),
545 Self::ConcreteStruct(i) => func(i),
546 Self::ConcreteCont(i) => func(i),
547 _ => Ok(()),
548 }
549 }
550}
551
552impl WasmHeapType {
553 #[inline]
555 pub fn is_vmgcref_type(&self) -> bool {
556 match self.top() {
557 WasmHeapTopType::Any | WasmHeapTopType::Extern | WasmHeapTopType::Exn => true,
561
562 WasmHeapTopType::Func => false,
564 WasmHeapTopType::Cont => false,
565 }
566 }
567
568 #[inline]
574 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
575 self.is_vmgcref_type() && *self != Self::I31
576 }
577
578 #[inline]
580 pub fn is_top(&self) -> bool {
581 *self == Self::from(self.top())
582 }
583
584 #[inline]
586 pub fn top(&self) -> WasmHeapTopType {
587 match self {
588 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapTopType::Extern,
589
590 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
591 WasmHeapTopType::Func
592 }
593
594 WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
595 WasmHeapTopType::Cont
596 }
597
598 WasmHeapType::Exn | WasmHeapType::ConcreteExn(_) | WasmHeapType::NoExn => {
599 WasmHeapTopType::Exn
600 }
601
602 WasmHeapType::Any
603 | WasmHeapType::Eq
604 | WasmHeapType::I31
605 | WasmHeapType::Array
606 | WasmHeapType::ConcreteArray(_)
607 | WasmHeapType::Struct
608 | WasmHeapType::ConcreteStruct(_)
609 | WasmHeapType::None => WasmHeapTopType::Any,
610 }
611 }
612
613 #[inline]
615 pub fn is_bottom(&self) -> bool {
616 *self == Self::from(self.bottom())
617 }
618
619 #[inline]
621 pub fn bottom(&self) -> WasmHeapBottomType {
622 match self {
623 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapBottomType::NoExtern,
624
625 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
626 WasmHeapBottomType::NoFunc
627 }
628
629 WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
630 WasmHeapBottomType::NoCont
631 }
632
633 WasmHeapType::Exn | WasmHeapType::ConcreteExn(_) | WasmHeapType::NoExn => {
634 WasmHeapBottomType::NoExn
635 }
636
637 WasmHeapType::Any
638 | WasmHeapType::Eq
639 | WasmHeapType::I31
640 | WasmHeapType::Array
641 | WasmHeapType::ConcreteArray(_)
642 | WasmHeapType::Struct
643 | WasmHeapType::ConcreteStruct(_)
644 | WasmHeapType::None => WasmHeapBottomType::None,
645 }
646 }
647}
648
649#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
651pub enum WasmHeapTopType {
652 Extern,
654 Any,
656 Func,
658 Exn,
660 Cont,
662}
663
664#[derive(Debug, Clone, Copy, Eq, PartialEq)]
666pub enum WasmHeapBottomType {
667 NoExtern,
669 None,
671 NoFunc,
673 NoExn,
675 NoCont,
677}
678
679#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
681pub struct WasmFuncType {
682 params: Box<[WasmValType]>,
683 non_i31_gc_ref_params_count: usize,
684 returns: Box<[WasmValType]>,
685 non_i31_gc_ref_returns_count: usize,
686}
687
688impl fmt::Display for WasmFuncType {
689 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
690 write!(f, "(func")?;
691 if !self.params.is_empty() {
692 write!(f, " (param")?;
693 for p in self.params.iter() {
694 write!(f, " {p}")?;
695 }
696 write!(f, ")")?;
697 }
698 if !self.returns.is_empty() {
699 write!(f, " (result")?;
700 for r in self.returns.iter() {
701 write!(f, " {r}")?;
702 }
703 write!(f, ")")?;
704 }
705 write!(f, ")")
706 }
707}
708
709impl TypeTrace for WasmFuncType {
710 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
711 where
712 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
713 {
714 for p in self.params.iter() {
715 p.trace(func)?;
716 }
717 for r in self.returns.iter() {
718 r.trace(func)?;
719 }
720 Ok(())
721 }
722
723 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
724 where
725 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
726 {
727 for p in self.params.iter_mut() {
728 p.trace_mut(func)?;
729 }
730 for r in self.returns.iter_mut() {
731 r.trace_mut(func)?;
732 }
733 Ok(())
734 }
735}
736
737impl WasmFuncType {
738 #[inline]
740 pub fn new(params: Box<[WasmValType]>, returns: Box<[WasmValType]>) -> Self {
741 let non_i31_gc_ref_params_count = params
742 .iter()
743 .filter(|p| p.is_vmgcref_type_and_not_i31())
744 .count();
745 let non_i31_gc_ref_returns_count = returns
746 .iter()
747 .filter(|r| r.is_vmgcref_type_and_not_i31())
748 .count();
749 WasmFuncType {
750 params,
751 non_i31_gc_ref_params_count,
752 returns,
753 non_i31_gc_ref_returns_count,
754 }
755 }
756
757 #[inline]
759 pub fn params(&self) -> &[WasmValType] {
760 &self.params
761 }
762
763 #[inline]
765 pub fn non_i31_gc_ref_params_count(&self) -> usize {
766 self.non_i31_gc_ref_params_count
767 }
768
769 #[inline]
771 pub fn returns(&self) -> &[WasmValType] {
772 &self.returns
773 }
774
775 #[inline]
777 pub fn non_i31_gc_ref_returns_count(&self) -> usize {
778 self.non_i31_gc_ref_returns_count
779 }
780
781 pub fn is_trampoline_type(&self) -> bool {
783 self.params().iter().all(|p| *p == p.trampoline_type())
784 && self.returns().iter().all(|r| *r == r.trampoline_type())
785 }
786
787 pub fn trampoline_type(&self) -> Cow<'_, Self> {
813 if self.is_trampoline_type() {
814 return Cow::Borrowed(self);
815 }
816
817 Cow::Owned(Self::new(
818 self.params().iter().map(|p| p.trampoline_type()).collect(),
819 self.returns().iter().map(|r| r.trampoline_type()).collect(),
820 ))
821 }
822}
823
824#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
826pub struct WasmContType(EngineOrModuleTypeIndex);
827
828impl fmt::Display for WasmContType {
829 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
830 write!(f, "(cont {})", self.0)
831 }
832}
833
834impl WasmContType {
835 pub fn new(idx: EngineOrModuleTypeIndex) -> Self {
837 WasmContType(idx)
838 }
839
840 pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
842 match self.0 {
843 EngineOrModuleTypeIndex::Engine(_) => panic!("not module interned"),
844 EngineOrModuleTypeIndex::Module(idx) => idx,
845 EngineOrModuleTypeIndex::RecGroup(_) => todo!(),
846 }
847 }
848}
849
850impl TypeTrace for WasmContType {
851 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
852 where
853 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
854 {
855 func(self.0)
856 }
857
858 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
859 where
860 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
861 {
862 func(&mut self.0)
863 }
864}
865
866#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
891pub struct WasmExnType {
892 pub func_ty: EngineOrModuleTypeIndex,
896 pub fields: Box<[WasmFieldType]>,
903}
904
905impl fmt::Display for WasmExnType {
906 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
907 write!(f, "(exn ({})", self.func_ty)?;
908 for ty in self.fields.iter() {
909 write!(f, " {ty}")?;
910 }
911 write!(f, ")")
912 }
913}
914
915impl TypeTrace for WasmExnType {
916 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
917 where
918 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
919 {
920 func(self.func_ty)?;
921 for f in self.fields.iter() {
922 f.trace(func)?;
923 }
924 Ok(())
925 }
926
927 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
928 where
929 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
930 {
931 func(&mut self.func_ty)?;
932 for f in self.fields.iter_mut() {
933 f.trace_mut(func)?;
934 }
935 Ok(())
936 }
937}
938
939#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
941pub enum WasmStorageType {
942 I8,
944 I16,
946 Val(WasmValType),
948}
949
950impl fmt::Display for WasmStorageType {
951 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
952 match self {
953 WasmStorageType::I8 => write!(f, "i8"),
954 WasmStorageType::I16 => write!(f, "i16"),
955 WasmStorageType::Val(v) => fmt::Display::fmt(v, f),
956 }
957 }
958}
959
960impl TypeTrace for WasmStorageType {
961 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
962 where
963 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
964 {
965 match self {
966 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
967 WasmStorageType::Val(v) => v.trace(func),
968 }
969 }
970
971 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
972 where
973 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
974 {
975 match self {
976 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
977 WasmStorageType::Val(v) => v.trace_mut(func),
978 }
979 }
980}
981
982impl WasmStorageType {
983 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
989 match self {
990 WasmStorageType::I8 | WasmStorageType::I16 => false,
991 WasmStorageType::Val(v) => v.is_vmgcref_type_and_not_i31(),
992 }
993 }
994}
995
996#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
998pub struct WasmFieldType {
999 pub element_type: WasmStorageType,
1001
1002 pub mutable: bool,
1004}
1005
1006impl fmt::Display for WasmFieldType {
1007 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1008 if self.mutable {
1009 write!(f, "(mut {})", self.element_type)
1010 } else {
1011 fmt::Display::fmt(&self.element_type, f)
1012 }
1013 }
1014}
1015
1016impl TypeTrace for WasmFieldType {
1017 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1018 where
1019 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1020 {
1021 self.element_type.trace(func)
1022 }
1023
1024 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1025 where
1026 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1027 {
1028 self.element_type.trace_mut(func)
1029 }
1030}
1031
1032#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1034pub struct WasmArrayType(pub WasmFieldType);
1035
1036impl fmt::Display for WasmArrayType {
1037 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1038 write!(f, "(array {})", self.0)
1039 }
1040}
1041
1042impl TypeTrace for WasmArrayType {
1043 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1044 where
1045 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1046 {
1047 self.0.trace(func)
1048 }
1049
1050 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1051 where
1052 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1053 {
1054 self.0.trace_mut(func)
1055 }
1056}
1057
1058#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1060pub struct WasmStructType {
1061 pub fields: Box<[WasmFieldType]>,
1063}
1064
1065impl fmt::Display for WasmStructType {
1066 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1067 write!(f, "(struct")?;
1068 for ty in self.fields.iter() {
1069 write!(f, " {ty}")?;
1070 }
1071 write!(f, ")")
1072 }
1073}
1074
1075impl TypeTrace for WasmStructType {
1076 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1077 where
1078 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1079 {
1080 for f in self.fields.iter() {
1081 f.trace(func)?;
1082 }
1083 Ok(())
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 for f in self.fields.iter_mut() {
1091 f.trace_mut(func)?;
1092 }
1093 Ok(())
1094 }
1095}
1096
1097#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1098#[expect(missing_docs, reason = "self-describing type")]
1099pub struct WasmCompositeType {
1100 pub inner: WasmCompositeInnerType,
1102 pub shared: bool,
1105}
1106
1107impl fmt::Display for WasmCompositeType {
1108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1109 if self.shared {
1110 write!(f, "(shared ")?;
1111 }
1112 fmt::Display::fmt(&self.inner, f)?;
1113 if self.shared {
1114 write!(f, ")")?;
1115 }
1116 Ok(())
1117 }
1118}
1119
1120#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1122#[expect(missing_docs, reason = "self-describing variants")]
1123pub enum WasmCompositeInnerType {
1124 Array(WasmArrayType),
1125 Func(WasmFuncType),
1126 Struct(WasmStructType),
1127 Cont(WasmContType),
1128 Exn(WasmExnType),
1129}
1130
1131impl fmt::Display for WasmCompositeInnerType {
1132 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1133 match self {
1134 Self::Array(ty) => fmt::Display::fmt(ty, f),
1135 Self::Func(ty) => fmt::Display::fmt(ty, f),
1136 Self::Struct(ty) => fmt::Display::fmt(ty, f),
1137 Self::Cont(ty) => fmt::Display::fmt(ty, f),
1138 Self::Exn(ty) => fmt::Display::fmt(ty, f),
1139 }
1140 }
1141}
1142
1143#[expect(missing_docs, reason = "self-describing functions")]
1144impl WasmCompositeInnerType {
1145 #[inline]
1146 pub fn is_array(&self) -> bool {
1147 matches!(self, Self::Array(_))
1148 }
1149
1150 #[inline]
1151 pub fn as_array(&self) -> Option<&WasmArrayType> {
1152 match self {
1153 Self::Array(f) => Some(f),
1154 _ => None,
1155 }
1156 }
1157
1158 #[inline]
1159 pub fn unwrap_array(&self) -> &WasmArrayType {
1160 self.as_array().unwrap()
1161 }
1162
1163 #[inline]
1164 pub fn is_func(&self) -> bool {
1165 matches!(self, Self::Func(_))
1166 }
1167
1168 #[inline]
1169 pub fn as_func(&self) -> Option<&WasmFuncType> {
1170 match self {
1171 Self::Func(f) => Some(f),
1172 _ => None,
1173 }
1174 }
1175
1176 #[inline]
1177 pub fn unwrap_func(&self) -> &WasmFuncType {
1178 self.as_func().unwrap()
1179 }
1180
1181 #[inline]
1182 pub fn is_struct(&self) -> bool {
1183 matches!(self, Self::Struct(_))
1184 }
1185
1186 #[inline]
1187 pub fn as_struct(&self) -> Option<&WasmStructType> {
1188 match self {
1189 Self::Struct(f) => Some(f),
1190 _ => None,
1191 }
1192 }
1193
1194 #[inline]
1195 pub fn unwrap_struct(&self) -> &WasmStructType {
1196 self.as_struct().unwrap()
1197 }
1198
1199 #[inline]
1200 pub fn is_cont(&self) -> bool {
1201 matches!(self, Self::Cont(_))
1202 }
1203
1204 #[inline]
1205 pub fn as_cont(&self) -> Option<&WasmContType> {
1206 match self {
1207 Self::Cont(f) => Some(f),
1208 _ => None,
1209 }
1210 }
1211
1212 #[inline]
1213 pub fn unwrap_cont(&self) -> &WasmContType {
1214 self.as_cont().unwrap()
1215 }
1216
1217 #[inline]
1218 pub fn is_exn(&self) -> bool {
1219 matches!(self, Self::Exn(_))
1220 }
1221
1222 #[inline]
1223 pub fn as_exn(&self) -> Option<&WasmExnType> {
1224 match self {
1225 Self::Exn(f) => Some(f),
1226 _ => None,
1227 }
1228 }
1229
1230 #[inline]
1231 pub fn unwrap_exn(&self) -> &WasmExnType {
1232 self.as_exn().unwrap()
1233 }
1234}
1235
1236impl TypeTrace for WasmCompositeType {
1237 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1238 where
1239 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1240 {
1241 match &self.inner {
1242 WasmCompositeInnerType::Array(a) => a.trace(func),
1243 WasmCompositeInnerType::Func(f) => f.trace(func),
1244 WasmCompositeInnerType::Struct(a) => a.trace(func),
1245 WasmCompositeInnerType::Cont(c) => c.trace(func),
1246 WasmCompositeInnerType::Exn(e) => e.trace(func),
1247 }
1248 }
1249
1250 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1251 where
1252 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1253 {
1254 match &mut self.inner {
1255 WasmCompositeInnerType::Array(a) => a.trace_mut(func),
1256 WasmCompositeInnerType::Func(f) => f.trace_mut(func),
1257 WasmCompositeInnerType::Struct(a) => a.trace_mut(func),
1258 WasmCompositeInnerType::Cont(c) => c.trace_mut(func),
1259 WasmCompositeInnerType::Exn(e) => e.trace_mut(func),
1260 }
1261 }
1262}
1263
1264#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1266pub struct WasmSubType {
1267 pub is_final: bool,
1270
1271 pub supertype: Option<EngineOrModuleTypeIndex>,
1273
1274 pub composite_type: WasmCompositeType,
1276}
1277
1278impl fmt::Display for WasmSubType {
1279 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1280 if self.is_final && self.supertype.is_none() {
1281 fmt::Display::fmt(&self.composite_type, f)
1282 } else {
1283 write!(f, "(sub")?;
1284 if self.is_final {
1285 write!(f, " final")?;
1286 }
1287 if let Some(sup) = self.supertype {
1288 write!(f, " {sup}")?;
1289 }
1290 write!(f, " {})", self.composite_type)
1291 }
1292 }
1293}
1294
1295#[expect(missing_docs, reason = "self-describing functions")]
1299impl WasmSubType {
1300 #[inline]
1301 pub fn is_func(&self) -> bool {
1302 self.composite_type.inner.is_func() && !self.composite_type.shared
1303 }
1304
1305 #[inline]
1306 pub fn as_func(&self) -> Option<&WasmFuncType> {
1307 if self.composite_type.shared {
1308 None
1309 } else {
1310 self.composite_type.inner.as_func()
1311 }
1312 }
1313
1314 #[inline]
1315 pub fn unwrap_func(&self) -> &WasmFuncType {
1316 assert!(!self.composite_type.shared);
1317 self.composite_type.inner.unwrap_func()
1318 }
1319
1320 #[inline]
1321 pub fn is_array(&self) -> bool {
1322 self.composite_type.inner.is_array() && !self.composite_type.shared
1323 }
1324
1325 #[inline]
1326 pub fn as_array(&self) -> Option<&WasmArrayType> {
1327 if self.composite_type.shared {
1328 None
1329 } else {
1330 self.composite_type.inner.as_array()
1331 }
1332 }
1333
1334 #[inline]
1335 pub fn unwrap_array(&self) -> &WasmArrayType {
1336 assert!(!self.composite_type.shared);
1337 self.composite_type.inner.unwrap_array()
1338 }
1339
1340 #[inline]
1341 pub fn is_struct(&self) -> bool {
1342 self.composite_type.inner.is_struct() && !self.composite_type.shared
1343 }
1344
1345 #[inline]
1346 pub fn as_struct(&self) -> Option<&WasmStructType> {
1347 if self.composite_type.shared {
1348 None
1349 } else {
1350 self.composite_type.inner.as_struct()
1351 }
1352 }
1353
1354 #[inline]
1355 pub fn unwrap_struct(&self) -> &WasmStructType {
1356 assert!(!self.composite_type.shared);
1357 self.composite_type.inner.unwrap_struct()
1358 }
1359
1360 #[inline]
1361 pub fn is_cont(&self) -> bool {
1362 self.composite_type.inner.is_cont() && !self.composite_type.shared
1363 }
1364
1365 #[inline]
1366 pub fn as_cont(&self) -> Option<&WasmContType> {
1367 if self.composite_type.shared {
1368 None
1369 } else {
1370 self.composite_type.inner.as_cont()
1371 }
1372 }
1373
1374 #[inline]
1375 pub fn unwrap_cont(&self) -> &WasmContType {
1376 assert!(!self.composite_type.shared);
1377 self.composite_type.inner.unwrap_cont()
1378 }
1379
1380 #[inline]
1381 pub fn is_exn(&self) -> bool {
1382 self.composite_type.inner.is_exn() && !self.composite_type.shared
1383 }
1384
1385 #[inline]
1386 pub fn as_exn(&self) -> Option<&WasmExnType> {
1387 if self.composite_type.shared {
1388 None
1389 } else {
1390 self.composite_type.inner.as_exn()
1391 }
1392 }
1393
1394 #[inline]
1395 pub fn unwrap_exn(&self) -> &WasmExnType {
1396 assert!(!self.composite_type.shared);
1397 self.composite_type.inner.unwrap_exn()
1398 }
1399}
1400
1401impl TypeTrace for WasmSubType {
1402 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1403 where
1404 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1405 {
1406 if let Some(sup) = self.supertype {
1407 func(sup)?;
1408 }
1409 self.composite_type.trace(func)
1410 }
1411
1412 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1413 where
1414 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1415 {
1416 if let Some(sup) = self.supertype.as_mut() {
1417 func(sup)?;
1418 }
1419 self.composite_type.trace_mut(func)
1420 }
1421}
1422
1423#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1434pub struct WasmRecGroup {
1435 pub types: Box<[WasmSubType]>,
1437}
1438
1439impl TypeTrace for WasmRecGroup {
1440 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1441 where
1442 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1443 {
1444 for ty in self.types.iter() {
1445 ty.trace(func)?;
1446 }
1447 Ok(())
1448 }
1449
1450 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1451 where
1452 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1453 {
1454 for ty in self.types.iter_mut() {
1455 ty.trace_mut(func)?;
1456 }
1457 Ok(())
1458 }
1459}
1460
1461#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1463pub struct FuncIndex(u32);
1464entity_impl!(FuncIndex);
1465
1466#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1468pub struct DefinedFuncIndex(u32);
1469entity_impl!(DefinedFuncIndex);
1470
1471#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1473pub struct DefinedTableIndex(u32);
1474entity_impl!(DefinedTableIndex);
1475
1476#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1478pub struct DefinedMemoryIndex(u32);
1479entity_impl!(DefinedMemoryIndex);
1480
1481#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1483pub struct OwnedMemoryIndex(u32);
1484entity_impl!(OwnedMemoryIndex);
1485
1486#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1488pub struct DefinedGlobalIndex(u32);
1489entity_impl!(DefinedGlobalIndex);
1490
1491#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1493pub struct TableIndex(u32);
1494entity_impl!(TableIndex);
1495
1496#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1498pub struct GlobalIndex(u32);
1499entity_impl!(GlobalIndex);
1500
1501#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1503pub struct MemoryIndex(u32);
1504entity_impl!(MemoryIndex);
1505
1506#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1509pub struct ModuleInternedRecGroupIndex(u32);
1510entity_impl!(ModuleInternedRecGroupIndex);
1511
1512#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1515pub struct EngineInternedRecGroupIndex(u32);
1516entity_impl!(EngineInternedRecGroupIndex);
1517
1518#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1520pub struct TypeIndex(u32);
1521entity_impl!(TypeIndex);
1522
1523#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1529pub struct RecGroupRelativeTypeIndex(u32);
1530entity_impl!(RecGroupRelativeTypeIndex);
1531
1532#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1540pub struct ModuleInternedTypeIndex(u32);
1541entity_impl!(ModuleInternedTypeIndex);
1542
1543#[repr(transparent)] #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1552pub struct VMSharedTypeIndex(u32);
1553entity_impl!(VMSharedTypeIndex);
1554
1555impl VMSharedTypeIndex {
1556 #[inline]
1558 pub fn new(value: u32) -> Self {
1559 assert_ne!(
1560 value,
1561 u32::MAX,
1562 "u32::MAX is reserved for the default value"
1563 );
1564 Self(value)
1565 }
1566
1567 #[inline]
1569 pub fn bits(&self) -> u32 {
1570 self.0
1571 }
1572}
1573
1574impl Default for VMSharedTypeIndex {
1575 #[inline]
1576 fn default() -> Self {
1577 Self(u32::MAX)
1578 }
1579}
1580
1581#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1583pub struct DataIndex(u32);
1584entity_impl!(DataIndex);
1585
1586#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1588pub struct ElemIndex(u32);
1589entity_impl!(ElemIndex);
1590
1591#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1593pub struct DefinedTagIndex(u32);
1594entity_impl!(DefinedTagIndex);
1595
1596#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1598pub struct TagIndex(u32);
1599entity_impl!(TagIndex);
1600
1601#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1606pub struct StaticModuleIndex(u32);
1607entity_impl!(StaticModuleIndex);
1608
1609#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1611pub enum EntityIndex {
1612 Function(FuncIndex),
1614 Table(TableIndex),
1616 Memory(MemoryIndex),
1618 Global(GlobalIndex),
1620 Tag(TagIndex),
1622}
1623
1624impl From<FuncIndex> for EntityIndex {
1625 fn from(idx: FuncIndex) -> EntityIndex {
1626 EntityIndex::Function(idx)
1627 }
1628}
1629
1630impl From<TableIndex> for EntityIndex {
1631 fn from(idx: TableIndex) -> EntityIndex {
1632 EntityIndex::Table(idx)
1633 }
1634}
1635
1636impl From<MemoryIndex> for EntityIndex {
1637 fn from(idx: MemoryIndex) -> EntityIndex {
1638 EntityIndex::Memory(idx)
1639 }
1640}
1641
1642impl From<GlobalIndex> for EntityIndex {
1643 fn from(idx: GlobalIndex) -> EntityIndex {
1644 EntityIndex::Global(idx)
1645 }
1646}
1647
1648impl From<TagIndex> for EntityIndex {
1649 fn from(idx: TagIndex) -> EntityIndex {
1650 EntityIndex::Tag(idx)
1651 }
1652}
1653
1654#[derive(Clone, Debug, Serialize, Deserialize)]
1657pub enum EntityType {
1658 Global(Global),
1660 Memory(Memory),
1662 Tag(Tag),
1664 Table(Table),
1666 Function(EngineOrModuleTypeIndex),
1669}
1670
1671impl TypeTrace for EntityType {
1672 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1673 where
1674 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1675 {
1676 match self {
1677 Self::Global(g) => g.trace(func),
1678 Self::Table(t) => t.trace(func),
1679 Self::Function(idx) => func(*idx),
1680 Self::Memory(_) => Ok(()),
1681 Self::Tag(t) => t.trace(func),
1682 }
1683 }
1684
1685 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1686 where
1687 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1688 {
1689 match self {
1690 Self::Global(g) => g.trace_mut(func),
1691 Self::Table(t) => t.trace_mut(func),
1692 Self::Function(idx) => func(idx),
1693 Self::Memory(_) => Ok(()),
1694 Self::Tag(t) => t.trace_mut(func),
1695 }
1696 }
1697}
1698
1699impl EntityType {
1700 pub fn unwrap_global(&self) -> &Global {
1702 match self {
1703 EntityType::Global(g) => g,
1704 _ => panic!("not a global"),
1705 }
1706 }
1707
1708 pub fn unwrap_memory(&self) -> &Memory {
1710 match self {
1711 EntityType::Memory(g) => g,
1712 _ => panic!("not a memory"),
1713 }
1714 }
1715
1716 pub fn unwrap_tag(&self) -> &Tag {
1718 match self {
1719 EntityType::Tag(g) => g,
1720 _ => panic!("not a tag"),
1721 }
1722 }
1723
1724 pub fn unwrap_table(&self) -> &Table {
1726 match self {
1727 EntityType::Table(g) => g,
1728 _ => panic!("not a table"),
1729 }
1730 }
1731
1732 pub fn unwrap_func(&self) -> EngineOrModuleTypeIndex {
1734 match self {
1735 EntityType::Function(g) => *g,
1736 _ => panic!("not a func"),
1737 }
1738 }
1739}
1740
1741#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1749pub struct Global {
1750 pub wasm_ty: crate::WasmValType,
1752 pub mutability: bool,
1754}
1755
1756impl TypeTrace for Global {
1757 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1758 where
1759 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1760 {
1761 let Global {
1762 wasm_ty,
1763 mutability: _,
1764 } = self;
1765 wasm_ty.trace(func)
1766 }
1767
1768 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1769 where
1770 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1771 {
1772 let Global {
1773 wasm_ty,
1774 mutability: _,
1775 } = self;
1776 wasm_ty.trace_mut(func)
1777 }
1778}
1779
1780#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1784pub struct ConstExpr {
1785 ops: SmallVec<[ConstOp; 2]>,
1786}
1787
1788impl ConstExpr {
1789 pub fn new(ops: impl IntoIterator<Item = ConstOp>) -> Self {
1795 let ops = ops.into_iter().collect::<SmallVec<[ConstOp; 2]>>();
1796 assert!(!ops.is_empty());
1797 ConstExpr { ops }
1798 }
1799
1800 pub fn from_wasmparser(
1805 env: &dyn TypeConvert,
1806 expr: wasmparser::ConstExpr<'_>,
1807 ) -> WasmResult<(Self, SmallVec<[FuncIndex; 1]>)> {
1808 let mut iter = expr
1809 .get_operators_reader()
1810 .into_iter_with_offsets()
1811 .peekable();
1812
1813 let mut ops = SmallVec::<[ConstOp; 2]>::new();
1814 let mut escaped = SmallVec::<[FuncIndex; 1]>::new();
1815 while let Some(res) = iter.next() {
1816 let (op, offset) = res?;
1817
1818 if matches!(op, wasmparser::Operator::End) && iter.peek().is_none() {
1822 break;
1823 }
1824
1825 if let wasmparser::Operator::RefFunc { function_index } = &op {
1828 escaped.push(FuncIndex::from_u32(*function_index));
1829 }
1830
1831 ops.push(ConstOp::from_wasmparser(env, op, offset)?);
1832 }
1833 Ok((Self { ops }, escaped))
1834 }
1835
1836 #[inline]
1838 pub fn ops(&self) -> &[ConstOp] {
1839 &self.ops
1840 }
1841
1842 pub fn provably_nonzero_i32(&self) -> bool {
1852 assert!(self.ops.len() > 0);
1853 if self.ops.len() > 1 {
1854 return false;
1857 }
1858 match self.ops[0] {
1860 ConstOp::I32Const(0) => false,
1862 ConstOp::I32Const(_) => true,
1865 _ => false,
1867 }
1868 }
1869}
1870
1871#[expect(missing_docs, reason = "self-describing variants")]
1873#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1874pub enum ConstOp {
1875 I32Const(i32),
1876 I64Const(i64),
1877 F32Const(u32),
1878 F64Const(u64),
1879 V128Const(u128),
1880 GlobalGet(GlobalIndex),
1881 RefI31,
1882 RefNull(WasmHeapTopType),
1883 RefFunc(FuncIndex),
1884 I32Add,
1885 I32Sub,
1886 I32Mul,
1887 I64Add,
1888 I64Sub,
1889 I64Mul,
1890 StructNew {
1891 struct_type_index: TypeIndex,
1892 },
1893 StructNewDefault {
1894 struct_type_index: TypeIndex,
1895 },
1896 ArrayNew {
1897 array_type_index: TypeIndex,
1898 },
1899 ArrayNewDefault {
1900 array_type_index: TypeIndex,
1901 },
1902 ArrayNewFixed {
1903 array_type_index: TypeIndex,
1904 array_size: u32,
1905 },
1906 ExternConvertAny,
1907 AnyConvertExtern,
1908}
1909
1910impl ConstOp {
1911 pub fn from_wasmparser(
1913 env: &dyn TypeConvert,
1914 op: wasmparser::Operator<'_>,
1915 offset: usize,
1916 ) -> WasmResult<Self> {
1917 use wasmparser::Operator as O;
1918 Ok(match op {
1919 O::I32Const { value } => Self::I32Const(value),
1920 O::I64Const { value } => Self::I64Const(value),
1921 O::F32Const { value } => Self::F32Const(value.bits()),
1922 O::F64Const { value } => Self::F64Const(value.bits()),
1923 O::V128Const { value } => Self::V128Const(u128::from_le_bytes(*value.bytes())),
1924 O::RefNull { hty } => Self::RefNull(env.convert_heap_type(hty)?.top()),
1925 O::RefFunc { function_index } => Self::RefFunc(FuncIndex::from_u32(function_index)),
1926 O::GlobalGet { global_index } => Self::GlobalGet(GlobalIndex::from_u32(global_index)),
1927 O::RefI31 => Self::RefI31,
1928 O::I32Add => Self::I32Add,
1929 O::I32Sub => Self::I32Sub,
1930 O::I32Mul => Self::I32Mul,
1931 O::I64Add => Self::I64Add,
1932 O::I64Sub => Self::I64Sub,
1933 O::I64Mul => Self::I64Mul,
1934 O::StructNew { struct_type_index } => Self::StructNew {
1935 struct_type_index: TypeIndex::from_u32(struct_type_index),
1936 },
1937 O::StructNewDefault { struct_type_index } => Self::StructNewDefault {
1938 struct_type_index: TypeIndex::from_u32(struct_type_index),
1939 },
1940 O::ArrayNew { array_type_index } => Self::ArrayNew {
1941 array_type_index: TypeIndex::from_u32(array_type_index),
1942 },
1943 O::ArrayNewDefault { array_type_index } => Self::ArrayNewDefault {
1944 array_type_index: TypeIndex::from_u32(array_type_index),
1945 },
1946 O::ArrayNewFixed {
1947 array_type_index,
1948 array_size,
1949 } => Self::ArrayNewFixed {
1950 array_type_index: TypeIndex::from_u32(array_type_index),
1951 array_size,
1952 },
1953 O::ExternConvertAny => Self::ExternConvertAny,
1954 O::AnyConvertExtern => Self::AnyConvertExtern,
1955 op => {
1956 return Err(wasm_unsupported!(
1957 "unsupported opcode in const expression at offset {offset:#x}: {op:?}",
1958 ));
1959 }
1960 })
1961 }
1962}
1963
1964#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1966#[expect(missing_docs, reason = "self-describing variants")]
1967pub enum IndexType {
1968 I32,
1969 I64,
1970}
1971
1972#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1974#[expect(missing_docs, reason = "self-describing fields")]
1975pub struct Limits {
1976 pub min: u64,
1977 pub max: Option<u64>,
1978}
1979
1980#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1982pub struct Table {
1983 pub idx_type: IndexType,
1985 pub limits: Limits,
1988 pub ref_type: WasmRefType,
1990}
1991
1992impl TypeTrace for Table {
1993 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1994 where
1995 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1996 {
1997 let Table {
1998 ref_type: wasm_ty,
1999 idx_type: _,
2000 limits: _,
2001 } = self;
2002 wasm_ty.trace(func)
2003 }
2004
2005 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2006 where
2007 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2008 {
2009 let Table {
2010 ref_type: wasm_ty,
2011 idx_type: _,
2012 limits: _,
2013 } = self;
2014 wasm_ty.trace_mut(func)
2015 }
2016}
2017
2018#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2020pub struct Memory {
2021 pub idx_type: IndexType,
2023 pub limits: Limits,
2026 pub shared: bool,
2028 pub page_size_log2: u8,
2033}
2034
2035pub const WASM32_MAX_SIZE: u64 = 1 << 32;
2037
2038impl Memory {
2039 pub const DEFAULT_PAGE_SIZE: u32 = 0x10000;
2041
2042 pub const DEFAULT_PAGE_SIZE_LOG2: u8 = {
2044 let log2 = 16;
2045 assert!(1 << log2 == Memory::DEFAULT_PAGE_SIZE);
2046 log2
2047 };
2048
2049 pub fn minimum_byte_size(&self) -> Result<u64, SizeOverflow> {
2057 self.limits
2058 .min
2059 .checked_mul(self.page_size())
2060 .ok_or(SizeOverflow)
2061 }
2062
2063 pub fn maximum_byte_size(&self) -> Result<u64, SizeOverflow> {
2078 match self.limits.max {
2079 Some(max) => max.checked_mul(self.page_size()).ok_or(SizeOverflow),
2080 None => {
2081 let min = self.minimum_byte_size()?;
2082 Ok(min.max(self.max_size_based_on_index_type()))
2083 }
2084 }
2085 }
2086
2087 pub fn page_size(&self) -> u64 {
2089 debug_assert!(
2090 self.page_size_log2 == 16 || self.page_size_log2 == 0,
2091 "invalid page_size_log2: {}; must be 16 or 0",
2092 self.page_size_log2
2093 );
2094 1 << self.page_size_log2
2095 }
2096
2097 pub fn max_size_based_on_index_type(&self) -> u64 {
2102 match self.idx_type {
2103 IndexType::I64 =>
2104 {
2112 0_u64.wrapping_sub(self.page_size())
2113 }
2114 IndexType::I32 => WASM32_MAX_SIZE,
2115 }
2116 }
2117
2118 pub fn can_use_virtual_memory(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
2130 tunables.signals_based_traps && self.page_size_log2 >= host_page_size_log2
2131 }
2132
2133 pub fn can_elide_bounds_check(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
2153 self.can_use_virtual_memory(tunables, host_page_size_log2)
2154 && self.idx_type == IndexType::I32
2155 && tunables.memory_reservation >= (1 << 32)
2156 }
2157
2158 pub fn static_heap_size(&self) -> Option<u64> {
2162 let min = self.minimum_byte_size().ok()?;
2163 let max = self.maximum_byte_size().ok()?;
2164 if min == max { Some(min) } else { None }
2165 }
2166
2167 pub fn memory_may_move(&self, tunables: &Tunables) -> bool {
2174 if self.shared {
2178 return false;
2179 }
2180
2181 if !tunables.memory_may_move {
2184 return false;
2185 }
2186
2187 if self.limits.max.is_some_and(|max| self.limits.min == max) {
2190 return false;
2191 }
2192
2193 let max = self.maximum_byte_size().unwrap_or(u64::MAX);
2196 max > tunables.memory_reservation
2197 }
2198}
2199
2200#[derive(Copy, Clone, Debug)]
2201#[expect(missing_docs, reason = "self-describing error struct")]
2202pub struct SizeOverflow;
2203
2204impl fmt::Display for SizeOverflow {
2205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2206 f.write_str("size overflow calculating memory size")
2207 }
2208}
2209
2210impl core::error::Error for SizeOverflow {}
2211
2212impl From<wasmparser::MemoryType> for Memory {
2213 fn from(ty: wasmparser::MemoryType) -> Memory {
2214 let idx_type = match ty.memory64 {
2215 false => IndexType::I32,
2216 true => IndexType::I64,
2217 };
2218 let limits = Limits {
2219 min: ty.initial,
2220 max: ty.maximum,
2221 };
2222 let page_size_log2 = u8::try_from(ty.page_size_log2.unwrap_or(16)).unwrap();
2223 debug_assert!(
2224 page_size_log2 == 16 || page_size_log2 == 0,
2225 "invalid page_size_log2: {page_size_log2}; must be 16 or 0"
2226 );
2227 Memory {
2228 idx_type,
2229 limits,
2230 shared: ty.shared,
2231 page_size_log2,
2232 }
2233 }
2234}
2235
2236#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2238pub struct Tag {
2239 pub signature: EngineOrModuleTypeIndex,
2241 pub exception: EngineOrModuleTypeIndex,
2243}
2244
2245impl TypeTrace for Tag {
2246 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2247 where
2248 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2249 {
2250 func(self.signature)?;
2251 func(self.exception)?;
2252 Ok(())
2253 }
2254
2255 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2256 where
2257 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2258 {
2259 func(&mut self.signature)?;
2260 func(&mut self.exception)?;
2261 Ok(())
2262 }
2263}
2264
2265#[expect(missing_docs, reason = "self-describing functions")]
2267pub trait TypeConvert {
2268 fn convert_global_type(&self, ty: &wasmparser::GlobalType) -> WasmResult<Global> {
2270 Ok(Global {
2271 wasm_ty: self.convert_valtype(ty.content_type)?,
2272 mutability: ty.mutable,
2273 })
2274 }
2275
2276 fn convert_table_type(&self, ty: &wasmparser::TableType) -> WasmResult<Table> {
2278 let idx_type = match ty.table64 {
2279 false => IndexType::I32,
2280 true => IndexType::I64,
2281 };
2282 let limits = Limits {
2283 min: ty.initial,
2284 max: ty.maximum,
2285 };
2286 Ok(Table {
2287 idx_type,
2288 limits,
2289 ref_type: self.convert_ref_type(ty.element_type)?,
2290 })
2291 }
2292
2293 fn convert_sub_type(&self, ty: &wasmparser::SubType) -> WasmResult<WasmSubType> {
2294 Ok(WasmSubType {
2295 is_final: ty.is_final,
2296 supertype: ty.supertype_idx.map(|i| self.lookup_type_index(i.unpack())),
2297 composite_type: self.convert_composite_type(&ty.composite_type)?,
2298 })
2299 }
2300
2301 fn convert_composite_type(
2302 &self,
2303 ty: &wasmparser::CompositeType,
2304 ) -> WasmResult<WasmCompositeType> {
2305 let inner = match &ty.inner {
2306 wasmparser::CompositeInnerType::Func(f) => {
2307 WasmCompositeInnerType::Func(self.convert_func_type(f)?)
2308 }
2309 wasmparser::CompositeInnerType::Array(a) => {
2310 WasmCompositeInnerType::Array(self.convert_array_type(a)?)
2311 }
2312 wasmparser::CompositeInnerType::Struct(s) => {
2313 WasmCompositeInnerType::Struct(self.convert_struct_type(s)?)
2314 }
2315 wasmparser::CompositeInnerType::Cont(c) => {
2316 WasmCompositeInnerType::Cont(self.convert_cont_type(c))
2317 }
2318 };
2319 Ok(WasmCompositeType {
2320 inner,
2321 shared: ty.shared,
2322 })
2323 }
2324
2325 fn convert_cont_type(&self, ty: &wasmparser::ContType) -> WasmContType {
2327 if let WasmHeapType::ConcreteFunc(sigidx) = self.lookup_heap_type(ty.0.unpack()) {
2328 WasmContType::new(sigidx)
2329 } else {
2330 panic!("Failed to extract signature index for continuation type.")
2331 }
2332 }
2333
2334 fn convert_struct_type(&self, ty: &wasmparser::StructType) -> WasmResult<WasmStructType> {
2335 Ok(WasmStructType {
2336 fields: ty
2337 .fields
2338 .iter()
2339 .map(|f| self.convert_field_type(f))
2340 .collect::<WasmResult<_>>()?,
2341 })
2342 }
2343
2344 fn convert_array_type(&self, ty: &wasmparser::ArrayType) -> WasmResult<WasmArrayType> {
2345 Ok(WasmArrayType(self.convert_field_type(&ty.0)?))
2346 }
2347
2348 fn convert_field_type(&self, ty: &wasmparser::FieldType) -> WasmResult<WasmFieldType> {
2349 Ok(WasmFieldType {
2350 element_type: self.convert_storage_type(&ty.element_type)?,
2351 mutable: ty.mutable,
2352 })
2353 }
2354
2355 fn convert_storage_type(&self, ty: &wasmparser::StorageType) -> WasmResult<WasmStorageType> {
2356 Ok(match ty {
2357 wasmparser::StorageType::I8 => WasmStorageType::I8,
2358 wasmparser::StorageType::I16 => WasmStorageType::I16,
2359 wasmparser::StorageType::Val(v) => WasmStorageType::Val(self.convert_valtype(*v)?),
2360 })
2361 }
2362
2363 fn convert_func_type(&self, ty: &wasmparser::FuncType) -> WasmResult<WasmFuncType> {
2365 let params = ty
2366 .params()
2367 .iter()
2368 .map(|t| self.convert_valtype(*t))
2369 .collect::<WasmResult<_>>()?;
2370 let results = ty
2371 .results()
2372 .iter()
2373 .map(|t| self.convert_valtype(*t))
2374 .collect::<WasmResult<_>>()?;
2375 Ok(WasmFuncType::new(params, results))
2376 }
2377
2378 fn convert_valtype(&self, ty: wasmparser::ValType) -> WasmResult<WasmValType> {
2380 Ok(match ty {
2381 wasmparser::ValType::I32 => WasmValType::I32,
2382 wasmparser::ValType::I64 => WasmValType::I64,
2383 wasmparser::ValType::F32 => WasmValType::F32,
2384 wasmparser::ValType::F64 => WasmValType::F64,
2385 wasmparser::ValType::V128 => WasmValType::V128,
2386 wasmparser::ValType::Ref(t) => WasmValType::Ref(self.convert_ref_type(t)?),
2387 })
2388 }
2389
2390 fn convert_ref_type(&self, ty: wasmparser::RefType) -> WasmResult<WasmRefType> {
2392 Ok(WasmRefType {
2393 nullable: ty.is_nullable(),
2394 heap_type: self.convert_heap_type(ty.heap_type())?,
2395 })
2396 }
2397
2398 fn convert_heap_type(&self, ty: wasmparser::HeapType) -> WasmResult<WasmHeapType> {
2400 Ok(match ty {
2401 wasmparser::HeapType::Concrete(i) => self.lookup_heap_type(i),
2402 wasmparser::HeapType::Abstract { ty, shared: false } => match ty {
2403 wasmparser::AbstractHeapType::Extern => WasmHeapType::Extern,
2404 wasmparser::AbstractHeapType::NoExtern => WasmHeapType::NoExtern,
2405 wasmparser::AbstractHeapType::Func => WasmHeapType::Func,
2406 wasmparser::AbstractHeapType::NoFunc => WasmHeapType::NoFunc,
2407 wasmparser::AbstractHeapType::Any => WasmHeapType::Any,
2408 wasmparser::AbstractHeapType::Eq => WasmHeapType::Eq,
2409 wasmparser::AbstractHeapType::I31 => WasmHeapType::I31,
2410 wasmparser::AbstractHeapType::Array => WasmHeapType::Array,
2411 wasmparser::AbstractHeapType::Struct => WasmHeapType::Struct,
2412 wasmparser::AbstractHeapType::None => WasmHeapType::None,
2413 wasmparser::AbstractHeapType::Cont => WasmHeapType::Cont,
2414 wasmparser::AbstractHeapType::NoCont => WasmHeapType::NoCont,
2415 wasmparser::AbstractHeapType::Exn => WasmHeapType::Exn,
2416 wasmparser::AbstractHeapType::NoExn => WasmHeapType::NoExn,
2417 },
2418 _ => return Err(wasm_unsupported!("unsupported heap type {ty:?}")),
2419 })
2420 }
2421
2422 fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType;
2425
2426 fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex;
2429}