1use crate::{
2 MemoryTunables, PanicOnOom as _, Tunables, WasmResult, collections::TryCow, error::OutOfMemory,
3 prelude::*, wasm_unsupported,
4};
5use alloc::boxed::Box;
6use core::{fmt, ops::Range};
7use serde_derive::{Deserialize, Serialize};
8use smallvec::SmallVec;
9
10#[doc(hidden)]
11pub fn deserialize_boxed_slice<'de, T, D>(deserializer: D) -> Result<Box<[T]>, D::Error>
12where
13 T: serde::de::Deserialize<'de>,
14 D: serde::de::Deserializer<'de>,
15{
16 let tys: crate::collections::TryVec<T> = serde::Deserialize::deserialize(deserializer)?;
17 let tys = tys
18 .into_boxed_slice()
19 .map_err(|oom| serde::de::Error::custom(oom))?;
20 Ok(tys)
21}
22
23pub trait TypeTrace {
26 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
30 where
31 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>;
32
33 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
39 where
40 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>;
41
42 fn trace_engine_indices<F, E>(&self, func: &mut F) -> Result<(), E>
44 where
45 F: FnMut(VMSharedTypeIndex) -> Result<(), E>,
46 {
47 self.trace(&mut |idx| match idx {
48 EngineOrModuleTypeIndex::Engine(idx) => func(idx),
49 EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
50 })
51 }
52
53 fn canonicalize_for_runtime_usage<F>(&mut self, module_to_engine: &mut F)
64 where
65 F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
66 {
67 self.trace_mut::<_, ()>(&mut |idx| match idx {
68 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
69 EngineOrModuleTypeIndex::Module(module_index) => {
70 let engine_index = module_to_engine(*module_index);
71 *idx = EngineOrModuleTypeIndex::Engine(engine_index);
72 Ok(())
73 }
74 EngineOrModuleTypeIndex::RecGroup(_) => {
75 panic!("should not already be canonicalized for hash consing")
76 }
77 })
78 .unwrap()
79 }
80
81 fn is_canonicalized_for_runtime_usage(&self) -> bool {
83 self.trace(&mut |idx| match idx {
84 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
85 EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Err(()),
86 })
87 .is_ok()
88 }
89
90 fn canonicalize_for_hash_consing<F>(
101 &mut self,
102 rec_group_range: Range<ModuleInternedTypeIndex>,
103 module_to_engine: &mut F,
104 ) where
105 F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
106 {
107 self.trace_mut::<_, ()>(&mut |idx| match *idx {
108 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
109 EngineOrModuleTypeIndex::Module(module_index) => {
110 *idx = if rec_group_range.start <= module_index {
111 debug_assert!(module_index < rec_group_range.end);
114 let relative = module_index.as_u32() - rec_group_range.start.as_u32();
115 let relative = RecGroupRelativeTypeIndex::from_u32(relative);
116 EngineOrModuleTypeIndex::RecGroup(relative)
117 } else {
118 debug_assert!(module_index < rec_group_range.start);
121 EngineOrModuleTypeIndex::Engine(module_to_engine(module_index))
122 };
123 Ok(())
124 }
125 EngineOrModuleTypeIndex::RecGroup(_) => {
126 panic!("should not already be canonicalized for hash consing")
127 }
128 })
129 .unwrap()
130 }
131
132 fn is_canonicalized_for_hash_consing(&self) -> bool {
134 self.trace(&mut |idx| match idx {
135 EngineOrModuleTypeIndex::Engine(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
136 EngineOrModuleTypeIndex::Module(_) => Err(()),
137 })
138 .is_ok()
139 }
140}
141
142#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
144pub enum WasmValType {
145 I32,
147 I64,
149 F32,
151 F64,
153 V128,
155 Ref(WasmRefType),
157}
158
159impl TryClone for WasmValType {
160 fn try_clone(&self) -> Result<Self, OutOfMemory> {
161 Ok(*self)
162 }
163}
164
165impl fmt::Display for WasmValType {
166 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
167 match self {
168 WasmValType::I32 => write!(f, "i32"),
169 WasmValType::I64 => write!(f, "i64"),
170 WasmValType::F32 => write!(f, "f32"),
171 WasmValType::F64 => write!(f, "f64"),
172 WasmValType::V128 => write!(f, "v128"),
173 WasmValType::Ref(rt) => write!(f, "{rt}"),
174 }
175 }
176}
177
178impl TypeTrace for WasmValType {
179 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
180 where
181 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
182 {
183 match self {
184 WasmValType::Ref(r) => r.trace(func),
185 WasmValType::I32
186 | WasmValType::I64
187 | WasmValType::F32
188 | WasmValType::F64
189 | WasmValType::V128 => Ok(()),
190 }
191 }
192
193 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
194 where
195 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
196 {
197 match self {
198 WasmValType::Ref(r) => r.trace_mut(func),
199 WasmValType::I32
200 | WasmValType::I64
201 | WasmValType::F32
202 | WasmValType::F64
203 | WasmValType::V128 => Ok(()),
204 }
205 }
206}
207
208impl WasmValType {
209 pub const FUNCREF: WasmValType = WasmValType::Ref(WasmRefType::FUNCREF);
211
212 #[inline]
214 pub fn is_vmgcref_type(&self) -> bool {
215 match self {
216 WasmValType::Ref(r) => r.is_vmgcref_type(),
217 _ => false,
218 }
219 }
220
221 #[inline]
227 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
228 match self {
229 WasmValType::Ref(r) => r.is_vmgcref_type_and_not_i31(),
230 _ => false,
231 }
232 }
233
234 fn trampoline_type(&self) -> Self {
235 match self {
236 WasmValType::Ref(r) => WasmValType::Ref(WasmRefType {
237 nullable: true,
238 heap_type: r.heap_type.top().into(),
239 }),
240 WasmValType::I32
241 | WasmValType::I64
242 | WasmValType::F32
243 | WasmValType::F64
244 | WasmValType::V128 => *self,
245 }
246 }
247
248 pub fn int_from_bits(bits: u8) -> Self {
252 match bits {
253 32 => Self::I32,
254 64 => Self::I64,
255 size => panic!("invalid int bits for WasmValType: {size}"),
256 }
257 }
258
259 pub fn unwrap_ref_type(&self) -> WasmRefType {
263 match self {
264 WasmValType::Ref(ref_type) => *ref_type,
265 _ => panic!("Called WasmValType::unwrap_ref_type on non-reference type"),
266 }
267 }
268}
269
270#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
272pub struct WasmRefType {
273 pub nullable: bool,
275 pub heap_type: WasmHeapType,
277}
278
279impl TypeTrace for WasmRefType {
280 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
281 where
282 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
283 {
284 self.heap_type.trace(func)
285 }
286
287 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
288 where
289 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
290 {
291 self.heap_type.trace_mut(func)
292 }
293}
294
295impl WasmRefType {
296 pub const EXTERNREF: WasmRefType = WasmRefType {
298 nullable: true,
299 heap_type: WasmHeapType::Extern,
300 };
301 pub const FUNCREF: WasmRefType = WasmRefType {
303 nullable: true,
304 heap_type: WasmHeapType::Func,
305 };
306
307 #[inline]
309 pub fn is_vmgcref_type(&self) -> bool {
310 self.heap_type.is_vmgcref_type()
311 }
312
313 #[inline]
319 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
320 self.heap_type.is_vmgcref_type_and_not_i31()
321 }
322}
323
324impl fmt::Display for WasmRefType {
325 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
326 match *self {
327 Self::FUNCREF => write!(f, "funcref"),
328 Self::EXTERNREF => write!(f, "externref"),
329 _ => {
330 if self.nullable {
331 write!(f, "(ref null {})", self.heap_type)
332 } else {
333 write!(f, "(ref {})", self.heap_type)
334 }
335 }
336 }
337 }
338}
339
340#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
345pub enum EngineOrModuleTypeIndex {
346 Engine(VMSharedTypeIndex),
349
350 Module(ModuleInternedTypeIndex),
353
354 RecGroup(RecGroupRelativeTypeIndex),
358}
359
360impl From<ModuleInternedTypeIndex> for EngineOrModuleTypeIndex {
361 #[inline]
362 fn from(i: ModuleInternedTypeIndex) -> Self {
363 Self::Module(i)
364 }
365}
366
367impl From<VMSharedTypeIndex> for EngineOrModuleTypeIndex {
368 #[inline]
369 fn from(i: VMSharedTypeIndex) -> Self {
370 Self::Engine(i)
371 }
372}
373
374impl From<RecGroupRelativeTypeIndex> for EngineOrModuleTypeIndex {
375 #[inline]
376 fn from(i: RecGroupRelativeTypeIndex) -> Self {
377 Self::RecGroup(i)
378 }
379}
380
381impl fmt::Display for EngineOrModuleTypeIndex {
382 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
383 match self {
384 Self::Engine(i) => write!(f, "(engine {})", i.bits()),
385 Self::Module(i) => write!(f, "(module {})", i.as_u32()),
386 Self::RecGroup(i) => write!(f, "(recgroup {})", i.as_u32()),
387 }
388 }
389}
390
391impl EngineOrModuleTypeIndex {
392 pub fn is_engine_type_index(self) -> bool {
394 matches!(self, Self::Engine(_))
395 }
396
397 #[inline]
399 pub fn as_engine_type_index(self) -> Option<VMSharedTypeIndex> {
400 match self {
401 Self::Engine(e) => Some(e),
402 Self::RecGroup(_) | Self::Module(_) => None,
403 }
404 }
405
406 #[track_caller]
408 #[inline]
409 pub fn unwrap_engine_type_index(self) -> VMSharedTypeIndex {
410 match self.as_engine_type_index() {
411 Some(x) => x,
412 None => panic!("`unwrap_engine_type_index` on {self:?}"),
413 }
414 }
415
416 pub fn is_module_type_index(self) -> bool {
418 matches!(self, Self::Module(_))
419 }
420
421 pub fn as_module_type_index(self) -> Option<ModuleInternedTypeIndex> {
423 match self {
424 Self::Module(e) => Some(e),
425 Self::RecGroup(_) | Self::Engine(_) => None,
426 }
427 }
428
429 #[track_caller]
431 pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
432 match self.as_module_type_index() {
433 Some(x) => x,
434 None => panic!("`unwrap_module_type_index` on {self:?}"),
435 }
436 }
437
438 pub fn is_rec_group_type_index(self) -> bool {
440 matches!(self, Self::RecGroup(_))
441 }
442
443 pub fn as_rec_group_type_index(self) -> Option<RecGroupRelativeTypeIndex> {
445 match self {
446 Self::RecGroup(r) => Some(r),
447 Self::Module(_) | Self::Engine(_) => None,
448 }
449 }
450
451 #[track_caller]
453 pub fn unwrap_rec_group_type_index(self) -> RecGroupRelativeTypeIndex {
454 match self.as_rec_group_type_index() {
455 Some(x) => x,
456 None => panic!("`unwrap_rec_group_type_index` on {self:?}"),
457 }
458 }
459}
460
461#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
463#[expect(missing_docs, reason = "self-describing variants")]
464pub enum WasmHeapType {
465 Extern,
467 NoExtern,
468
469 Func,
471 ConcreteFunc(EngineOrModuleTypeIndex),
472 NoFunc,
473
474 Exn,
476 ConcreteExn(EngineOrModuleTypeIndex),
477 NoExn,
478
479 Cont,
481 ConcreteCont(EngineOrModuleTypeIndex),
482 NoCont,
483
484 Any,
486 Eq,
487 I31,
488 Array,
489 ConcreteArray(EngineOrModuleTypeIndex),
490 Struct,
491 ConcreteStruct(EngineOrModuleTypeIndex),
492 None,
493}
494
495impl From<WasmHeapTopType> for WasmHeapType {
496 #[inline]
497 fn from(value: WasmHeapTopType) -> Self {
498 match value {
499 WasmHeapTopType::Extern => Self::Extern,
500 WasmHeapTopType::Any => Self::Any,
501 WasmHeapTopType::Func => Self::Func,
502 WasmHeapTopType::Cont => Self::Cont,
503 WasmHeapTopType::Exn => Self::Exn,
504 }
505 }
506}
507
508impl From<WasmHeapBottomType> for WasmHeapType {
509 #[inline]
510 fn from(value: WasmHeapBottomType) -> Self {
511 match value {
512 WasmHeapBottomType::NoExtern => Self::NoExtern,
513 WasmHeapBottomType::None => Self::None,
514 WasmHeapBottomType::NoFunc => Self::NoFunc,
515 WasmHeapBottomType::NoCont => Self::NoCont,
516 WasmHeapBottomType::NoExn => Self::NoExn,
517 }
518 }
519}
520
521impl fmt::Display for WasmHeapType {
522 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
523 match self {
524 Self::Extern => write!(f, "extern"),
525 Self::NoExtern => write!(f, "noextern"),
526 Self::Func => write!(f, "func"),
527 Self::ConcreteFunc(i) => write!(f, "func {i}"),
528 Self::NoFunc => write!(f, "nofunc"),
529 Self::Cont => write!(f, "cont"),
530 Self::ConcreteCont(i) => write!(f, "cont {i}"),
531 Self::NoCont => write!(f, "nocont"),
532 Self::Any => write!(f, "any"),
533 Self::Eq => write!(f, "eq"),
534 Self::I31 => write!(f, "i31"),
535 Self::Array => write!(f, "array"),
536 Self::ConcreteArray(i) => write!(f, "array {i}"),
537 Self::Struct => write!(f, "struct"),
538 Self::ConcreteStruct(i) => write!(f, "struct {i}"),
539 Self::Exn => write!(f, "exn"),
540 Self::ConcreteExn(i) => write!(f, "exn {i}"),
541 Self::NoExn => write!(f, "noexn"),
542 Self::None => write!(f, "none"),
543 }
544 }
545}
546
547impl TypeTrace for WasmHeapType {
548 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
549 where
550 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
551 {
552 match *self {
553 Self::ConcreteArray(i) => func(i),
554 Self::ConcreteFunc(i) => func(i),
555 Self::ConcreteStruct(i) => func(i),
556 Self::ConcreteCont(i) => func(i),
557 Self::ConcreteExn(i) => func(i),
558 Self::Extern
561 | Self::NoExtern
562 | Self::Func
563 | Self::NoFunc
564 | Self::Cont
565 | Self::NoCont
566 | Self::Any
567 | Self::Eq
568 | Self::I31
569 | Self::Array
570 | Self::Struct
571 | Self::Exn
572 | Self::NoExn
573 | Self::None => Ok(()),
574 }
575 }
576
577 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
578 where
579 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
580 {
581 match self {
582 Self::ConcreteArray(i) => func(i),
583 Self::ConcreteFunc(i) => func(i),
584 Self::ConcreteStruct(i) => func(i),
585 Self::ConcreteCont(i) => func(i),
586 Self::ConcreteExn(i) => func(i),
587 Self::Extern
590 | Self::NoExtern
591 | Self::Func
592 | Self::NoFunc
593 | Self::Cont
594 | Self::NoCont
595 | Self::Any
596 | Self::Eq
597 | Self::I31
598 | Self::Array
599 | Self::Struct
600 | Self::Exn
601 | Self::NoExn
602 | Self::None => Ok(()),
603 }
604 }
605}
606
607impl WasmHeapType {
608 #[inline]
610 pub fn is_vmgcref_type(&self) -> bool {
611 match self.top() {
612 WasmHeapTopType::Any | WasmHeapTopType::Extern | WasmHeapTopType::Exn => true,
616
617 WasmHeapTopType::Func => false,
619 WasmHeapTopType::Cont => false,
620 }
621 }
622
623 #[inline]
629 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
630 self.is_vmgcref_type() && *self != Self::I31
631 }
632
633 #[inline]
635 pub fn is_top(&self) -> bool {
636 *self == Self::from(self.top())
637 }
638
639 #[inline]
641 pub fn top(&self) -> WasmHeapTopType {
642 match self {
643 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapTopType::Extern,
644
645 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
646 WasmHeapTopType::Func
647 }
648
649 WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
650 WasmHeapTopType::Cont
651 }
652
653 WasmHeapType::Exn | WasmHeapType::ConcreteExn(_) | WasmHeapType::NoExn => {
654 WasmHeapTopType::Exn
655 }
656
657 WasmHeapType::Any
658 | WasmHeapType::Eq
659 | WasmHeapType::I31
660 | WasmHeapType::Array
661 | WasmHeapType::ConcreteArray(_)
662 | WasmHeapType::Struct
663 | WasmHeapType::ConcreteStruct(_)
664 | WasmHeapType::None => WasmHeapTopType::Any,
665 }
666 }
667
668 #[inline]
670 pub fn is_bottom(&self) -> bool {
671 *self == Self::from(self.bottom())
672 }
673
674 #[inline]
676 pub fn bottom(&self) -> WasmHeapBottomType {
677 match self {
678 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapBottomType::NoExtern,
679
680 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
681 WasmHeapBottomType::NoFunc
682 }
683
684 WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
685 WasmHeapBottomType::NoCont
686 }
687
688 WasmHeapType::Exn | WasmHeapType::ConcreteExn(_) | WasmHeapType::NoExn => {
689 WasmHeapBottomType::NoExn
690 }
691
692 WasmHeapType::Any
693 | WasmHeapType::Eq
694 | WasmHeapType::I31
695 | WasmHeapType::Array
696 | WasmHeapType::ConcreteArray(_)
697 | WasmHeapType::Struct
698 | WasmHeapType::ConcreteStruct(_)
699 | WasmHeapType::None => WasmHeapBottomType::None,
700 }
701 }
702}
703
704#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
706pub enum WasmHeapTopType {
707 Extern,
709 Any,
711 Func,
713 Exn,
715 Cont,
717}
718
719#[derive(Debug, Clone, Copy, Eq, PartialEq)]
721pub enum WasmHeapBottomType {
722 NoExtern,
724 None,
726 NoFunc,
728 NoExn,
730 NoCont,
732}
733
734#[derive(Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
736pub struct WasmFuncType {
737 #[serde(deserialize_with = "deserialize_boxed_slice")]
738 params_results: Box<[WasmValType]>,
739 params_len: u32,
740 non_i31_gc_ref_params_count: u32,
741 non_i31_gc_ref_results_count: u32,
742}
743
744impl TryClone for WasmFuncType {
745 fn try_clone(&self) -> Result<Self, OutOfMemory> {
746 Ok(Self {
747 params_results: TryClone::try_clone(&self.params_results)?,
748 params_len: self.params_len,
749 non_i31_gc_ref_params_count: self.non_i31_gc_ref_params_count,
750 non_i31_gc_ref_results_count: self.non_i31_gc_ref_results_count,
751 })
752 }
753}
754
755impl fmt::Display for WasmFuncType {
756 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
757 write!(f, "(func")?;
758 if !self.params().is_empty() {
759 write!(f, " (param")?;
760 for p in self.params() {
761 write!(f, " {p}")?;
762 }
763 write!(f, ")")?;
764 }
765 if !self.results().is_empty() {
766 write!(f, " (result")?;
767 for r in self.results() {
768 write!(f, " {r}")?;
769 }
770 write!(f, ")")?;
771 }
772 write!(f, ")")
773 }
774}
775
776impl TypeTrace for WasmFuncType {
777 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
778 where
779 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
780 {
781 for ty in self.params_results.iter() {
782 ty.trace(func)?;
783 }
784 Ok(())
785 }
786
787 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
788 where
789 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
790 {
791 for ty in self.params_results.iter_mut() {
792 ty.trace_mut(func)?;
793 }
794 Ok(())
795 }
796}
797
798impl WasmFuncType {
799 #[inline]
801 pub fn new(
802 params: impl IntoIterator<Item = WasmValType>,
803 results: impl IntoIterator<Item = WasmValType>,
804 ) -> Result<Self, OutOfMemory> {
805 let mut params_results: crate::collections::TryVec<_> = params.into_iter().try_collect()?;
806 let non_i31_gc_ref_params_count = params_results
807 .iter()
808 .filter(|p| p.is_vmgcref_type_and_not_i31())
809 .count();
810
811 let params_len = params_results.len();
812 params_results.try_extend(results)?;
813 let non_i31_gc_ref_results_count = params_results[params_len..]
814 .iter()
815 .filter(|r| r.is_vmgcref_type_and_not_i31())
816 .count();
817
818 let params_results = params_results.into_boxed_slice()?;
819 let params_len = u32::try_from(params_len).unwrap();
820 let non_i31_gc_ref_params_count = u32::try_from(non_i31_gc_ref_params_count).unwrap();
821 let non_i31_gc_ref_results_count = u32::try_from(non_i31_gc_ref_results_count).unwrap();
822
823 Ok(Self {
824 params_results,
825 params_len,
826 non_i31_gc_ref_params_count,
827 non_i31_gc_ref_results_count,
828 })
829 }
830
831 fn results_start(&self) -> usize {
832 usize::try_from(self.params_len).unwrap()
833 }
834
835 #[inline]
837 pub fn params(&self) -> &[WasmValType] {
838 &self.params_results[..self.results_start()]
839 }
840
841 #[inline]
843 pub fn non_i31_gc_ref_params_count(&self) -> usize {
844 usize::try_from(self.non_i31_gc_ref_params_count).unwrap()
845 }
846
847 #[inline]
849 pub fn results(&self) -> &[WasmValType] {
850 &self.params_results[self.results_start()..]
851 }
852
853 #[inline]
855 pub fn non_i31_gc_ref_results_count(&self) -> usize {
856 usize::try_from(self.non_i31_gc_ref_results_count).unwrap()
857 }
858
859 pub fn is_trampoline_type(&self) -> bool {
861 self.params().iter().all(|p| *p == p.trampoline_type())
862 && self.results().iter().all(|r| *r == r.trampoline_type())
863 }
864
865 pub fn trampoline_type(&self) -> Result<TryCow<'_, Self>, OutOfMemory> {
891 if self.is_trampoline_type() {
892 return Ok(TryCow::Borrowed(self));
893 }
894
895 Ok(TryCow::Owned(Self::new(
896 self.params().iter().map(|p| p.trampoline_type()),
897 self.results().iter().map(|r| r.trampoline_type()),
898 )?))
899 }
900}
901
902#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
904pub struct WasmContType(EngineOrModuleTypeIndex);
905
906impl fmt::Display for WasmContType {
907 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
908 write!(f, "(cont {})", self.0)
909 }
910}
911
912impl WasmContType {
913 pub fn new(idx: EngineOrModuleTypeIndex) -> Self {
915 WasmContType(idx)
916 }
917
918 pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
920 match self.0 {
921 EngineOrModuleTypeIndex::Engine(_) => panic!("not module interned"),
922 EngineOrModuleTypeIndex::Module(idx) => idx,
923 EngineOrModuleTypeIndex::RecGroup(_) => todo!(),
924 }
925 }
926}
927
928impl TypeTrace for WasmContType {
929 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
930 where
931 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
932 {
933 func(self.0)
934 }
935
936 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
937 where
938 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
939 {
940 func(&mut self.0)
941 }
942}
943
944#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
969pub struct WasmExnType {
970 pub func_ty: EngineOrModuleTypeIndex,
974 #[serde(deserialize_with = "deserialize_boxed_slice")]
981 pub fields: Box<[WasmFieldType]>,
982}
983
984impl TryClone for WasmExnType {
985 fn try_clone(&self) -> Result<Self, OutOfMemory> {
986 Ok(Self {
987 func_ty: self.func_ty,
988 fields: self.fields.try_clone()?,
989 })
990 }
991}
992
993impl fmt::Display for WasmExnType {
994 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
995 write!(f, "(exn ({})", self.func_ty)?;
996 for ty in self.fields.iter() {
997 write!(f, " {ty}")?;
998 }
999 write!(f, ")")
1000 }
1001}
1002
1003impl TypeTrace for WasmExnType {
1004 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1005 where
1006 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1007 {
1008 func(self.func_ty)?;
1009 for f in self.fields.iter() {
1010 f.trace(func)?;
1011 }
1012 Ok(())
1013 }
1014
1015 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1016 where
1017 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1018 {
1019 func(&mut self.func_ty)?;
1020 for f in self.fields.iter_mut() {
1021 f.trace_mut(func)?;
1022 }
1023 Ok(())
1024 }
1025}
1026
1027#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1029pub enum WasmStorageType {
1030 I8,
1032 I16,
1034 Val(WasmValType),
1036}
1037
1038impl fmt::Display for WasmStorageType {
1039 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1040 match self {
1041 WasmStorageType::I8 => write!(f, "i8"),
1042 WasmStorageType::I16 => write!(f, "i16"),
1043 WasmStorageType::Val(v) => fmt::Display::fmt(v, f),
1044 }
1045 }
1046}
1047
1048impl TypeTrace for WasmStorageType {
1049 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1050 where
1051 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1052 {
1053 match self {
1054 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
1055 WasmStorageType::Val(v) => v.trace(func),
1056 }
1057 }
1058
1059 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1060 where
1061 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1062 {
1063 match self {
1064 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
1065 WasmStorageType::Val(v) => v.trace_mut(func),
1066 }
1067 }
1068}
1069
1070impl WasmStorageType {
1071 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
1077 match self {
1078 WasmStorageType::I8 | WasmStorageType::I16 => false,
1079 WasmStorageType::Val(v) => v.is_vmgcref_type_and_not_i31(),
1080 }
1081 }
1082}
1083
1084#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
1086pub struct WasmFieldType {
1087 pub element_type: WasmStorageType,
1089
1090 pub mutable: bool,
1092}
1093
1094impl TryClone for WasmFieldType {
1095 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1096 Ok(*self)
1097 }
1098}
1099
1100impl fmt::Display for WasmFieldType {
1101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1102 if self.mutable {
1103 write!(f, "(mut {})", self.element_type)
1104 } else {
1105 fmt::Display::fmt(&self.element_type, f)
1106 }
1107 }
1108}
1109
1110impl TypeTrace for WasmFieldType {
1111 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1112 where
1113 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1114 {
1115 self.element_type.trace(func)
1116 }
1117
1118 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1119 where
1120 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1121 {
1122 self.element_type.trace_mut(func)
1123 }
1124}
1125
1126#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
1128pub struct WasmArrayType(pub WasmFieldType);
1129
1130impl fmt::Display for WasmArrayType {
1131 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1132 write!(f, "(array {})", self.0)
1133 }
1134}
1135
1136impl TypeTrace for WasmArrayType {
1137 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1138 where
1139 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1140 {
1141 self.0.trace(func)
1142 }
1143
1144 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1145 where
1146 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1147 {
1148 self.0.trace_mut(func)
1149 }
1150}
1151
1152#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1154pub struct WasmStructType {
1155 #[serde(deserialize_with = "deserialize_boxed_slice")]
1157 pub fields: Box<[WasmFieldType]>,
1158}
1159
1160impl TryClone for WasmStructType {
1161 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1162 Ok(Self {
1163 fields: self.fields.try_clone()?,
1164 })
1165 }
1166}
1167
1168impl fmt::Display for WasmStructType {
1169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1170 write!(f, "(struct")?;
1171 for ty in self.fields.iter() {
1172 write!(f, " {ty}")?;
1173 }
1174 write!(f, ")")
1175 }
1176}
1177
1178impl TypeTrace for WasmStructType {
1179 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1180 where
1181 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1182 {
1183 for f in self.fields.iter() {
1184 f.trace(func)?;
1185 }
1186 Ok(())
1187 }
1188
1189 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1190 where
1191 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1192 {
1193 for f in self.fields.iter_mut() {
1194 f.trace_mut(func)?;
1195 }
1196 Ok(())
1197 }
1198}
1199
1200#[derive(Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1201#[expect(missing_docs, reason = "self-describing type")]
1202pub struct WasmCompositeType {
1203 pub inner: WasmCompositeInnerType,
1205 pub shared: bool,
1208}
1209
1210impl TryClone for WasmCompositeType {
1211 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1212 Ok(Self {
1213 inner: self.inner.try_clone()?,
1214 shared: self.shared,
1215 })
1216 }
1217}
1218
1219impl fmt::Display for WasmCompositeType {
1220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1221 if self.shared {
1222 write!(f, "(shared ")?;
1223 }
1224 fmt::Display::fmt(&self.inner, f)?;
1225 if self.shared {
1226 write!(f, ")")?;
1227 }
1228 Ok(())
1229 }
1230}
1231
1232#[derive(Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1234#[expect(missing_docs, reason = "self-describing variants")]
1235pub enum WasmCompositeInnerType {
1236 Array(WasmArrayType),
1237 Func(WasmFuncType),
1238 Struct(WasmStructType),
1239 Cont(WasmContType),
1240 Exn(WasmExnType),
1241}
1242
1243impl TryClone for WasmCompositeInnerType {
1244 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1245 Ok(match self {
1246 Self::Array(ty) => Self::Array(*ty),
1247 Self::Func(ty) => Self::Func(ty.try_clone()?),
1248 Self::Struct(ty) => Self::Struct(ty.try_clone()?),
1249 Self::Cont(ty) => Self::Cont(*ty),
1250 Self::Exn(ty) => Self::Exn(ty.try_clone()?),
1251 })
1252 }
1253}
1254
1255impl fmt::Display for WasmCompositeInnerType {
1256 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1257 match self {
1258 Self::Array(ty) => fmt::Display::fmt(ty, f),
1259 Self::Func(ty) => fmt::Display::fmt(ty, f),
1260 Self::Struct(ty) => fmt::Display::fmt(ty, f),
1261 Self::Cont(ty) => fmt::Display::fmt(ty, f),
1262 Self::Exn(ty) => fmt::Display::fmt(ty, f),
1263 }
1264 }
1265}
1266
1267#[expect(missing_docs, reason = "self-describing functions")]
1268impl WasmCompositeInnerType {
1269 #[inline]
1270 pub fn is_array(&self) -> bool {
1271 matches!(self, Self::Array(_))
1272 }
1273
1274 #[inline]
1275 pub fn as_array(&self) -> Option<&WasmArrayType> {
1276 match self {
1277 Self::Array(f) => Some(f),
1278 _ => None,
1279 }
1280 }
1281
1282 #[inline]
1283 pub fn unwrap_array(&self) -> &WasmArrayType {
1284 self.as_array().unwrap()
1285 }
1286
1287 #[inline]
1288 pub fn is_func(&self) -> bool {
1289 matches!(self, Self::Func(_))
1290 }
1291
1292 #[inline]
1293 pub fn as_func(&self) -> Option<&WasmFuncType> {
1294 match self {
1295 Self::Func(f) => Some(f),
1296 _ => None,
1297 }
1298 }
1299
1300 #[inline]
1301 pub fn unwrap_func(&self) -> &WasmFuncType {
1302 self.as_func().unwrap()
1303 }
1304
1305 #[inline]
1306 pub fn is_struct(&self) -> bool {
1307 matches!(self, Self::Struct(_))
1308 }
1309
1310 #[inline]
1311 pub fn as_struct(&self) -> Option<&WasmStructType> {
1312 match self {
1313 Self::Struct(f) => Some(f),
1314 _ => None,
1315 }
1316 }
1317
1318 #[inline]
1319 pub fn unwrap_struct(&self) -> &WasmStructType {
1320 self.as_struct().unwrap()
1321 }
1322
1323 #[inline]
1324 pub fn is_cont(&self) -> bool {
1325 matches!(self, Self::Cont(_))
1326 }
1327
1328 #[inline]
1329 pub fn as_cont(&self) -> Option<&WasmContType> {
1330 match self {
1331 Self::Cont(f) => Some(f),
1332 _ => None,
1333 }
1334 }
1335
1336 #[inline]
1337 pub fn unwrap_cont(&self) -> &WasmContType {
1338 self.as_cont().unwrap()
1339 }
1340
1341 #[inline]
1342 pub fn is_exn(&self) -> bool {
1343 matches!(self, Self::Exn(_))
1344 }
1345
1346 #[inline]
1347 pub fn as_exn(&self) -> Option<&WasmExnType> {
1348 match self {
1349 Self::Exn(f) => Some(f),
1350 _ => None,
1351 }
1352 }
1353
1354 #[inline]
1355 pub fn unwrap_exn(&self) -> &WasmExnType {
1356 self.as_exn().unwrap()
1357 }
1358}
1359
1360impl TypeTrace for WasmCompositeType {
1361 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1362 where
1363 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1364 {
1365 match &self.inner {
1366 WasmCompositeInnerType::Array(a) => a.trace(func),
1367 WasmCompositeInnerType::Func(f) => f.trace(func),
1368 WasmCompositeInnerType::Struct(a) => a.trace(func),
1369 WasmCompositeInnerType::Cont(c) => c.trace(func),
1370 WasmCompositeInnerType::Exn(e) => e.trace(func),
1371 }
1372 }
1373
1374 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1375 where
1376 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1377 {
1378 match &mut self.inner {
1379 WasmCompositeInnerType::Array(a) => a.trace_mut(func),
1380 WasmCompositeInnerType::Func(f) => f.trace_mut(func),
1381 WasmCompositeInnerType::Struct(a) => a.trace_mut(func),
1382 WasmCompositeInnerType::Cont(c) => c.trace_mut(func),
1383 WasmCompositeInnerType::Exn(e) => e.trace_mut(func),
1384 }
1385 }
1386}
1387
1388#[derive(Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1390pub struct WasmSubType {
1391 pub is_final: bool,
1394
1395 pub supertype: Option<EngineOrModuleTypeIndex>,
1397
1398 pub composite_type: WasmCompositeType,
1400}
1401
1402impl TryClone for WasmSubType {
1403 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1404 Ok(Self {
1405 is_final: self.is_final,
1406 supertype: self.supertype,
1407 composite_type: self.composite_type.try_clone()?,
1408 })
1409 }
1410}
1411
1412impl fmt::Display for WasmSubType {
1413 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1414 if self.is_final && self.supertype.is_none() {
1415 fmt::Display::fmt(&self.composite_type, f)
1416 } else {
1417 write!(f, "(sub")?;
1418 if self.is_final {
1419 write!(f, " final")?;
1420 }
1421 if let Some(sup) = self.supertype {
1422 write!(f, " {sup}")?;
1423 }
1424 write!(f, " {})", self.composite_type)
1425 }
1426 }
1427}
1428
1429#[expect(missing_docs, reason = "self-describing functions")]
1433impl WasmSubType {
1434 #[inline]
1435 pub fn is_func(&self) -> bool {
1436 self.composite_type.inner.is_func() && !self.composite_type.shared
1437 }
1438
1439 #[inline]
1440 pub fn as_func(&self) -> Option<&WasmFuncType> {
1441 if self.composite_type.shared {
1442 None
1443 } else {
1444 self.composite_type.inner.as_func()
1445 }
1446 }
1447
1448 #[inline]
1449 pub fn unwrap_func(&self) -> &WasmFuncType {
1450 assert!(!self.composite_type.shared);
1451 self.composite_type.inner.unwrap_func()
1452 }
1453
1454 #[inline]
1455 pub fn is_array(&self) -> bool {
1456 self.composite_type.inner.is_array() && !self.composite_type.shared
1457 }
1458
1459 #[inline]
1460 pub fn as_array(&self) -> Option<&WasmArrayType> {
1461 if self.composite_type.shared {
1462 None
1463 } else {
1464 self.composite_type.inner.as_array()
1465 }
1466 }
1467
1468 #[inline]
1469 pub fn unwrap_array(&self) -> &WasmArrayType {
1470 assert!(!self.composite_type.shared);
1471 self.composite_type.inner.unwrap_array()
1472 }
1473
1474 #[inline]
1475 pub fn is_struct(&self) -> bool {
1476 self.composite_type.inner.is_struct() && !self.composite_type.shared
1477 }
1478
1479 #[inline]
1480 pub fn as_struct(&self) -> Option<&WasmStructType> {
1481 if self.composite_type.shared {
1482 None
1483 } else {
1484 self.composite_type.inner.as_struct()
1485 }
1486 }
1487
1488 #[inline]
1489 pub fn unwrap_struct(&self) -> &WasmStructType {
1490 assert!(!self.composite_type.shared);
1491 self.composite_type.inner.unwrap_struct()
1492 }
1493
1494 #[inline]
1495 pub fn is_cont(&self) -> bool {
1496 self.composite_type.inner.is_cont() && !self.composite_type.shared
1497 }
1498
1499 #[inline]
1500 pub fn as_cont(&self) -> Option<&WasmContType> {
1501 if self.composite_type.shared {
1502 None
1503 } else {
1504 self.composite_type.inner.as_cont()
1505 }
1506 }
1507
1508 #[inline]
1509 pub fn unwrap_cont(&self) -> &WasmContType {
1510 assert!(!self.composite_type.shared);
1511 self.composite_type.inner.unwrap_cont()
1512 }
1513
1514 #[inline]
1515 pub fn is_exn(&self) -> bool {
1516 self.composite_type.inner.is_exn() && !self.composite_type.shared
1517 }
1518
1519 #[inline]
1520 pub fn as_exn(&self) -> Option<&WasmExnType> {
1521 if self.composite_type.shared {
1522 None
1523 } else {
1524 self.composite_type.inner.as_exn()
1525 }
1526 }
1527
1528 #[inline]
1529 pub fn unwrap_exn(&self) -> &WasmExnType {
1530 assert!(!self.composite_type.shared);
1531 self.composite_type.inner.unwrap_exn()
1532 }
1533}
1534
1535impl TypeTrace for WasmSubType {
1536 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1537 where
1538 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1539 {
1540 if let Some(sup) = self.supertype {
1541 func(sup)?;
1542 }
1543 self.composite_type.trace(func)
1544 }
1545
1546 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1547 where
1548 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1549 {
1550 if let Some(sup) = self.supertype.as_mut() {
1551 func(sup)?;
1552 }
1553 self.composite_type.trace_mut(func)
1554 }
1555}
1556
1557#[derive(Debug, Default, Eq, PartialEq, Hash, Serialize, Deserialize)]
1568pub struct WasmRecGroup {
1569 #[serde(deserialize_with = "deserialize_boxed_slice")]
1571 pub types: Box<[WasmSubType]>,
1572}
1573
1574impl TypeTrace for WasmRecGroup {
1575 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1576 where
1577 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1578 {
1579 for ty in self.types.iter() {
1580 ty.trace(func)?;
1581 }
1582 Ok(())
1583 }
1584
1585 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1586 where
1587 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1588 {
1589 for ty in self.types.iter_mut() {
1590 ty.trace_mut(func)?;
1591 }
1592 Ok(())
1593 }
1594}
1595
1596macro_rules! entity_impl_with_try_clone {
1597 ( $ty:ident ) => {
1598 cranelift_entity::entity_impl!($ty);
1599
1600 impl TryClone for $ty {
1601 #[inline]
1602 fn try_clone(&self) -> Result<Self, $crate::error::OutOfMemory> {
1603 Ok(*self)
1604 }
1605 }
1606 };
1607}
1608
1609#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1611pub struct FuncIndex(u32);
1612entity_impl_with_try_clone!(FuncIndex);
1613
1614#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1616pub struct DefinedFuncIndex(u32);
1617entity_impl_with_try_clone!(DefinedFuncIndex);
1618
1619#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1621pub struct DefinedTableIndex(u32);
1622entity_impl_with_try_clone!(DefinedTableIndex);
1623
1624#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1626pub struct DefinedMemoryIndex(u32);
1627entity_impl_with_try_clone!(DefinedMemoryIndex);
1628
1629#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1631pub struct OwnedMemoryIndex(u32);
1632entity_impl_with_try_clone!(OwnedMemoryIndex);
1633
1634#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1636pub struct DefinedGlobalIndex(u32);
1637entity_impl_with_try_clone!(DefinedGlobalIndex);
1638
1639#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1641pub struct TableIndex(u32);
1642entity_impl_with_try_clone!(TableIndex);
1643
1644#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1646pub struct GlobalIndex(u32);
1647entity_impl_with_try_clone!(GlobalIndex);
1648
1649#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1651pub struct MemoryIndex(u32);
1652entity_impl_with_try_clone!(MemoryIndex);
1653
1654#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1657pub struct ModuleInternedRecGroupIndex(u32);
1658entity_impl_with_try_clone!(ModuleInternedRecGroupIndex);
1659
1660#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1663pub struct EngineInternedRecGroupIndex(u32);
1664entity_impl_with_try_clone!(EngineInternedRecGroupIndex);
1665
1666#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1668pub struct TypeIndex(u32);
1669entity_impl_with_try_clone!(TypeIndex);
1670
1671#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1677pub struct RecGroupRelativeTypeIndex(u32);
1678entity_impl_with_try_clone!(RecGroupRelativeTypeIndex);
1679
1680#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1688pub struct ModuleInternedTypeIndex(u32);
1689entity_impl_with_try_clone!(ModuleInternedTypeIndex);
1690
1691#[repr(transparent)] #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1700pub struct VMSharedTypeIndex(u32);
1701entity_impl_with_try_clone!(VMSharedTypeIndex);
1702
1703impl VMSharedTypeIndex {
1704 #[inline]
1706 pub fn new(value: u32) -> Self {
1707 assert_ne!(
1708 value,
1709 u32::MAX,
1710 "u32::MAX is reserved for the default value"
1711 );
1712 Self(value)
1713 }
1714
1715 #[inline]
1717 pub fn bits(&self) -> u32 {
1718 self.0
1719 }
1720}
1721
1722impl Default for VMSharedTypeIndex {
1723 #[inline]
1724 fn default() -> Self {
1725 Self(u32::MAX)
1726 }
1727}
1728
1729#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1731pub struct DataIndex(u32);
1732entity_impl_with_try_clone!(DataIndex);
1733
1734#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1745pub struct RuntimeDataIndex(u32);
1746entity_impl_with_try_clone!(RuntimeDataIndex);
1747
1748#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1750pub struct ElemIndex(u32);
1751entity_impl_with_try_clone!(ElemIndex);
1752
1753#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1758pub struct PassiveElemIndex(u32);
1759entity_impl_with_try_clone!(PassiveElemIndex);
1760
1761#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1763pub struct DefinedTagIndex(u32);
1764entity_impl_with_try_clone!(DefinedTagIndex);
1765
1766#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1768pub struct TagIndex(u32);
1769entity_impl_with_try_clone!(TagIndex);
1770
1771#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1776pub struct StaticModuleIndex(u32);
1777entity_impl_with_try_clone!(StaticModuleIndex);
1778
1779#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1781pub enum EntityIndex {
1782 Function(FuncIndex),
1784 Table(TableIndex),
1786 Memory(MemoryIndex),
1788 Global(GlobalIndex),
1790 Tag(TagIndex),
1792}
1793
1794impl From<FuncIndex> for EntityIndex {
1795 fn from(idx: FuncIndex) -> EntityIndex {
1796 EntityIndex::Function(idx)
1797 }
1798}
1799
1800impl From<TableIndex> for EntityIndex {
1801 fn from(idx: TableIndex) -> EntityIndex {
1802 EntityIndex::Table(idx)
1803 }
1804}
1805
1806impl From<MemoryIndex> for EntityIndex {
1807 fn from(idx: MemoryIndex) -> EntityIndex {
1808 EntityIndex::Memory(idx)
1809 }
1810}
1811
1812impl From<GlobalIndex> for EntityIndex {
1813 fn from(idx: GlobalIndex) -> EntityIndex {
1814 EntityIndex::Global(idx)
1815 }
1816}
1817
1818impl From<TagIndex> for EntityIndex {
1819 fn from(idx: TagIndex) -> EntityIndex {
1820 EntityIndex::Tag(idx)
1821 }
1822}
1823
1824#[derive(Clone, Debug, Serialize, Deserialize)]
1827pub enum EntityType {
1828 Global(Global),
1830 Memory(Memory),
1832 Tag(Tag),
1834 Table(Table),
1836 Function(EngineOrModuleTypeIndex),
1839}
1840
1841impl TypeTrace for EntityType {
1842 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1843 where
1844 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1845 {
1846 match self {
1847 Self::Global(g) => g.trace(func),
1848 Self::Table(t) => t.trace(func),
1849 Self::Function(idx) => func(*idx),
1850 Self::Memory(_) => Ok(()),
1851 Self::Tag(t) => t.trace(func),
1852 }
1853 }
1854
1855 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1856 where
1857 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1858 {
1859 match self {
1860 Self::Global(g) => g.trace_mut(func),
1861 Self::Table(t) => t.trace_mut(func),
1862 Self::Function(idx) => func(idx),
1863 Self::Memory(_) => Ok(()),
1864 Self::Tag(t) => t.trace_mut(func),
1865 }
1866 }
1867}
1868
1869impl EntityType {
1870 pub fn unwrap_global(&self) -> &Global {
1872 match self {
1873 EntityType::Global(g) => g,
1874 _ => panic!("not a global"),
1875 }
1876 }
1877
1878 pub fn unwrap_memory(&self) -> &Memory {
1880 match self {
1881 EntityType::Memory(g) => g,
1882 _ => panic!("not a memory"),
1883 }
1884 }
1885
1886 pub fn unwrap_tag(&self) -> &Tag {
1888 match self {
1889 EntityType::Tag(g) => g,
1890 _ => panic!("not a tag"),
1891 }
1892 }
1893
1894 pub fn unwrap_table(&self) -> &Table {
1896 match self {
1897 EntityType::Table(g) => g,
1898 _ => panic!("not a table"),
1899 }
1900 }
1901
1902 pub fn unwrap_func(&self) -> EngineOrModuleTypeIndex {
1904 match self {
1905 EntityType::Function(g) => *g,
1906 _ => panic!("not a func"),
1907 }
1908 }
1909}
1910
1911#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1919pub struct Global {
1920 pub wasm_ty: crate::WasmValType,
1922 pub mutability: bool,
1924}
1925
1926impl TypeTrace for Global {
1927 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1928 where
1929 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1930 {
1931 let Global {
1932 wasm_ty,
1933 mutability: _,
1934 } = self;
1935 wasm_ty.trace(func)
1936 }
1937
1938 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1939 where
1940 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1941 {
1942 let Global {
1943 wasm_ty,
1944 mutability: _,
1945 } = self;
1946 wasm_ty.trace_mut(func)
1947 }
1948}
1949
1950#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1954pub struct ConstExpr {
1955 ops: SmallVec<[ConstOp; 2]>,
1956}
1957
1958impl ConstExpr {
1959 pub fn new(ops: impl IntoIterator<Item = ConstOp>) -> Self {
1965 let ops = ops.into_iter().collect::<SmallVec<[ConstOp; 2]>>();
1966 assert!(!ops.is_empty());
1967 ConstExpr { ops }
1968 }
1969
1970 pub fn from_wasmparser(
1975 env: &dyn TypeConvert,
1976 expr: wasmparser::ConstExpr<'_>,
1977 ) -> WasmResult<(Self, SmallVec<[FuncIndex; 1]>)> {
1978 let mut iter = expr
1979 .get_operators_reader()
1980 .into_iter_with_offsets()
1981 .peekable();
1982
1983 let mut ops = SmallVec::<[ConstOp; 2]>::new();
1984 let mut escaped = SmallVec::<[FuncIndex; 1]>::new();
1985 while let Some(res) = iter.next() {
1986 let (op, offset) = res?;
1987
1988 if matches!(op, wasmparser::Operator::End) && iter.peek().is_none() {
1992 break;
1993 }
1994
1995 if let wasmparser::Operator::RefFunc { function_index } = &op {
1998 escaped.push(FuncIndex::from_u32(*function_index));
1999 }
2000
2001 ops.push(ConstOp::from_wasmparser(env, op, offset)?);
2002 }
2003 Ok((Self { ops }, escaped))
2004 }
2005
2006 #[inline]
2008 pub fn ops(&self) -> &[ConstOp] {
2009 &self.ops
2010 }
2011
2012 pub fn provably_nonzero_i32(&self) -> bool {
2022 match self.const_eval() {
2023 Some(GlobalConstValue::I32(x)) => x != 0,
2024
2025 _ => false,
2028 }
2029 }
2030
2031 pub fn const_eval(&self) -> Option<GlobalConstValue> {
2033 match self.ops() {
2036 [ConstOp::I32Const(x)] => Some(GlobalConstValue::I32(*x)),
2037 [ConstOp::I64Const(x)] => Some(GlobalConstValue::I64(*x)),
2038 [ConstOp::F32Const(x)] => Some(GlobalConstValue::F32(*x)),
2039 [ConstOp::F64Const(x)] => Some(GlobalConstValue::F64(*x)),
2040 [ConstOp::V128Const(x)] => Some(GlobalConstValue::V128(*x)),
2041 _ => None,
2042 }
2043 }
2044}
2045
2046#[expect(missing_docs, reason = "self-describing variants")]
2048#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
2049pub enum GlobalConstValue {
2050 I32(i32),
2051 I64(i64),
2052 F32(u32),
2053 F64(u64),
2054 V128(u128),
2055}
2056
2057#[expect(missing_docs, reason = "self-describing variants")]
2059#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
2060pub enum ConstOp {
2061 I32Const(i32),
2062 I64Const(i64),
2063 F32Const(u32),
2064 F64Const(u64),
2065 V128Const(u128),
2066 GlobalGet(GlobalIndex),
2067 RefI31,
2068 RefNull(WasmHeapType),
2069 RefFunc(FuncIndex),
2070 I32Add,
2071 I32Sub,
2072 I32Mul,
2073 I64Add,
2074 I64Sub,
2075 I64Mul,
2076 StructNew {
2077 struct_type_index: TypeIndex,
2078 },
2079 StructNewDefault {
2080 struct_type_index: TypeIndex,
2081 },
2082 ArrayNew {
2083 array_type_index: TypeIndex,
2084 },
2085 ArrayNewDefault {
2086 array_type_index: TypeIndex,
2087 },
2088 ArrayNewFixed {
2089 array_type_index: TypeIndex,
2090 array_size: u32,
2091 },
2092 ExternConvertAny,
2093 AnyConvertExtern,
2094}
2095
2096impl ConstOp {
2097 pub fn from_wasmparser(
2099 env: &dyn TypeConvert,
2100 op: wasmparser::Operator<'_>,
2101 offset: u64,
2102 ) -> WasmResult<Self> {
2103 use wasmparser::Operator as O;
2104 Ok(match op {
2105 O::I32Const { value } => Self::I32Const(value),
2106 O::I64Const { value } => Self::I64Const(value),
2107 O::F32Const { value } => Self::F32Const(value.bits()),
2108 O::F64Const { value } => Self::F64Const(value.bits()),
2109 O::V128Const { value } => Self::V128Const(u128::from_le_bytes(*value.bytes())),
2110 O::RefNull { hty } => Self::RefNull(env.convert_heap_type(hty)?),
2111 O::RefFunc { function_index } => Self::RefFunc(FuncIndex::from_u32(function_index)),
2112 O::GlobalGet { global_index } => Self::GlobalGet(GlobalIndex::from_u32(global_index)),
2113 O::RefI31 => Self::RefI31,
2114 O::I32Add => Self::I32Add,
2115 O::I32Sub => Self::I32Sub,
2116 O::I32Mul => Self::I32Mul,
2117 O::I64Add => Self::I64Add,
2118 O::I64Sub => Self::I64Sub,
2119 O::I64Mul => Self::I64Mul,
2120 O::StructNew { struct_type_index } => Self::StructNew {
2121 struct_type_index: TypeIndex::from_u32(struct_type_index),
2122 },
2123 O::StructNewDefault { struct_type_index } => Self::StructNewDefault {
2124 struct_type_index: TypeIndex::from_u32(struct_type_index),
2125 },
2126 O::ArrayNew { array_type_index } => Self::ArrayNew {
2127 array_type_index: TypeIndex::from_u32(array_type_index),
2128 },
2129 O::ArrayNewDefault { array_type_index } => Self::ArrayNewDefault {
2130 array_type_index: TypeIndex::from_u32(array_type_index),
2131 },
2132 O::ArrayNewFixed {
2133 array_type_index,
2134 array_size,
2135 } => Self::ArrayNewFixed {
2136 array_type_index: TypeIndex::from_u32(array_type_index),
2137 array_size,
2138 },
2139 O::ExternConvertAny => Self::ExternConvertAny,
2140 O::AnyConvertExtern => Self::AnyConvertExtern,
2141 op => {
2142 return Err(wasm_unsupported!(
2143 "unsupported opcode in const expression at offset {offset:#x}: {op:?}",
2144 ));
2145 }
2146 })
2147 }
2148
2149 pub fn to_operator(&self) -> wasmparser::Operator<'static> {
2154 use wasmparser::{AbstractHeapType, HeapType, Ieee32, Ieee64, Operator, V128};
2155 match self {
2156 ConstOp::I32Const(value) => Operator::I32Const { value: *value },
2157 ConstOp::I64Const(value) => Operator::I64Const { value: *value },
2158 ConstOp::F32Const(bits) => Operator::F32Const {
2159 value: Ieee32::from(f32::from_bits(*bits)),
2160 },
2161 ConstOp::F64Const(bits) => Operator::F64Const {
2162 value: Ieee64::from(f64::from_bits(*bits)),
2163 },
2164 ConstOp::V128Const(value) => Operator::V128Const {
2165 value: V128::from(*value as i128),
2166 },
2167 ConstOp::GlobalGet(index) => Operator::GlobalGet {
2168 global_index: index.as_u32(),
2169 },
2170 ConstOp::RefI31 => Operator::RefI31,
2171 ConstOp::RefNull(_) => Operator::RefNull {
2172 hty: HeapType::Abstract {
2173 shared: false,
2174 ty: AbstractHeapType::Any,
2175 },
2176 },
2177 ConstOp::RefFunc(index) => Operator::RefFunc {
2178 function_index: index.as_u32(),
2179 },
2180 ConstOp::I32Add => Operator::I32Add,
2181 ConstOp::I32Sub => Operator::I32Sub,
2182 ConstOp::I32Mul => Operator::I32Mul,
2183 ConstOp::I64Add => Operator::I64Add,
2184 ConstOp::I64Sub => Operator::I64Sub,
2185 ConstOp::I64Mul => Operator::I64Mul,
2186 ConstOp::StructNew { struct_type_index } => Operator::StructNew {
2187 struct_type_index: struct_type_index.as_u32(),
2188 },
2189 ConstOp::StructNewDefault { struct_type_index } => Operator::StructNewDefault {
2190 struct_type_index: struct_type_index.as_u32(),
2191 },
2192 ConstOp::ArrayNew { array_type_index } => Operator::ArrayNew {
2193 array_type_index: array_type_index.as_u32(),
2194 },
2195 ConstOp::ArrayNewDefault { array_type_index } => Operator::ArrayNewDefault {
2196 array_type_index: array_type_index.as_u32(),
2197 },
2198 ConstOp::ArrayNewFixed {
2199 array_type_index,
2200 array_size,
2201 } => Operator::ArrayNewFixed {
2202 array_type_index: array_type_index.as_u32(),
2203 array_size: *array_size,
2204 },
2205 ConstOp::ExternConvertAny => Operator::ExternConvertAny,
2206 ConstOp::AnyConvertExtern => Operator::AnyConvertExtern,
2207 }
2208 }
2209}
2210
2211#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2213#[expect(missing_docs, reason = "self-describing variants")]
2214pub enum IndexType {
2215 I32,
2216 I64,
2217}
2218
2219#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2221#[expect(missing_docs, reason = "self-describing fields")]
2222pub struct Limits {
2223 pub min: u64,
2224 pub max: Option<u64>,
2225}
2226
2227#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2229pub struct Table {
2230 pub idx_type: IndexType,
2232 pub limits: Limits,
2235 pub ref_type: WasmRefType,
2237}
2238
2239impl TypeTrace for Table {
2240 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2241 where
2242 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2243 {
2244 let Table {
2245 ref_type: wasm_ty,
2246 idx_type: _,
2247 limits: _,
2248 } = self;
2249 wasm_ty.trace(func)
2250 }
2251
2252 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2253 where
2254 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2255 {
2256 let Table {
2257 ref_type: wasm_ty,
2258 idx_type: _,
2259 limits: _,
2260 } = self;
2261 wasm_ty.trace_mut(func)
2262 }
2263}
2264
2265#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2267pub struct Memory {
2268 pub idx_type: IndexType,
2270 pub limits: Limits,
2273 pub shared: bool,
2275 pub page_size_log2: u8,
2280}
2281
2282pub const WASM32_MAX_SIZE: u64 = 1 << 32;
2284
2285impl Memory {
2286 pub const DEFAULT_PAGE_SIZE: u32 = 0x10000;
2288
2289 pub const DEFAULT_PAGE_SIZE_LOG2: u8 = {
2291 let log2 = 16;
2292 assert!(1 << log2 == Memory::DEFAULT_PAGE_SIZE);
2293 log2
2294 };
2295
2296 pub fn minimum_byte_size(&self) -> Result<u64, SizeOverflow> {
2304 self.limits
2305 .min
2306 .checked_mul(self.page_size())
2307 .ok_or(SizeOverflow)
2308 }
2309
2310 pub fn maximum_byte_size(&self) -> Result<u64, SizeOverflow> {
2325 match self.limits.max {
2326 Some(max) => max.checked_mul(self.page_size()).ok_or(SizeOverflow),
2327 None => {
2328 let min = self.minimum_byte_size()?;
2329 Ok(min.max(self.max_size_based_on_index_type()))
2330 }
2331 }
2332 }
2333
2334 pub fn page_size(&self) -> u64 {
2336 debug_assert!(
2337 self.page_size_log2 == 16 || self.page_size_log2 == 0,
2338 "invalid page_size_log2: {}; must be 16 or 0",
2339 self.page_size_log2
2340 );
2341 1 << self.page_size_log2
2342 }
2343
2344 pub fn max_size_based_on_index_type(&self) -> u64 {
2349 match self.idx_type {
2350 IndexType::I64 =>
2351 {
2359 0_u64.wrapping_sub(self.page_size())
2360 }
2361 IndexType::I32 => WASM32_MAX_SIZE,
2362 }
2363 }
2364
2365 pub fn can_use_virtual_memory(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
2377 tunables.signals_based_traps && self.page_size_log2 >= host_page_size_log2
2378 }
2379
2380 pub fn can_elide_bounds_check(
2400 &self,
2401 memory_tunables: &MemoryTunables<'_>,
2402 host_page_size_log2: u8,
2403 ) -> bool {
2404 self.can_use_virtual_memory(memory_tunables.tunables(), host_page_size_log2)
2405 && self.idx_type == IndexType::I32
2406 && memory_tunables.reservation() + memory_tunables.guard_size() >= (1 << 32)
2407 }
2408
2409 pub fn static_heap_size(&self) -> Option<u64> {
2413 let min = self.minimum_byte_size().ok()?;
2414 let max = self.maximum_byte_size().ok()?;
2415 if min == max { Some(min) } else { None }
2416 }
2417
2418 pub fn memory_may_move(&self, memory_tunables: &MemoryTunables<'_>) -> bool {
2425 if self.shared {
2429 return false;
2430 }
2431
2432 if !memory_tunables.may_move() {
2435 return false;
2436 }
2437
2438 if self.limits.max.is_some_and(|max| self.limits.min == max) {
2441 return false;
2442 }
2443
2444 let max = self.maximum_byte_size().unwrap_or(u64::MAX);
2447 max > memory_tunables.reservation()
2448 }
2449
2450 pub fn allow_growth_to(&self, size: usize) -> bool {
2460 if self.page_size_log2 != 0 {
2461 return true;
2462 }
2463 match self.idx_type {
2464 IndexType::I32 => size < 0xffff_ffff,
2473
2474 IndexType::I64 => true,
2477 }
2478 }
2479}
2480
2481#[derive(Copy, Clone, Debug)]
2482#[expect(missing_docs, reason = "self-describing error struct")]
2483pub struct SizeOverflow;
2484
2485impl fmt::Display for SizeOverflow {
2486 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2487 f.write_str("size overflow calculating memory size")
2488 }
2489}
2490
2491impl core::error::Error for SizeOverflow {}
2492
2493impl From<wasmparser::MemoryType> for Memory {
2494 fn from(ty: wasmparser::MemoryType) -> Memory {
2495 let idx_type = match ty.memory64 {
2496 false => IndexType::I32,
2497 true => IndexType::I64,
2498 };
2499 let limits = Limits {
2500 min: ty.initial,
2501 max: ty.maximum,
2502 };
2503 let page_size_log2 = u8::try_from(ty.page_size_log2.unwrap_or(16)).unwrap();
2504 debug_assert!(
2505 page_size_log2 == 16 || page_size_log2 == 0,
2506 "invalid page_size_log2: {page_size_log2}; must be 16 or 0"
2507 );
2508 Memory {
2509 idx_type,
2510 limits,
2511 shared: ty.shared,
2512 page_size_log2,
2513 }
2514 }
2515}
2516
2517#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2519pub struct Tag {
2520 pub signature: EngineOrModuleTypeIndex,
2522 pub exception: EngineOrModuleTypeIndex,
2524}
2525
2526impl TypeTrace for Tag {
2527 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2528 where
2529 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2530 {
2531 func(self.signature)?;
2532 func(self.exception)?;
2533 Ok(())
2534 }
2535
2536 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2537 where
2538 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2539 {
2540 func(&mut self.signature)?;
2541 func(&mut self.exception)?;
2542 Ok(())
2543 }
2544}
2545
2546#[expect(missing_docs, reason = "self-describing functions")]
2548pub trait TypeConvert {
2549 fn convert_global_type(&self, ty: &wasmparser::GlobalType) -> WasmResult<Global> {
2551 Ok(Global {
2552 wasm_ty: self.convert_valtype(ty.content_type)?,
2553 mutability: ty.mutable,
2554 })
2555 }
2556
2557 fn convert_table_type(&self, ty: &wasmparser::TableType) -> WasmResult<Table> {
2559 let idx_type = match ty.table64 {
2560 false => IndexType::I32,
2561 true => IndexType::I64,
2562 };
2563 let limits = Limits {
2564 min: ty.initial,
2565 max: ty.maximum,
2566 };
2567 Ok(Table {
2568 idx_type,
2569 limits,
2570 ref_type: self.convert_ref_type(ty.element_type)?,
2571 })
2572 }
2573
2574 fn convert_sub_type(&self, ty: &wasmparser::SubType) -> WasmResult<WasmSubType> {
2575 Ok(WasmSubType {
2576 is_final: ty.is_final,
2577 supertype: ty.supertype_idx.map(|i| self.lookup_type_index(i.unpack())),
2578 composite_type: self.convert_composite_type(&ty.composite_type)?,
2579 })
2580 }
2581
2582 fn convert_composite_type(
2583 &self,
2584 ty: &wasmparser::CompositeType,
2585 ) -> WasmResult<WasmCompositeType> {
2586 let inner = match &ty.inner {
2587 wasmparser::CompositeInnerType::Func(f) => {
2588 WasmCompositeInnerType::Func(self.convert_func_type(f)?)
2589 }
2590 wasmparser::CompositeInnerType::Array(a) => {
2591 WasmCompositeInnerType::Array(self.convert_array_type(a)?)
2592 }
2593 wasmparser::CompositeInnerType::Struct(s) => {
2594 WasmCompositeInnerType::Struct(self.convert_struct_type(s)?)
2595 }
2596 wasmparser::CompositeInnerType::Cont(c) => {
2597 WasmCompositeInnerType::Cont(self.convert_cont_type(c))
2598 }
2599 };
2600 Ok(WasmCompositeType {
2601 inner,
2602 shared: ty.shared,
2603 })
2604 }
2605
2606 fn convert_cont_type(&self, ty: &wasmparser::ContType) -> WasmContType {
2608 if let WasmHeapType::ConcreteFunc(sigidx) = self.lookup_heap_type(ty.0.unpack()) {
2609 WasmContType::new(sigidx)
2610 } else {
2611 panic!("Failed to extract signature index for continuation type.")
2612 }
2613 }
2614
2615 fn convert_struct_type(&self, ty: &wasmparser::StructType) -> WasmResult<WasmStructType> {
2616 Ok(WasmStructType {
2617 fields: ty
2618 .fields
2619 .iter()
2620 .map(|f| self.convert_field_type(f))
2621 .collect::<WasmResult<_>>()?,
2622 })
2623 }
2624
2625 fn convert_array_type(&self, ty: &wasmparser::ArrayType) -> WasmResult<WasmArrayType> {
2626 Ok(WasmArrayType(self.convert_field_type(&ty.0)?))
2627 }
2628
2629 fn convert_field_type(&self, ty: &wasmparser::FieldType) -> WasmResult<WasmFieldType> {
2630 Ok(WasmFieldType {
2631 element_type: self.convert_storage_type(&ty.element_type)?,
2632 mutable: ty.mutable,
2633 })
2634 }
2635
2636 fn convert_storage_type(&self, ty: &wasmparser::StorageType) -> WasmResult<WasmStorageType> {
2637 Ok(match ty {
2638 wasmparser::StorageType::I8 => WasmStorageType::I8,
2639 wasmparser::StorageType::I16 => WasmStorageType::I16,
2640 wasmparser::StorageType::Val(v) => WasmStorageType::Val(self.convert_valtype(*v)?),
2641 })
2642 }
2643
2644 fn convert_func_type(&self, ty: &wasmparser::FuncType) -> WasmResult<WasmFuncType> {
2646 let params = ty
2647 .params()
2648 .iter()
2649 .map(|t| self.convert_valtype(*t))
2650 .collect::<WasmResult<Vec<_>>>()?;
2651 let results = ty
2652 .results()
2653 .iter()
2654 .map(|t| self.convert_valtype(*t))
2655 .collect::<WasmResult<Vec<_>>>()?;
2656 Ok(WasmFuncType::new(params, results).panic_on_oom())
2657 }
2658
2659 fn convert_valtype(&self, ty: wasmparser::ValType) -> WasmResult<WasmValType> {
2661 Ok(match ty {
2662 wasmparser::ValType::I32 => WasmValType::I32,
2663 wasmparser::ValType::I64 => WasmValType::I64,
2664 wasmparser::ValType::F32 => WasmValType::F32,
2665 wasmparser::ValType::F64 => WasmValType::F64,
2666 wasmparser::ValType::V128 => WasmValType::V128,
2667 wasmparser::ValType::Ref(t) => WasmValType::Ref(self.convert_ref_type(t)?),
2668 })
2669 }
2670
2671 fn convert_ref_type(&self, ty: wasmparser::RefType) -> WasmResult<WasmRefType> {
2673 Ok(WasmRefType {
2674 nullable: ty.is_nullable(),
2675 heap_type: self.convert_heap_type(ty.heap_type())?,
2676 })
2677 }
2678
2679 fn convert_heap_type(&self, ty: wasmparser::HeapType) -> WasmResult<WasmHeapType> {
2681 Ok(match ty {
2682 wasmparser::HeapType::Concrete(i) => self.lookup_heap_type(i),
2683 wasmparser::HeapType::Abstract { ty, shared: false } => match ty {
2684 wasmparser::AbstractHeapType::Extern => WasmHeapType::Extern,
2685 wasmparser::AbstractHeapType::NoExtern => WasmHeapType::NoExtern,
2686 wasmparser::AbstractHeapType::Func => WasmHeapType::Func,
2687 wasmparser::AbstractHeapType::NoFunc => WasmHeapType::NoFunc,
2688 wasmparser::AbstractHeapType::Any => WasmHeapType::Any,
2689 wasmparser::AbstractHeapType::Eq => WasmHeapType::Eq,
2690 wasmparser::AbstractHeapType::I31 => WasmHeapType::I31,
2691 wasmparser::AbstractHeapType::Array => WasmHeapType::Array,
2692 wasmparser::AbstractHeapType::Struct => WasmHeapType::Struct,
2693 wasmparser::AbstractHeapType::None => WasmHeapType::None,
2694 wasmparser::AbstractHeapType::Cont => WasmHeapType::Cont,
2695 wasmparser::AbstractHeapType::NoCont => WasmHeapType::NoCont,
2696 wasmparser::AbstractHeapType::Exn => WasmHeapType::Exn,
2697 wasmparser::AbstractHeapType::NoExn => WasmHeapType::NoExn,
2698 },
2699 _ => return Err(wasm_unsupported!("unsupported heap type {ty:?}")),
2700 })
2701 }
2702
2703 fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType;
2706
2707 fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex;
2710}
2711
2712#[cfg(test)]
2713mod tests {
2714 use super::*;
2715
2716 #[test]
2717 fn wasm_func_type_new() -> Result<()> {
2718 let i32 = WasmValType::I32;
2719 let anyref = WasmValType::Ref(WasmRefType {
2720 nullable: true,
2721 heap_type: WasmHeapType::Any,
2722 });
2723 let ty = WasmFuncType::new([i32, i32, anyref, anyref], [i32, anyref])?;
2724 assert_eq!(ty.params(), &[i32, i32, anyref, anyref]);
2725 assert_eq!(ty.non_i31_gc_ref_params_count(), 2);
2726 assert_eq!(ty.results(), &[i32, anyref]);
2727 assert_eq!(ty.non_i31_gc_ref_results_count(), 1);
2728 Ok(())
2729 }
2730}