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 match self.const_eval() {
1853 Some(GlobalConstValue::I32(x)) => x != 0,
1854
1855 _ => false,
1858 }
1859 }
1860
1861 pub fn const_eval(&self) -> Option<GlobalConstValue> {
1863 match self.ops() {
1866 [ConstOp::I32Const(x)] => Some(GlobalConstValue::I32(*x)),
1867 [ConstOp::I64Const(x)] => Some(GlobalConstValue::I64(*x)),
1868 [ConstOp::F32Const(x)] => Some(GlobalConstValue::F32(*x)),
1869 [ConstOp::F64Const(x)] => Some(GlobalConstValue::F64(*x)),
1870 [ConstOp::V128Const(x)] => Some(GlobalConstValue::V128(*x)),
1871 _ => None,
1872 }
1873 }
1874}
1875
1876#[expect(missing_docs, reason = "self-describing variants")]
1878#[derive(Clone, Copy)]
1879pub enum GlobalConstValue {
1880 I32(i32),
1881 I64(i64),
1882 F32(u32),
1883 F64(u64),
1884 V128(u128),
1885}
1886
1887#[expect(missing_docs, reason = "self-describing variants")]
1889#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1890pub enum ConstOp {
1891 I32Const(i32),
1892 I64Const(i64),
1893 F32Const(u32),
1894 F64Const(u64),
1895 V128Const(u128),
1896 GlobalGet(GlobalIndex),
1897 RefI31,
1898 RefNull(WasmHeapTopType),
1899 RefFunc(FuncIndex),
1900 I32Add,
1901 I32Sub,
1902 I32Mul,
1903 I64Add,
1904 I64Sub,
1905 I64Mul,
1906 StructNew {
1907 struct_type_index: TypeIndex,
1908 },
1909 StructNewDefault {
1910 struct_type_index: TypeIndex,
1911 },
1912 ArrayNew {
1913 array_type_index: TypeIndex,
1914 },
1915 ArrayNewDefault {
1916 array_type_index: TypeIndex,
1917 },
1918 ArrayNewFixed {
1919 array_type_index: TypeIndex,
1920 array_size: u32,
1921 },
1922 ExternConvertAny,
1923 AnyConvertExtern,
1924}
1925
1926impl ConstOp {
1927 pub fn from_wasmparser(
1929 env: &dyn TypeConvert,
1930 op: wasmparser::Operator<'_>,
1931 offset: usize,
1932 ) -> WasmResult<Self> {
1933 use wasmparser::Operator as O;
1934 Ok(match op {
1935 O::I32Const { value } => Self::I32Const(value),
1936 O::I64Const { value } => Self::I64Const(value),
1937 O::F32Const { value } => Self::F32Const(value.bits()),
1938 O::F64Const { value } => Self::F64Const(value.bits()),
1939 O::V128Const { value } => Self::V128Const(u128::from_le_bytes(*value.bytes())),
1940 O::RefNull { hty } => Self::RefNull(env.convert_heap_type(hty)?.top()),
1941 O::RefFunc { function_index } => Self::RefFunc(FuncIndex::from_u32(function_index)),
1942 O::GlobalGet { global_index } => Self::GlobalGet(GlobalIndex::from_u32(global_index)),
1943 O::RefI31 => Self::RefI31,
1944 O::I32Add => Self::I32Add,
1945 O::I32Sub => Self::I32Sub,
1946 O::I32Mul => Self::I32Mul,
1947 O::I64Add => Self::I64Add,
1948 O::I64Sub => Self::I64Sub,
1949 O::I64Mul => Self::I64Mul,
1950 O::StructNew { struct_type_index } => Self::StructNew {
1951 struct_type_index: TypeIndex::from_u32(struct_type_index),
1952 },
1953 O::StructNewDefault { struct_type_index } => Self::StructNewDefault {
1954 struct_type_index: TypeIndex::from_u32(struct_type_index),
1955 },
1956 O::ArrayNew { array_type_index } => Self::ArrayNew {
1957 array_type_index: TypeIndex::from_u32(array_type_index),
1958 },
1959 O::ArrayNewDefault { array_type_index } => Self::ArrayNewDefault {
1960 array_type_index: TypeIndex::from_u32(array_type_index),
1961 },
1962 O::ArrayNewFixed {
1963 array_type_index,
1964 array_size,
1965 } => Self::ArrayNewFixed {
1966 array_type_index: TypeIndex::from_u32(array_type_index),
1967 array_size,
1968 },
1969 O::ExternConvertAny => Self::ExternConvertAny,
1970 O::AnyConvertExtern => Self::AnyConvertExtern,
1971 op => {
1972 return Err(wasm_unsupported!(
1973 "unsupported opcode in const expression at offset {offset:#x}: {op:?}",
1974 ));
1975 }
1976 })
1977 }
1978}
1979
1980#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1982#[expect(missing_docs, reason = "self-describing variants")]
1983pub enum IndexType {
1984 I32,
1985 I64,
1986}
1987
1988#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1990#[expect(missing_docs, reason = "self-describing fields")]
1991pub struct Limits {
1992 pub min: u64,
1993 pub max: Option<u64>,
1994}
1995
1996#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1998pub struct Table {
1999 pub idx_type: IndexType,
2001 pub limits: Limits,
2004 pub ref_type: WasmRefType,
2006}
2007
2008impl TypeTrace for Table {
2009 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2010 where
2011 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2012 {
2013 let Table {
2014 ref_type: wasm_ty,
2015 idx_type: _,
2016 limits: _,
2017 } = self;
2018 wasm_ty.trace(func)
2019 }
2020
2021 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2022 where
2023 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2024 {
2025 let Table {
2026 ref_type: wasm_ty,
2027 idx_type: _,
2028 limits: _,
2029 } = self;
2030 wasm_ty.trace_mut(func)
2031 }
2032}
2033
2034#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2036pub struct Memory {
2037 pub idx_type: IndexType,
2039 pub limits: Limits,
2042 pub shared: bool,
2044 pub page_size_log2: u8,
2049}
2050
2051pub const WASM32_MAX_SIZE: u64 = 1 << 32;
2053
2054impl Memory {
2055 pub const DEFAULT_PAGE_SIZE: u32 = 0x10000;
2057
2058 pub const DEFAULT_PAGE_SIZE_LOG2: u8 = {
2060 let log2 = 16;
2061 assert!(1 << log2 == Memory::DEFAULT_PAGE_SIZE);
2062 log2
2063 };
2064
2065 pub fn minimum_byte_size(&self) -> Result<u64, SizeOverflow> {
2073 self.limits
2074 .min
2075 .checked_mul(self.page_size())
2076 .ok_or(SizeOverflow)
2077 }
2078
2079 pub fn maximum_byte_size(&self) -> Result<u64, SizeOverflow> {
2094 match self.limits.max {
2095 Some(max) => max.checked_mul(self.page_size()).ok_or(SizeOverflow),
2096 None => {
2097 let min = self.minimum_byte_size()?;
2098 Ok(min.max(self.max_size_based_on_index_type()))
2099 }
2100 }
2101 }
2102
2103 pub fn page_size(&self) -> u64 {
2105 debug_assert!(
2106 self.page_size_log2 == 16 || self.page_size_log2 == 0,
2107 "invalid page_size_log2: {}; must be 16 or 0",
2108 self.page_size_log2
2109 );
2110 1 << self.page_size_log2
2111 }
2112
2113 pub fn max_size_based_on_index_type(&self) -> u64 {
2118 match self.idx_type {
2119 IndexType::I64 =>
2120 {
2128 0_u64.wrapping_sub(self.page_size())
2129 }
2130 IndexType::I32 => WASM32_MAX_SIZE,
2131 }
2132 }
2133
2134 pub fn can_use_virtual_memory(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
2146 tunables.signals_based_traps && self.page_size_log2 >= host_page_size_log2
2147 }
2148
2149 pub fn can_elide_bounds_check(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
2169 self.can_use_virtual_memory(tunables, host_page_size_log2)
2170 && self.idx_type == IndexType::I32
2171 && tunables.memory_reservation + tunables.memory_guard_size >= (1 << 32)
2172 }
2173
2174 pub fn static_heap_size(&self) -> Option<u64> {
2178 let min = self.minimum_byte_size().ok()?;
2179 let max = self.maximum_byte_size().ok()?;
2180 if min == max { Some(min) } else { None }
2181 }
2182
2183 pub fn memory_may_move(&self, tunables: &Tunables) -> bool {
2190 if self.shared {
2194 return false;
2195 }
2196
2197 if !tunables.memory_may_move {
2200 return false;
2201 }
2202
2203 if self.limits.max.is_some_and(|max| self.limits.min == max) {
2206 return false;
2207 }
2208
2209 let max = self.maximum_byte_size().unwrap_or(u64::MAX);
2212 max > tunables.memory_reservation
2213 }
2214}
2215
2216#[derive(Copy, Clone, Debug)]
2217#[expect(missing_docs, reason = "self-describing error struct")]
2218pub struct SizeOverflow;
2219
2220impl fmt::Display for SizeOverflow {
2221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2222 f.write_str("size overflow calculating memory size")
2223 }
2224}
2225
2226impl core::error::Error for SizeOverflow {}
2227
2228impl From<wasmparser::MemoryType> for Memory {
2229 fn from(ty: wasmparser::MemoryType) -> Memory {
2230 let idx_type = match ty.memory64 {
2231 false => IndexType::I32,
2232 true => IndexType::I64,
2233 };
2234 let limits = Limits {
2235 min: ty.initial,
2236 max: ty.maximum,
2237 };
2238 let page_size_log2 = u8::try_from(ty.page_size_log2.unwrap_or(16)).unwrap();
2239 debug_assert!(
2240 page_size_log2 == 16 || page_size_log2 == 0,
2241 "invalid page_size_log2: {page_size_log2}; must be 16 or 0"
2242 );
2243 Memory {
2244 idx_type,
2245 limits,
2246 shared: ty.shared,
2247 page_size_log2,
2248 }
2249 }
2250}
2251
2252#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2254pub struct Tag {
2255 pub signature: EngineOrModuleTypeIndex,
2257 pub exception: EngineOrModuleTypeIndex,
2259}
2260
2261impl TypeTrace for Tag {
2262 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2263 where
2264 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2265 {
2266 func(self.signature)?;
2267 func(self.exception)?;
2268 Ok(())
2269 }
2270
2271 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2272 where
2273 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2274 {
2275 func(&mut self.signature)?;
2276 func(&mut self.exception)?;
2277 Ok(())
2278 }
2279}
2280
2281#[expect(missing_docs, reason = "self-describing functions")]
2283pub trait TypeConvert {
2284 fn convert_global_type(&self, ty: &wasmparser::GlobalType) -> WasmResult<Global> {
2286 Ok(Global {
2287 wasm_ty: self.convert_valtype(ty.content_type)?,
2288 mutability: ty.mutable,
2289 })
2290 }
2291
2292 fn convert_table_type(&self, ty: &wasmparser::TableType) -> WasmResult<Table> {
2294 let idx_type = match ty.table64 {
2295 false => IndexType::I32,
2296 true => IndexType::I64,
2297 };
2298 let limits = Limits {
2299 min: ty.initial,
2300 max: ty.maximum,
2301 };
2302 Ok(Table {
2303 idx_type,
2304 limits,
2305 ref_type: self.convert_ref_type(ty.element_type)?,
2306 })
2307 }
2308
2309 fn convert_sub_type(&self, ty: &wasmparser::SubType) -> WasmResult<WasmSubType> {
2310 Ok(WasmSubType {
2311 is_final: ty.is_final,
2312 supertype: ty.supertype_idx.map(|i| self.lookup_type_index(i.unpack())),
2313 composite_type: self.convert_composite_type(&ty.composite_type)?,
2314 })
2315 }
2316
2317 fn convert_composite_type(
2318 &self,
2319 ty: &wasmparser::CompositeType,
2320 ) -> WasmResult<WasmCompositeType> {
2321 let inner = match &ty.inner {
2322 wasmparser::CompositeInnerType::Func(f) => {
2323 WasmCompositeInnerType::Func(self.convert_func_type(f)?)
2324 }
2325 wasmparser::CompositeInnerType::Array(a) => {
2326 WasmCompositeInnerType::Array(self.convert_array_type(a)?)
2327 }
2328 wasmparser::CompositeInnerType::Struct(s) => {
2329 WasmCompositeInnerType::Struct(self.convert_struct_type(s)?)
2330 }
2331 wasmparser::CompositeInnerType::Cont(c) => {
2332 WasmCompositeInnerType::Cont(self.convert_cont_type(c))
2333 }
2334 };
2335 Ok(WasmCompositeType {
2336 inner,
2337 shared: ty.shared,
2338 })
2339 }
2340
2341 fn convert_cont_type(&self, ty: &wasmparser::ContType) -> WasmContType {
2343 if let WasmHeapType::ConcreteFunc(sigidx) = self.lookup_heap_type(ty.0.unpack()) {
2344 WasmContType::new(sigidx)
2345 } else {
2346 panic!("Failed to extract signature index for continuation type.")
2347 }
2348 }
2349
2350 fn convert_struct_type(&self, ty: &wasmparser::StructType) -> WasmResult<WasmStructType> {
2351 Ok(WasmStructType {
2352 fields: ty
2353 .fields
2354 .iter()
2355 .map(|f| self.convert_field_type(f))
2356 .collect::<WasmResult<_>>()?,
2357 })
2358 }
2359
2360 fn convert_array_type(&self, ty: &wasmparser::ArrayType) -> WasmResult<WasmArrayType> {
2361 Ok(WasmArrayType(self.convert_field_type(&ty.0)?))
2362 }
2363
2364 fn convert_field_type(&self, ty: &wasmparser::FieldType) -> WasmResult<WasmFieldType> {
2365 Ok(WasmFieldType {
2366 element_type: self.convert_storage_type(&ty.element_type)?,
2367 mutable: ty.mutable,
2368 })
2369 }
2370
2371 fn convert_storage_type(&self, ty: &wasmparser::StorageType) -> WasmResult<WasmStorageType> {
2372 Ok(match ty {
2373 wasmparser::StorageType::I8 => WasmStorageType::I8,
2374 wasmparser::StorageType::I16 => WasmStorageType::I16,
2375 wasmparser::StorageType::Val(v) => WasmStorageType::Val(self.convert_valtype(*v)?),
2376 })
2377 }
2378
2379 fn convert_func_type(&self, ty: &wasmparser::FuncType) -> WasmResult<WasmFuncType> {
2381 let params = ty
2382 .params()
2383 .iter()
2384 .map(|t| self.convert_valtype(*t))
2385 .collect::<WasmResult<_>>()?;
2386 let results = ty
2387 .results()
2388 .iter()
2389 .map(|t| self.convert_valtype(*t))
2390 .collect::<WasmResult<_>>()?;
2391 Ok(WasmFuncType::new(params, results))
2392 }
2393
2394 fn convert_valtype(&self, ty: wasmparser::ValType) -> WasmResult<WasmValType> {
2396 Ok(match ty {
2397 wasmparser::ValType::I32 => WasmValType::I32,
2398 wasmparser::ValType::I64 => WasmValType::I64,
2399 wasmparser::ValType::F32 => WasmValType::F32,
2400 wasmparser::ValType::F64 => WasmValType::F64,
2401 wasmparser::ValType::V128 => WasmValType::V128,
2402 wasmparser::ValType::Ref(t) => WasmValType::Ref(self.convert_ref_type(t)?),
2403 })
2404 }
2405
2406 fn convert_ref_type(&self, ty: wasmparser::RefType) -> WasmResult<WasmRefType> {
2408 Ok(WasmRefType {
2409 nullable: ty.is_nullable(),
2410 heap_type: self.convert_heap_type(ty.heap_type())?,
2411 })
2412 }
2413
2414 fn convert_heap_type(&self, ty: wasmparser::HeapType) -> WasmResult<WasmHeapType> {
2416 Ok(match ty {
2417 wasmparser::HeapType::Concrete(i) => self.lookup_heap_type(i),
2418 wasmparser::HeapType::Abstract { ty, shared: false } => match ty {
2419 wasmparser::AbstractHeapType::Extern => WasmHeapType::Extern,
2420 wasmparser::AbstractHeapType::NoExtern => WasmHeapType::NoExtern,
2421 wasmparser::AbstractHeapType::Func => WasmHeapType::Func,
2422 wasmparser::AbstractHeapType::NoFunc => WasmHeapType::NoFunc,
2423 wasmparser::AbstractHeapType::Any => WasmHeapType::Any,
2424 wasmparser::AbstractHeapType::Eq => WasmHeapType::Eq,
2425 wasmparser::AbstractHeapType::I31 => WasmHeapType::I31,
2426 wasmparser::AbstractHeapType::Array => WasmHeapType::Array,
2427 wasmparser::AbstractHeapType::Struct => WasmHeapType::Struct,
2428 wasmparser::AbstractHeapType::None => WasmHeapType::None,
2429 wasmparser::AbstractHeapType::Cont => WasmHeapType::Cont,
2430 wasmparser::AbstractHeapType::NoCont => WasmHeapType::NoCont,
2431 wasmparser::AbstractHeapType::Exn => WasmHeapType::Exn,
2432 wasmparser::AbstractHeapType::NoExn => WasmHeapType::NoExn,
2433 },
2434 _ => return Err(wasm_unsupported!("unsupported heap type {ty:?}")),
2435 })
2436 }
2437
2438 fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType;
2441
2442 fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex;
2445}