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 TryClone for EntityIndex {
1795 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1796 Ok(*self)
1797 }
1798}
1799
1800impl From<FuncIndex> for EntityIndex {
1801 fn from(idx: FuncIndex) -> EntityIndex {
1802 EntityIndex::Function(idx)
1803 }
1804}
1805
1806impl From<TableIndex> for EntityIndex {
1807 fn from(idx: TableIndex) -> EntityIndex {
1808 EntityIndex::Table(idx)
1809 }
1810}
1811
1812impl From<MemoryIndex> for EntityIndex {
1813 fn from(idx: MemoryIndex) -> EntityIndex {
1814 EntityIndex::Memory(idx)
1815 }
1816}
1817
1818impl From<GlobalIndex> for EntityIndex {
1819 fn from(idx: GlobalIndex) -> EntityIndex {
1820 EntityIndex::Global(idx)
1821 }
1822}
1823
1824impl From<TagIndex> for EntityIndex {
1825 fn from(idx: TagIndex) -> EntityIndex {
1826 EntityIndex::Tag(idx)
1827 }
1828}
1829
1830#[derive(Clone, Debug, Serialize, Deserialize)]
1833pub enum EntityType {
1834 Global(Global),
1836 Memory(Memory),
1838 Tag(Tag),
1840 Table(Table),
1842 Function(EngineOrModuleTypeIndex),
1845}
1846
1847impl TypeTrace for EntityType {
1848 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1849 where
1850 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1851 {
1852 match self {
1853 Self::Global(g) => g.trace(func),
1854 Self::Table(t) => t.trace(func),
1855 Self::Function(idx) => func(*idx),
1856 Self::Memory(_) => Ok(()),
1857 Self::Tag(t) => t.trace(func),
1858 }
1859 }
1860
1861 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1862 where
1863 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1864 {
1865 match self {
1866 Self::Global(g) => g.trace_mut(func),
1867 Self::Table(t) => t.trace_mut(func),
1868 Self::Function(idx) => func(idx),
1869 Self::Memory(_) => Ok(()),
1870 Self::Tag(t) => t.trace_mut(func),
1871 }
1872 }
1873}
1874
1875impl EntityType {
1876 pub fn unwrap_global(&self) -> &Global {
1878 match self {
1879 EntityType::Global(g) => g,
1880 _ => panic!("not a global"),
1881 }
1882 }
1883
1884 pub fn unwrap_memory(&self) -> &Memory {
1886 match self {
1887 EntityType::Memory(g) => g,
1888 _ => panic!("not a memory"),
1889 }
1890 }
1891
1892 pub fn unwrap_tag(&self) -> &Tag {
1894 match self {
1895 EntityType::Tag(g) => g,
1896 _ => panic!("not a tag"),
1897 }
1898 }
1899
1900 pub fn unwrap_table(&self) -> &Table {
1902 match self {
1903 EntityType::Table(g) => g,
1904 _ => panic!("not a table"),
1905 }
1906 }
1907
1908 pub fn unwrap_func(&self) -> EngineOrModuleTypeIndex {
1910 match self {
1911 EntityType::Function(g) => *g,
1912 _ => panic!("not a func"),
1913 }
1914 }
1915}
1916
1917#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1925pub struct Global {
1926 pub wasm_ty: crate::WasmValType,
1928 pub mutability: bool,
1930}
1931
1932impl TypeTrace for Global {
1933 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1934 where
1935 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1936 {
1937 let Global {
1938 wasm_ty,
1939 mutability: _,
1940 } = self;
1941 wasm_ty.trace(func)
1942 }
1943
1944 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1945 where
1946 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1947 {
1948 let Global {
1949 wasm_ty,
1950 mutability: _,
1951 } = self;
1952 wasm_ty.trace_mut(func)
1953 }
1954}
1955
1956#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1960pub struct ConstExpr {
1961 ops: SmallVec<[ConstOp; 2]>,
1962}
1963
1964impl ConstExpr {
1965 pub fn new(ops: impl IntoIterator<Item = ConstOp>) -> Self {
1971 let ops = ops.into_iter().collect::<SmallVec<[ConstOp; 2]>>();
1972 assert!(!ops.is_empty());
1973 ConstExpr { ops }
1974 }
1975
1976 pub fn from_wasmparser(
1981 env: &dyn TypeConvert,
1982 expr: wasmparser::ConstExpr<'_>,
1983 ) -> WasmResult<(Self, SmallVec<[FuncIndex; 1]>)> {
1984 let mut iter = expr
1985 .get_operators_reader()
1986 .into_iter_with_offsets()
1987 .peekable();
1988
1989 let mut ops = SmallVec::<[ConstOp; 2]>::new();
1990 let mut escaped = SmallVec::<[FuncIndex; 1]>::new();
1991 while let Some(res) = iter.next() {
1992 let (op, offset) = res?;
1993
1994 if matches!(op, wasmparser::Operator::End) && iter.peek().is_none() {
1998 break;
1999 }
2000
2001 if let wasmparser::Operator::RefFunc { function_index } = &op {
2004 escaped.push(FuncIndex::from_u32(*function_index));
2005 }
2006
2007 ops.push(ConstOp::from_wasmparser(env, op, offset)?);
2008 }
2009 Ok((Self { ops }, escaped))
2010 }
2011
2012 #[inline]
2014 pub fn ops(&self) -> &[ConstOp] {
2015 &self.ops
2016 }
2017
2018 pub fn provably_nonzero_i32(&self) -> bool {
2028 match self.const_eval() {
2029 Some(GlobalConstValue::I32(x)) => x != 0,
2030
2031 _ => false,
2034 }
2035 }
2036
2037 pub fn const_eval(&self) -> Option<GlobalConstValue> {
2039 match self.ops() {
2042 [ConstOp::I32Const(x)] => Some(GlobalConstValue::I32(*x)),
2043 [ConstOp::I64Const(x)] => Some(GlobalConstValue::I64(*x)),
2044 [ConstOp::F32Const(x)] => Some(GlobalConstValue::F32(*x)),
2045 [ConstOp::F64Const(x)] => Some(GlobalConstValue::F64(*x)),
2046 [ConstOp::V128Const(x)] => Some(GlobalConstValue::V128(*x)),
2047 _ => None,
2048 }
2049 }
2050}
2051
2052#[expect(missing_docs, reason = "self-describing variants")]
2054#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
2055pub enum GlobalConstValue {
2056 I32(i32),
2057 I64(i64),
2058 F32(u32),
2059 F64(u64),
2060 V128(u128),
2061}
2062
2063#[expect(missing_docs, reason = "self-describing variants")]
2065#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
2066pub enum ConstOp {
2067 I32Const(i32),
2068 I64Const(i64),
2069 F32Const(u32),
2070 F64Const(u64),
2071 V128Const(u128),
2072 GlobalGet(GlobalIndex),
2073 RefI31,
2074 RefNull(WasmHeapType),
2075 RefFunc(FuncIndex),
2076 I32Add,
2077 I32Sub,
2078 I32Mul,
2079 I64Add,
2080 I64Sub,
2081 I64Mul,
2082 StructNew {
2083 struct_type_index: TypeIndex,
2084 },
2085 StructNewDefault {
2086 struct_type_index: TypeIndex,
2087 },
2088 ArrayNew {
2089 array_type_index: TypeIndex,
2090 },
2091 ArrayNewDefault {
2092 array_type_index: TypeIndex,
2093 },
2094 ArrayNewFixed {
2095 array_type_index: TypeIndex,
2096 array_size: u32,
2097 },
2098 ExternConvertAny,
2099 AnyConvertExtern,
2100}
2101
2102impl ConstOp {
2103 pub fn from_wasmparser(
2105 env: &dyn TypeConvert,
2106 op: wasmparser::Operator<'_>,
2107 offset: u64,
2108 ) -> WasmResult<Self> {
2109 use wasmparser::Operator as O;
2110 Ok(match op {
2111 O::I32Const { value } => Self::I32Const(value),
2112 O::I64Const { value } => Self::I64Const(value),
2113 O::F32Const { value } => Self::F32Const(value.bits()),
2114 O::F64Const { value } => Self::F64Const(value.bits()),
2115 O::V128Const { value } => Self::V128Const(u128::from_le_bytes(*value.bytes())),
2116 O::RefNull { hty } => Self::RefNull(env.convert_heap_type(hty)?),
2117 O::RefFunc { function_index } => Self::RefFunc(FuncIndex::from_u32(function_index)),
2118 O::GlobalGet { global_index } => Self::GlobalGet(GlobalIndex::from_u32(global_index)),
2119 O::RefI31 => Self::RefI31,
2120 O::I32Add => Self::I32Add,
2121 O::I32Sub => Self::I32Sub,
2122 O::I32Mul => Self::I32Mul,
2123 O::I64Add => Self::I64Add,
2124 O::I64Sub => Self::I64Sub,
2125 O::I64Mul => Self::I64Mul,
2126 O::StructNew { struct_type_index } => Self::StructNew {
2127 struct_type_index: TypeIndex::from_u32(struct_type_index),
2128 },
2129 O::StructNewDefault { struct_type_index } => Self::StructNewDefault {
2130 struct_type_index: TypeIndex::from_u32(struct_type_index),
2131 },
2132 O::ArrayNew { array_type_index } => Self::ArrayNew {
2133 array_type_index: TypeIndex::from_u32(array_type_index),
2134 },
2135 O::ArrayNewDefault { array_type_index } => Self::ArrayNewDefault {
2136 array_type_index: TypeIndex::from_u32(array_type_index),
2137 },
2138 O::ArrayNewFixed {
2139 array_type_index,
2140 array_size,
2141 } => Self::ArrayNewFixed {
2142 array_type_index: TypeIndex::from_u32(array_type_index),
2143 array_size,
2144 },
2145 O::ExternConvertAny => Self::ExternConvertAny,
2146 O::AnyConvertExtern => Self::AnyConvertExtern,
2147 op => {
2148 return Err(wasm_unsupported!(
2149 "unsupported opcode in const expression at offset {offset:#x}: {op:?}",
2150 ));
2151 }
2152 })
2153 }
2154
2155 pub fn to_operator(&self) -> wasmparser::Operator<'static> {
2160 use wasmparser::{AbstractHeapType, HeapType, Ieee32, Ieee64, Operator, V128};
2161 match self {
2162 ConstOp::I32Const(value) => Operator::I32Const { value: *value },
2163 ConstOp::I64Const(value) => Operator::I64Const { value: *value },
2164 ConstOp::F32Const(bits) => Operator::F32Const {
2165 value: Ieee32::from(f32::from_bits(*bits)),
2166 },
2167 ConstOp::F64Const(bits) => Operator::F64Const {
2168 value: Ieee64::from(f64::from_bits(*bits)),
2169 },
2170 ConstOp::V128Const(value) => Operator::V128Const {
2171 value: V128::from(*value as i128),
2172 },
2173 ConstOp::GlobalGet(index) => Operator::GlobalGet {
2174 global_index: index.as_u32(),
2175 },
2176 ConstOp::RefI31 => Operator::RefI31,
2177 ConstOp::RefNull(_) => Operator::RefNull {
2178 hty: HeapType::Abstract {
2179 shared: false,
2180 ty: AbstractHeapType::Any,
2181 },
2182 },
2183 ConstOp::RefFunc(index) => Operator::RefFunc {
2184 function_index: index.as_u32(),
2185 },
2186 ConstOp::I32Add => Operator::I32Add,
2187 ConstOp::I32Sub => Operator::I32Sub,
2188 ConstOp::I32Mul => Operator::I32Mul,
2189 ConstOp::I64Add => Operator::I64Add,
2190 ConstOp::I64Sub => Operator::I64Sub,
2191 ConstOp::I64Mul => Operator::I64Mul,
2192 ConstOp::StructNew { struct_type_index } => Operator::StructNew {
2193 struct_type_index: struct_type_index.as_u32(),
2194 },
2195 ConstOp::StructNewDefault { struct_type_index } => Operator::StructNewDefault {
2196 struct_type_index: struct_type_index.as_u32(),
2197 },
2198 ConstOp::ArrayNew { array_type_index } => Operator::ArrayNew {
2199 array_type_index: array_type_index.as_u32(),
2200 },
2201 ConstOp::ArrayNewDefault { array_type_index } => Operator::ArrayNewDefault {
2202 array_type_index: array_type_index.as_u32(),
2203 },
2204 ConstOp::ArrayNewFixed {
2205 array_type_index,
2206 array_size,
2207 } => Operator::ArrayNewFixed {
2208 array_type_index: array_type_index.as_u32(),
2209 array_size: *array_size,
2210 },
2211 ConstOp::ExternConvertAny => Operator::ExternConvertAny,
2212 ConstOp::AnyConvertExtern => Operator::AnyConvertExtern,
2213 }
2214 }
2215
2216 pub fn may_trap(&self) -> bool {
2219 match self {
2220 ConstOp::I32Const(_)
2221 | ConstOp::I64Const(_)
2222 | ConstOp::F32Const(_)
2223 | ConstOp::F64Const(_)
2224 | ConstOp::V128Const(_)
2225 | ConstOp::GlobalGet(_)
2226 | ConstOp::RefI31
2227 | ConstOp::RefNull(_)
2228 | ConstOp::RefFunc(_)
2229 | ConstOp::I32Add
2230 | ConstOp::I32Sub
2231 | ConstOp::I32Mul
2232 | ConstOp::I64Add
2233 | ConstOp::I64Sub
2234 | ConstOp::I64Mul
2235 | ConstOp::ExternConvertAny
2236 | ConstOp::AnyConvertExtern => false,
2237
2238 ConstOp::StructNew { .. }
2240 | ConstOp::StructNewDefault { .. }
2241 | ConstOp::ArrayNew { .. }
2242 | ConstOp::ArrayNewDefault { .. }
2243 | ConstOp::ArrayNewFixed { .. } => true,
2244 }
2245 }
2246}
2247
2248#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2250#[expect(missing_docs, reason = "self-describing variants")]
2251pub enum IndexType {
2252 I32,
2253 I64,
2254}
2255
2256#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2258#[expect(missing_docs, reason = "self-describing fields")]
2259pub struct Limits {
2260 pub min: u64,
2261 pub max: Option<u64>,
2262}
2263
2264#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2266pub struct Table {
2267 pub idx_type: IndexType,
2269 pub limits: Limits,
2272 pub ref_type: WasmRefType,
2274}
2275
2276impl TypeTrace for Table {
2277 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2278 where
2279 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2280 {
2281 let Table {
2282 ref_type: wasm_ty,
2283 idx_type: _,
2284 limits: _,
2285 } = self;
2286 wasm_ty.trace(func)
2287 }
2288
2289 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2290 where
2291 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2292 {
2293 let Table {
2294 ref_type: wasm_ty,
2295 idx_type: _,
2296 limits: _,
2297 } = self;
2298 wasm_ty.trace_mut(func)
2299 }
2300}
2301
2302#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2304pub struct Memory {
2305 pub idx_type: IndexType,
2307 pub limits: Limits,
2310 pub shared: bool,
2312 pub page_size_log2: u8,
2317}
2318
2319pub const WASM32_MAX_SIZE: u64 = 1 << 32;
2321
2322impl Memory {
2323 pub const DEFAULT_PAGE_SIZE: u32 = 0x10000;
2325
2326 pub const DEFAULT_PAGE_SIZE_LOG2: u8 = {
2328 let log2 = 16;
2329 assert!(1 << log2 == Memory::DEFAULT_PAGE_SIZE);
2330 log2
2331 };
2332
2333 pub fn minimum_byte_size(&self) -> Result<u64, SizeOverflow> {
2341 self.limits
2342 .min
2343 .checked_mul(self.page_size())
2344 .ok_or(SizeOverflow)
2345 }
2346
2347 pub fn maximum_byte_size(&self) -> Result<u64, SizeOverflow> {
2362 match self.limits.max {
2363 Some(max) => max.checked_mul(self.page_size()).ok_or(SizeOverflow),
2364 None => {
2365 let min = self.minimum_byte_size()?;
2366 Ok(min.max(self.max_size_based_on_index_type()))
2367 }
2368 }
2369 }
2370
2371 pub fn page_size(&self) -> u64 {
2373 debug_assert!(
2374 self.page_size_log2 == 16 || self.page_size_log2 == 0,
2375 "invalid page_size_log2: {}; must be 16 or 0",
2376 self.page_size_log2
2377 );
2378 1 << self.page_size_log2
2379 }
2380
2381 pub fn max_size_based_on_index_type(&self) -> u64 {
2386 match self.idx_type {
2387 IndexType::I64 =>
2388 {
2396 0_u64.wrapping_sub(self.page_size())
2397 }
2398 IndexType::I32 => WASM32_MAX_SIZE,
2399 }
2400 }
2401
2402 pub fn can_use_virtual_memory(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
2414 tunables.signals_based_traps && self.page_size_log2 >= host_page_size_log2
2415 }
2416
2417 pub fn can_elide_bounds_check(
2437 &self,
2438 memory_tunables: &MemoryTunables<'_>,
2439 host_page_size_log2: u8,
2440 ) -> bool {
2441 self.can_use_virtual_memory(memory_tunables.tunables(), host_page_size_log2)
2442 && self.idx_type == IndexType::I32
2443 && memory_tunables.reservation() + memory_tunables.guard_size() >= (1 << 32)
2444 }
2445
2446 pub fn static_heap_size(&self) -> Option<u64> {
2450 let min = self.minimum_byte_size().ok()?;
2451 let max = self.maximum_byte_size().ok()?;
2452 if min == max { Some(min) } else { None }
2453 }
2454
2455 pub fn memory_may_move(&self, memory_tunables: &MemoryTunables<'_>) -> bool {
2462 if self.shared {
2466 return false;
2467 }
2468
2469 if !memory_tunables.may_move() {
2472 return false;
2473 }
2474
2475 if self.limits.max.is_some_and(|max| self.limits.min == max) {
2478 return false;
2479 }
2480
2481 let max = self.maximum_byte_size().unwrap_or(u64::MAX);
2484 max > memory_tunables.reservation()
2485 }
2486
2487 pub fn allow_growth_to(&self, size: usize) -> bool {
2497 if self.page_size_log2 != 0 {
2498 return true;
2499 }
2500 match self.idx_type {
2501 IndexType::I32 => size < 0xffff_ffff,
2510
2511 IndexType::I64 => true,
2514 }
2515 }
2516}
2517
2518#[derive(Copy, Clone, Debug)]
2519#[expect(missing_docs, reason = "self-describing error struct")]
2520pub struct SizeOverflow;
2521
2522impl fmt::Display for SizeOverflow {
2523 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2524 f.write_str("size overflow calculating memory size")
2525 }
2526}
2527
2528impl core::error::Error for SizeOverflow {}
2529
2530impl From<wasmparser::MemoryType> for Memory {
2531 fn from(ty: wasmparser::MemoryType) -> Memory {
2532 let idx_type = match ty.memory64 {
2533 false => IndexType::I32,
2534 true => IndexType::I64,
2535 };
2536 let limits = Limits {
2537 min: ty.initial,
2538 max: ty.maximum,
2539 };
2540 let page_size_log2 = u8::try_from(ty.page_size_log2.unwrap_or(16)).unwrap();
2541 debug_assert!(
2542 page_size_log2 == 16 || page_size_log2 == 0,
2543 "invalid page_size_log2: {page_size_log2}; must be 16 or 0"
2544 );
2545 Memory {
2546 idx_type,
2547 limits,
2548 shared: ty.shared,
2549 page_size_log2,
2550 }
2551 }
2552}
2553
2554#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2556pub struct Tag {
2557 pub signature: EngineOrModuleTypeIndex,
2559 pub exception: EngineOrModuleTypeIndex,
2561}
2562
2563impl TypeTrace for Tag {
2564 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2565 where
2566 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2567 {
2568 func(self.signature)?;
2569 func(self.exception)?;
2570 Ok(())
2571 }
2572
2573 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2574 where
2575 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2576 {
2577 func(&mut self.signature)?;
2578 func(&mut self.exception)?;
2579 Ok(())
2580 }
2581}
2582
2583#[expect(missing_docs, reason = "self-describing functions")]
2585pub trait TypeConvert {
2586 fn convert_global_type(&self, ty: &wasmparser::GlobalType) -> WasmResult<Global> {
2588 Ok(Global {
2589 wasm_ty: self.convert_valtype(ty.content_type)?,
2590 mutability: ty.mutable,
2591 })
2592 }
2593
2594 fn convert_table_type(&self, ty: &wasmparser::TableType) -> WasmResult<Table> {
2596 let idx_type = match ty.table64 {
2597 false => IndexType::I32,
2598 true => IndexType::I64,
2599 };
2600 let limits = Limits {
2601 min: ty.initial,
2602 max: ty.maximum,
2603 };
2604 Ok(Table {
2605 idx_type,
2606 limits,
2607 ref_type: self.convert_ref_type(ty.element_type)?,
2608 })
2609 }
2610
2611 fn convert_sub_type(&self, ty: &wasmparser::SubType) -> WasmResult<WasmSubType> {
2612 let supertype = match &ty.supertype_idxs[..] {
2613 [] => None,
2614 [i] => Some(self.lookup_type_index(i.unpack())),
2615 [_, _, ..] => {
2616 return Err(wasm_unsupported!("multiple supertypes"));
2617 }
2618 };
2619 Ok(WasmSubType {
2620 is_final: ty.is_final,
2621 supertype,
2622 composite_type: self.convert_composite_type(&ty.composite_type)?,
2623 })
2624 }
2625
2626 fn convert_composite_type(
2627 &self,
2628 ty: &wasmparser::CompositeType,
2629 ) -> WasmResult<WasmCompositeType> {
2630 let inner = match &ty.inner {
2631 wasmparser::CompositeInnerType::Func(f) => {
2632 WasmCompositeInnerType::Func(self.convert_func_type(f)?)
2633 }
2634 wasmparser::CompositeInnerType::Array(a) => {
2635 WasmCompositeInnerType::Array(self.convert_array_type(a)?)
2636 }
2637 wasmparser::CompositeInnerType::Struct(s) => {
2638 WasmCompositeInnerType::Struct(self.convert_struct_type(s)?)
2639 }
2640 wasmparser::CompositeInnerType::Cont(c) => {
2641 WasmCompositeInnerType::Cont(self.convert_cont_type(c))
2642 }
2643 };
2644 Ok(WasmCompositeType {
2645 inner,
2646 shared: ty.shared,
2647 })
2648 }
2649
2650 fn convert_cont_type(&self, ty: &wasmparser::ContType) -> WasmContType {
2652 if let WasmHeapType::ConcreteFunc(sigidx) = self.lookup_heap_type(ty.0.unpack()) {
2653 WasmContType::new(sigidx)
2654 } else {
2655 panic!("Failed to extract signature index for continuation type.")
2656 }
2657 }
2658
2659 fn convert_struct_type(&self, ty: &wasmparser::StructType) -> WasmResult<WasmStructType> {
2660 Ok(WasmStructType {
2661 fields: ty
2662 .fields
2663 .iter()
2664 .map(|f| self.convert_field_type(f))
2665 .collect::<WasmResult<_>>()?,
2666 })
2667 }
2668
2669 fn convert_array_type(&self, ty: &wasmparser::ArrayType) -> WasmResult<WasmArrayType> {
2670 Ok(WasmArrayType(self.convert_field_type(&ty.0)?))
2671 }
2672
2673 fn convert_field_type(&self, ty: &wasmparser::FieldType) -> WasmResult<WasmFieldType> {
2674 Ok(WasmFieldType {
2675 element_type: self.convert_storage_type(&ty.element_type)?,
2676 mutable: ty.mutable,
2677 })
2678 }
2679
2680 fn convert_storage_type(&self, ty: &wasmparser::StorageType) -> WasmResult<WasmStorageType> {
2681 Ok(match ty {
2682 wasmparser::StorageType::I8 => WasmStorageType::I8,
2683 wasmparser::StorageType::I16 => WasmStorageType::I16,
2684 wasmparser::StorageType::Val(v) => WasmStorageType::Val(self.convert_valtype(*v)?),
2685 })
2686 }
2687
2688 fn convert_func_type(&self, ty: &wasmparser::FuncType) -> WasmResult<WasmFuncType> {
2690 let params = ty
2691 .params()
2692 .iter()
2693 .map(|t| self.convert_valtype(*t))
2694 .collect::<WasmResult<Vec<_>>>()?;
2695 let results = ty
2696 .results()
2697 .iter()
2698 .map(|t| self.convert_valtype(*t))
2699 .collect::<WasmResult<Vec<_>>>()?;
2700 Ok(WasmFuncType::new(params, results).panic_on_oom())
2701 }
2702
2703 fn convert_valtype(&self, ty: wasmparser::ValType) -> WasmResult<WasmValType> {
2705 Ok(match ty {
2706 wasmparser::ValType::I32 => WasmValType::I32,
2707 wasmparser::ValType::I64 => WasmValType::I64,
2708 wasmparser::ValType::F32 => WasmValType::F32,
2709 wasmparser::ValType::F64 => WasmValType::F64,
2710 wasmparser::ValType::V128 => WasmValType::V128,
2711 wasmparser::ValType::Ref(t) => WasmValType::Ref(self.convert_ref_type(t)?),
2712 })
2713 }
2714
2715 fn convert_ref_type(&self, ty: wasmparser::RefType) -> WasmResult<WasmRefType> {
2717 Ok(WasmRefType {
2718 nullable: ty.is_nullable(),
2719 heap_type: self.convert_heap_type(ty.heap_type())?,
2720 })
2721 }
2722
2723 fn convert_heap_type(&self, ty: wasmparser::HeapType) -> WasmResult<WasmHeapType> {
2725 Ok(match ty {
2726 wasmparser::HeapType::Concrete(i) => self.lookup_heap_type(i),
2727 wasmparser::HeapType::Abstract { ty, shared: false } => match ty {
2728 wasmparser::AbstractHeapType::Extern => WasmHeapType::Extern,
2729 wasmparser::AbstractHeapType::NoExtern => WasmHeapType::NoExtern,
2730 wasmparser::AbstractHeapType::Func => WasmHeapType::Func,
2731 wasmparser::AbstractHeapType::NoFunc => WasmHeapType::NoFunc,
2732 wasmparser::AbstractHeapType::Any => WasmHeapType::Any,
2733 wasmparser::AbstractHeapType::Eq => WasmHeapType::Eq,
2734 wasmparser::AbstractHeapType::I31 => WasmHeapType::I31,
2735 wasmparser::AbstractHeapType::Array => WasmHeapType::Array,
2736 wasmparser::AbstractHeapType::Struct => WasmHeapType::Struct,
2737 wasmparser::AbstractHeapType::None => WasmHeapType::None,
2738 wasmparser::AbstractHeapType::Cont => WasmHeapType::Cont,
2739 wasmparser::AbstractHeapType::NoCont => WasmHeapType::NoCont,
2740 wasmparser::AbstractHeapType::Exn => WasmHeapType::Exn,
2741 wasmparser::AbstractHeapType::NoExn => WasmHeapType::NoExn,
2742 },
2743 _ => return Err(wasm_unsupported!("unsupported heap type {ty:?}")),
2744 })
2745 }
2746
2747 fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType;
2750
2751 fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex;
2754}
2755
2756#[cfg(test)]
2757mod tests {
2758 use super::*;
2759
2760 #[test]
2761 fn wasm_func_type_new() -> Result<()> {
2762 let i32 = WasmValType::I32;
2763 let anyref = WasmValType::Ref(WasmRefType {
2764 nullable: true,
2765 heap_type: WasmHeapType::Any,
2766 });
2767 let ty = WasmFuncType::new([i32, i32, anyref, anyref], [i32, anyref])?;
2768 assert_eq!(ty.params(), &[i32, i32, anyref, anyref]);
2769 assert_eq!(ty.non_i31_gc_ref_params_count(), 2);
2770 assert_eq!(ty.results(), &[i32, anyref]);
2771 assert_eq!(ty.non_i31_gc_ref_results_count(), 1);
2772 Ok(())
2773 }
2774}