1use crate::{
2 PanicOnOom as _, Tunables, WasmResult, collections::TryCow, error::OutOfMemory, prelude::*,
3 wasm_unsupported,
4};
5use alloc::boxed::Box;
6use core::{fmt, ops::Range};
7use serde_derive::{Deserialize, Serialize};
8use smallvec::SmallVec;
9
10pub trait TypeTrace {
13 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
17 where
18 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>;
19
20 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
26 where
27 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>;
28
29 fn trace_engine_indices<F, E>(&self, func: &mut F) -> Result<(), E>
31 where
32 F: FnMut(VMSharedTypeIndex) -> Result<(), E>,
33 {
34 self.trace(&mut |idx| match idx {
35 EngineOrModuleTypeIndex::Engine(idx) => func(idx),
36 EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
37 })
38 }
39
40 fn canonicalize_for_runtime_usage<F>(&mut self, module_to_engine: &mut F)
51 where
52 F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
53 {
54 self.trace_mut::<_, ()>(&mut |idx| match idx {
55 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
56 EngineOrModuleTypeIndex::Module(module_index) => {
57 let engine_index = module_to_engine(*module_index);
58 *idx = EngineOrModuleTypeIndex::Engine(engine_index);
59 Ok(())
60 }
61 EngineOrModuleTypeIndex::RecGroup(_) => {
62 panic!("should not already be canonicalized for hash consing")
63 }
64 })
65 .unwrap()
66 }
67
68 fn is_canonicalized_for_runtime_usage(&self) -> bool {
70 self.trace(&mut |idx| match idx {
71 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
72 EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Err(()),
73 })
74 .is_ok()
75 }
76
77 fn canonicalize_for_hash_consing<F>(
88 &mut self,
89 rec_group_range: Range<ModuleInternedTypeIndex>,
90 module_to_engine: &mut F,
91 ) where
92 F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
93 {
94 self.trace_mut::<_, ()>(&mut |idx| match *idx {
95 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
96 EngineOrModuleTypeIndex::Module(module_index) => {
97 *idx = if rec_group_range.start <= module_index {
98 debug_assert!(module_index < rec_group_range.end);
101 let relative = module_index.as_u32() - rec_group_range.start.as_u32();
102 let relative = RecGroupRelativeTypeIndex::from_u32(relative);
103 EngineOrModuleTypeIndex::RecGroup(relative)
104 } else {
105 debug_assert!(module_index < rec_group_range.start);
108 EngineOrModuleTypeIndex::Engine(module_to_engine(module_index))
109 };
110 Ok(())
111 }
112 EngineOrModuleTypeIndex::RecGroup(_) => {
113 panic!("should not already be canonicalized for hash consing")
114 }
115 })
116 .unwrap()
117 }
118
119 fn is_canonicalized_for_hash_consing(&self) -> bool {
121 self.trace(&mut |idx| match idx {
122 EngineOrModuleTypeIndex::Engine(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
123 EngineOrModuleTypeIndex::Module(_) => Err(()),
124 })
125 .is_ok()
126 }
127}
128
129#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
131pub enum WasmValType {
132 I32,
134 I64,
136 F32,
138 F64,
140 V128,
142 Ref(WasmRefType),
144}
145
146impl TryClone for WasmValType {
147 fn try_clone(&self) -> Result<Self, OutOfMemory> {
148 Ok(*self)
149 }
150}
151
152impl fmt::Display for WasmValType {
153 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
154 match self {
155 WasmValType::I32 => write!(f, "i32"),
156 WasmValType::I64 => write!(f, "i64"),
157 WasmValType::F32 => write!(f, "f32"),
158 WasmValType::F64 => write!(f, "f64"),
159 WasmValType::V128 => write!(f, "v128"),
160 WasmValType::Ref(rt) => write!(f, "{rt}"),
161 }
162 }
163}
164
165impl TypeTrace for WasmValType {
166 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
167 where
168 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
169 {
170 match self {
171 WasmValType::Ref(r) => r.trace(func),
172 WasmValType::I32
173 | WasmValType::I64
174 | WasmValType::F32
175 | WasmValType::F64
176 | WasmValType::V128 => Ok(()),
177 }
178 }
179
180 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
181 where
182 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
183 {
184 match self {
185 WasmValType::Ref(r) => r.trace_mut(func),
186 WasmValType::I32
187 | WasmValType::I64
188 | WasmValType::F32
189 | WasmValType::F64
190 | WasmValType::V128 => Ok(()),
191 }
192 }
193}
194
195impl WasmValType {
196 #[inline]
198 pub fn is_vmgcref_type(&self) -> bool {
199 match self {
200 WasmValType::Ref(r) => r.is_vmgcref_type(),
201 _ => false,
202 }
203 }
204
205 #[inline]
211 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
212 match self {
213 WasmValType::Ref(r) => r.is_vmgcref_type_and_not_i31(),
214 _ => false,
215 }
216 }
217
218 fn trampoline_type(&self) -> Self {
219 match self {
220 WasmValType::Ref(r) => WasmValType::Ref(WasmRefType {
221 nullable: true,
222 heap_type: r.heap_type.top().into(),
223 }),
224 WasmValType::I32
225 | WasmValType::I64
226 | WasmValType::F32
227 | WasmValType::F64
228 | WasmValType::V128 => *self,
229 }
230 }
231
232 pub fn int_from_bits(bits: u8) -> Self {
236 match bits {
237 32 => Self::I32,
238 64 => Self::I64,
239 size => panic!("invalid int bits for WasmValType: {size}"),
240 }
241 }
242
243 pub fn unwrap_ref_type(&self) -> WasmRefType {
247 match self {
248 WasmValType::Ref(ref_type) => *ref_type,
249 _ => panic!("Called WasmValType::unwrap_ref_type on non-reference type"),
250 }
251 }
252}
253
254#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
256pub struct WasmRefType {
257 pub nullable: bool,
259 pub heap_type: WasmHeapType,
261}
262
263impl TypeTrace for WasmRefType {
264 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
265 where
266 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
267 {
268 self.heap_type.trace(func)
269 }
270
271 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
272 where
273 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
274 {
275 self.heap_type.trace_mut(func)
276 }
277}
278
279impl WasmRefType {
280 pub const EXTERNREF: WasmRefType = WasmRefType {
282 nullable: true,
283 heap_type: WasmHeapType::Extern,
284 };
285 pub const FUNCREF: WasmRefType = WasmRefType {
287 nullable: true,
288 heap_type: WasmHeapType::Func,
289 };
290
291 #[inline]
293 pub fn is_vmgcref_type(&self) -> bool {
294 self.heap_type.is_vmgcref_type()
295 }
296
297 #[inline]
303 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
304 self.heap_type.is_vmgcref_type_and_not_i31()
305 }
306}
307
308impl fmt::Display for WasmRefType {
309 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
310 match *self {
311 Self::FUNCREF => write!(f, "funcref"),
312 Self::EXTERNREF => write!(f, "externref"),
313 _ => {
314 if self.nullable {
315 write!(f, "(ref null {})", self.heap_type)
316 } else {
317 write!(f, "(ref {})", self.heap_type)
318 }
319 }
320 }
321 }
322}
323
324#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
329pub enum EngineOrModuleTypeIndex {
330 Engine(VMSharedTypeIndex),
333
334 Module(ModuleInternedTypeIndex),
337
338 RecGroup(RecGroupRelativeTypeIndex),
342}
343
344impl From<ModuleInternedTypeIndex> for EngineOrModuleTypeIndex {
345 #[inline]
346 fn from(i: ModuleInternedTypeIndex) -> Self {
347 Self::Module(i)
348 }
349}
350
351impl From<VMSharedTypeIndex> for EngineOrModuleTypeIndex {
352 #[inline]
353 fn from(i: VMSharedTypeIndex) -> Self {
354 Self::Engine(i)
355 }
356}
357
358impl From<RecGroupRelativeTypeIndex> for EngineOrModuleTypeIndex {
359 #[inline]
360 fn from(i: RecGroupRelativeTypeIndex) -> Self {
361 Self::RecGroup(i)
362 }
363}
364
365impl fmt::Display for EngineOrModuleTypeIndex {
366 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
367 match self {
368 Self::Engine(i) => write!(f, "(engine {})", i.bits()),
369 Self::Module(i) => write!(f, "(module {})", i.as_u32()),
370 Self::RecGroup(i) => write!(f, "(recgroup {})", i.as_u32()),
371 }
372 }
373}
374
375impl EngineOrModuleTypeIndex {
376 pub fn is_engine_type_index(self) -> bool {
378 matches!(self, Self::Engine(_))
379 }
380
381 #[inline]
383 pub fn as_engine_type_index(self) -> Option<VMSharedTypeIndex> {
384 match self {
385 Self::Engine(e) => Some(e),
386 Self::RecGroup(_) | Self::Module(_) => None,
387 }
388 }
389
390 #[track_caller]
392 #[inline]
393 pub fn unwrap_engine_type_index(self) -> VMSharedTypeIndex {
394 match self.as_engine_type_index() {
395 Some(x) => x,
396 None => panic!("`unwrap_engine_type_index` on {self:?}"),
397 }
398 }
399
400 pub fn is_module_type_index(self) -> bool {
402 matches!(self, Self::Module(_))
403 }
404
405 pub fn as_module_type_index(self) -> Option<ModuleInternedTypeIndex> {
407 match self {
408 Self::Module(e) => Some(e),
409 Self::RecGroup(_) | Self::Engine(_) => None,
410 }
411 }
412
413 #[track_caller]
415 pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
416 match self.as_module_type_index() {
417 Some(x) => x,
418 None => panic!("`unwrap_module_type_index` on {self:?}"),
419 }
420 }
421
422 pub fn is_rec_group_type_index(self) -> bool {
424 matches!(self, Self::RecGroup(_))
425 }
426
427 pub fn as_rec_group_type_index(self) -> Option<RecGroupRelativeTypeIndex> {
429 match self {
430 Self::RecGroup(r) => Some(r),
431 Self::Module(_) | Self::Engine(_) => None,
432 }
433 }
434
435 #[track_caller]
437 pub fn unwrap_rec_group_type_index(self) -> RecGroupRelativeTypeIndex {
438 match self.as_rec_group_type_index() {
439 Some(x) => x,
440 None => panic!("`unwrap_rec_group_type_index` on {self:?}"),
441 }
442 }
443}
444
445#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
447#[expect(missing_docs, reason = "self-describing variants")]
448pub enum WasmHeapType {
449 Extern,
451 NoExtern,
452
453 Func,
455 ConcreteFunc(EngineOrModuleTypeIndex),
456 NoFunc,
457
458 Exn,
460 ConcreteExn(EngineOrModuleTypeIndex),
461 NoExn,
462
463 Cont,
465 ConcreteCont(EngineOrModuleTypeIndex),
466 NoCont,
467
468 Any,
470 Eq,
471 I31,
472 Array,
473 ConcreteArray(EngineOrModuleTypeIndex),
474 Struct,
475 ConcreteStruct(EngineOrModuleTypeIndex),
476 None,
477}
478
479impl From<WasmHeapTopType> for WasmHeapType {
480 #[inline]
481 fn from(value: WasmHeapTopType) -> Self {
482 match value {
483 WasmHeapTopType::Extern => Self::Extern,
484 WasmHeapTopType::Any => Self::Any,
485 WasmHeapTopType::Func => Self::Func,
486 WasmHeapTopType::Cont => Self::Cont,
487 WasmHeapTopType::Exn => Self::Exn,
488 }
489 }
490}
491
492impl From<WasmHeapBottomType> for WasmHeapType {
493 #[inline]
494 fn from(value: WasmHeapBottomType) -> Self {
495 match value {
496 WasmHeapBottomType::NoExtern => Self::NoExtern,
497 WasmHeapBottomType::None => Self::None,
498 WasmHeapBottomType::NoFunc => Self::NoFunc,
499 WasmHeapBottomType::NoCont => Self::NoCont,
500 WasmHeapBottomType::NoExn => Self::NoExn,
501 }
502 }
503}
504
505impl fmt::Display for WasmHeapType {
506 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
507 match self {
508 Self::Extern => write!(f, "extern"),
509 Self::NoExtern => write!(f, "noextern"),
510 Self::Func => write!(f, "func"),
511 Self::ConcreteFunc(i) => write!(f, "func {i}"),
512 Self::NoFunc => write!(f, "nofunc"),
513 Self::Cont => write!(f, "cont"),
514 Self::ConcreteCont(i) => write!(f, "cont {i}"),
515 Self::NoCont => write!(f, "nocont"),
516 Self::Any => write!(f, "any"),
517 Self::Eq => write!(f, "eq"),
518 Self::I31 => write!(f, "i31"),
519 Self::Array => write!(f, "array"),
520 Self::ConcreteArray(i) => write!(f, "array {i}"),
521 Self::Struct => write!(f, "struct"),
522 Self::ConcreteStruct(i) => write!(f, "struct {i}"),
523 Self::Exn => write!(f, "exn"),
524 Self::ConcreteExn(i) => write!(f, "exn {i}"),
525 Self::NoExn => write!(f, "noexn"),
526 Self::None => write!(f, "none"),
527 }
528 }
529}
530
531impl TypeTrace for WasmHeapType {
532 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
533 where
534 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
535 {
536 match *self {
537 Self::ConcreteArray(i) => func(i),
538 Self::ConcreteFunc(i) => func(i),
539 Self::ConcreteStruct(i) => func(i),
540 Self::ConcreteCont(i) => func(i),
541 _ => Ok(()),
542 }
543 }
544
545 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
546 where
547 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
548 {
549 match self {
550 Self::ConcreteArray(i) => func(i),
551 Self::ConcreteFunc(i) => func(i),
552 Self::ConcreteStruct(i) => func(i),
553 Self::ConcreteCont(i) => func(i),
554 _ => Ok(()),
555 }
556 }
557}
558
559impl WasmHeapType {
560 #[inline]
562 pub fn is_vmgcref_type(&self) -> bool {
563 match self.top() {
564 WasmHeapTopType::Any | WasmHeapTopType::Extern | WasmHeapTopType::Exn => true,
568
569 WasmHeapTopType::Func => false,
571 WasmHeapTopType::Cont => false,
572 }
573 }
574
575 #[inline]
581 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
582 self.is_vmgcref_type() && *self != Self::I31
583 }
584
585 #[inline]
587 pub fn is_top(&self) -> bool {
588 *self == Self::from(self.top())
589 }
590
591 #[inline]
593 pub fn top(&self) -> WasmHeapTopType {
594 match self {
595 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapTopType::Extern,
596
597 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
598 WasmHeapTopType::Func
599 }
600
601 WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
602 WasmHeapTopType::Cont
603 }
604
605 WasmHeapType::Exn | WasmHeapType::ConcreteExn(_) | WasmHeapType::NoExn => {
606 WasmHeapTopType::Exn
607 }
608
609 WasmHeapType::Any
610 | WasmHeapType::Eq
611 | WasmHeapType::I31
612 | WasmHeapType::Array
613 | WasmHeapType::ConcreteArray(_)
614 | WasmHeapType::Struct
615 | WasmHeapType::ConcreteStruct(_)
616 | WasmHeapType::None => WasmHeapTopType::Any,
617 }
618 }
619
620 #[inline]
622 pub fn is_bottom(&self) -> bool {
623 *self == Self::from(self.bottom())
624 }
625
626 #[inline]
628 pub fn bottom(&self) -> WasmHeapBottomType {
629 match self {
630 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapBottomType::NoExtern,
631
632 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
633 WasmHeapBottomType::NoFunc
634 }
635
636 WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
637 WasmHeapBottomType::NoCont
638 }
639
640 WasmHeapType::Exn | WasmHeapType::ConcreteExn(_) | WasmHeapType::NoExn => {
641 WasmHeapBottomType::NoExn
642 }
643
644 WasmHeapType::Any
645 | WasmHeapType::Eq
646 | WasmHeapType::I31
647 | WasmHeapType::Array
648 | WasmHeapType::ConcreteArray(_)
649 | WasmHeapType::Struct
650 | WasmHeapType::ConcreteStruct(_)
651 | WasmHeapType::None => WasmHeapBottomType::None,
652 }
653 }
654}
655
656#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
658pub enum WasmHeapTopType {
659 Extern,
661 Any,
663 Func,
665 Exn,
667 Cont,
669}
670
671#[derive(Debug, Clone, Copy, Eq, PartialEq)]
673pub enum WasmHeapBottomType {
674 NoExtern,
676 None,
678 NoFunc,
680 NoExn,
682 NoCont,
684}
685
686#[derive(Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
688pub struct WasmFuncType {
689 #[serde(deserialize_with = "WasmFuncType::deserialize_params_results")]
690 params_results: Box<[WasmValType]>,
691 params_len: u32,
692 non_i31_gc_ref_params_count: u32,
693 non_i31_gc_ref_results_count: u32,
694}
695
696impl TryClone for WasmFuncType {
697 fn try_clone(&self) -> Result<Self, OutOfMemory> {
698 Ok(Self {
699 params_results: TryClone::try_clone(&self.params_results)?,
700 params_len: self.params_len,
701 non_i31_gc_ref_params_count: self.non_i31_gc_ref_params_count,
702 non_i31_gc_ref_results_count: self.non_i31_gc_ref_results_count,
703 })
704 }
705}
706
707impl fmt::Display for WasmFuncType {
708 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
709 write!(f, "(func")?;
710 if !self.params().is_empty() {
711 write!(f, " (param")?;
712 for p in self.params() {
713 write!(f, " {p}")?;
714 }
715 write!(f, ")")?;
716 }
717 if !self.results().is_empty() {
718 write!(f, " (result")?;
719 for r in self.results() {
720 write!(f, " {r}")?;
721 }
722 write!(f, ")")?;
723 }
724 write!(f, ")")
725 }
726}
727
728impl TypeTrace for WasmFuncType {
729 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
730 where
731 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
732 {
733 for ty in self.params_results.iter() {
734 ty.trace(func)?;
735 }
736 Ok(())
737 }
738
739 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
740 where
741 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
742 {
743 for ty in self.params_results.iter_mut() {
744 ty.trace_mut(func)?;
745 }
746 Ok(())
747 }
748}
749
750impl WasmFuncType {
751 fn deserialize_params_results<'de, D>(deserializer: D) -> Result<Box<[WasmValType]>, D::Error>
752 where
753 D: serde::de::Deserializer<'de>,
754 {
755 let tys: crate::collections::Vec<WasmValType> =
756 serde::Deserialize::deserialize(deserializer)?;
757 let tys = tys
758 .into_boxed_slice()
759 .map_err(|oom| serde::de::Error::custom(oom))?;
760 Ok(tys)
761 }
762
763 #[inline]
765 pub fn new(
766 params: impl IntoIterator<Item = WasmValType>,
767 results: impl IntoIterator<Item = WasmValType>,
768 ) -> Result<Self, OutOfMemory> {
769 let mut params_results: crate::collections::Vec<_> = params.into_iter().try_collect()?;
770 let non_i31_gc_ref_params_count = params_results
771 .iter()
772 .filter(|p| p.is_vmgcref_type_and_not_i31())
773 .count();
774
775 let params_len = params_results.len();
776 params_results.try_extend(results)?;
777 let non_i31_gc_ref_results_count = params_results[params_len..]
778 .iter()
779 .filter(|r| r.is_vmgcref_type_and_not_i31())
780 .count();
781
782 let params_results = params_results.into_boxed_slice()?;
783 let params_len = u32::try_from(params_len).unwrap();
784 let non_i31_gc_ref_params_count = u32::try_from(non_i31_gc_ref_params_count).unwrap();
785 let non_i31_gc_ref_results_count = u32::try_from(non_i31_gc_ref_results_count).unwrap();
786
787 Ok(Self {
788 params_results,
789 params_len,
790 non_i31_gc_ref_params_count,
791 non_i31_gc_ref_results_count,
792 })
793 }
794
795 fn results_start(&self) -> usize {
796 usize::try_from(self.params_len).unwrap()
797 }
798
799 #[inline]
801 pub fn params(&self) -> &[WasmValType] {
802 &self.params_results[..self.results_start()]
803 }
804
805 #[inline]
807 pub fn non_i31_gc_ref_params_count(&self) -> usize {
808 usize::try_from(self.non_i31_gc_ref_params_count).unwrap()
809 }
810
811 #[inline]
813 pub fn results(&self) -> &[WasmValType] {
814 &self.params_results[self.results_start()..]
815 }
816
817 #[inline]
819 pub fn non_i31_gc_ref_results_count(&self) -> usize {
820 usize::try_from(self.non_i31_gc_ref_results_count).unwrap()
821 }
822
823 pub fn is_trampoline_type(&self) -> bool {
825 self.params().iter().all(|p| *p == p.trampoline_type())
826 && self.results().iter().all(|r| *r == r.trampoline_type())
827 }
828
829 pub fn trampoline_type(&self) -> Result<TryCow<'_, Self>, OutOfMemory> {
855 if self.is_trampoline_type() {
856 return Ok(TryCow::Borrowed(self));
857 }
858
859 Ok(TryCow::Owned(Self::new(
860 self.params().iter().map(|p| p.trampoline_type()),
861 self.results().iter().map(|r| r.trampoline_type()),
862 )?))
863 }
864}
865
866#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
868pub struct WasmContType(EngineOrModuleTypeIndex);
869
870impl fmt::Display for WasmContType {
871 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
872 write!(f, "(cont {})", self.0)
873 }
874}
875
876impl WasmContType {
877 pub fn new(idx: EngineOrModuleTypeIndex) -> Self {
879 WasmContType(idx)
880 }
881
882 pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
884 match self.0 {
885 EngineOrModuleTypeIndex::Engine(_) => panic!("not module interned"),
886 EngineOrModuleTypeIndex::Module(idx) => idx,
887 EngineOrModuleTypeIndex::RecGroup(_) => todo!(),
888 }
889 }
890}
891
892impl TypeTrace for WasmContType {
893 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
894 where
895 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
896 {
897 func(self.0)
898 }
899
900 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
901 where
902 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
903 {
904 func(&mut self.0)
905 }
906}
907
908#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
933pub struct WasmExnType {
934 pub func_ty: EngineOrModuleTypeIndex,
938 pub fields: Box<[WasmFieldType]>,
945}
946
947impl TryClone for WasmExnType {
948 fn try_clone(&self) -> Result<Self, OutOfMemory> {
949 Ok(Self {
950 func_ty: self.func_ty,
951 fields: self.fields.try_clone()?,
952 })
953 }
954}
955
956impl fmt::Display for WasmExnType {
957 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
958 write!(f, "(exn ({})", self.func_ty)?;
959 for ty in self.fields.iter() {
960 write!(f, " {ty}")?;
961 }
962 write!(f, ")")
963 }
964}
965
966impl TypeTrace for WasmExnType {
967 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
968 where
969 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
970 {
971 func(self.func_ty)?;
972 for f in self.fields.iter() {
973 f.trace(func)?;
974 }
975 Ok(())
976 }
977
978 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
979 where
980 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
981 {
982 func(&mut self.func_ty)?;
983 for f in self.fields.iter_mut() {
984 f.trace_mut(func)?;
985 }
986 Ok(())
987 }
988}
989
990#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
992pub enum WasmStorageType {
993 I8,
995 I16,
997 Val(WasmValType),
999}
1000
1001impl fmt::Display for WasmStorageType {
1002 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1003 match self {
1004 WasmStorageType::I8 => write!(f, "i8"),
1005 WasmStorageType::I16 => write!(f, "i16"),
1006 WasmStorageType::Val(v) => fmt::Display::fmt(v, f),
1007 }
1008 }
1009}
1010
1011impl TypeTrace for WasmStorageType {
1012 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1013 where
1014 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1015 {
1016 match self {
1017 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
1018 WasmStorageType::Val(v) => v.trace(func),
1019 }
1020 }
1021
1022 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1023 where
1024 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1025 {
1026 match self {
1027 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
1028 WasmStorageType::Val(v) => v.trace_mut(func),
1029 }
1030 }
1031}
1032
1033impl WasmStorageType {
1034 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
1040 match self {
1041 WasmStorageType::I8 | WasmStorageType::I16 => false,
1042 WasmStorageType::Val(v) => v.is_vmgcref_type_and_not_i31(),
1043 }
1044 }
1045}
1046
1047#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
1049pub struct WasmFieldType {
1050 pub element_type: WasmStorageType,
1052
1053 pub mutable: bool,
1055}
1056
1057impl TryClone for WasmFieldType {
1058 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1059 Ok(*self)
1060 }
1061}
1062
1063impl fmt::Display for WasmFieldType {
1064 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1065 if self.mutable {
1066 write!(f, "(mut {})", self.element_type)
1067 } else {
1068 fmt::Display::fmt(&self.element_type, f)
1069 }
1070 }
1071}
1072
1073impl TypeTrace for WasmFieldType {
1074 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1075 where
1076 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1077 {
1078 self.element_type.trace(func)
1079 }
1080
1081 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1082 where
1083 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1084 {
1085 self.element_type.trace_mut(func)
1086 }
1087}
1088
1089#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
1091pub struct WasmArrayType(pub WasmFieldType);
1092
1093impl fmt::Display for WasmArrayType {
1094 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1095 write!(f, "(array {})", self.0)
1096 }
1097}
1098
1099impl TypeTrace for WasmArrayType {
1100 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1101 where
1102 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1103 {
1104 self.0.trace(func)
1105 }
1106
1107 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1108 where
1109 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1110 {
1111 self.0.trace_mut(func)
1112 }
1113}
1114
1115#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1117pub struct WasmStructType {
1118 pub fields: Box<[WasmFieldType]>,
1120}
1121
1122impl TryClone for WasmStructType {
1123 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1124 Ok(Self {
1125 fields: self.fields.try_clone()?,
1126 })
1127 }
1128}
1129
1130impl fmt::Display for WasmStructType {
1131 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1132 write!(f, "(struct")?;
1133 for ty in self.fields.iter() {
1134 write!(f, " {ty}")?;
1135 }
1136 write!(f, ")")
1137 }
1138}
1139
1140impl TypeTrace for WasmStructType {
1141 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1142 where
1143 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1144 {
1145 for f in self.fields.iter() {
1146 f.trace(func)?;
1147 }
1148 Ok(())
1149 }
1150
1151 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1152 where
1153 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1154 {
1155 for f in self.fields.iter_mut() {
1156 f.trace_mut(func)?;
1157 }
1158 Ok(())
1159 }
1160}
1161
1162#[derive(Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1163#[expect(missing_docs, reason = "self-describing type")]
1164pub struct WasmCompositeType {
1165 pub inner: WasmCompositeInnerType,
1167 pub shared: bool,
1170}
1171
1172impl TryClone for WasmCompositeType {
1173 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1174 Ok(Self {
1175 inner: self.inner.try_clone()?,
1176 shared: self.shared,
1177 })
1178 }
1179}
1180
1181impl fmt::Display for WasmCompositeType {
1182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1183 if self.shared {
1184 write!(f, "(shared ")?;
1185 }
1186 fmt::Display::fmt(&self.inner, f)?;
1187 if self.shared {
1188 write!(f, ")")?;
1189 }
1190 Ok(())
1191 }
1192}
1193
1194#[derive(Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1196#[expect(missing_docs, reason = "self-describing variants")]
1197pub enum WasmCompositeInnerType {
1198 Array(WasmArrayType),
1199 Func(WasmFuncType),
1200 Struct(WasmStructType),
1201 Cont(WasmContType),
1202 Exn(WasmExnType),
1203}
1204
1205impl TryClone for WasmCompositeInnerType {
1206 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1207 Ok(match self {
1208 Self::Array(ty) => Self::Array(*ty),
1209 Self::Func(ty) => Self::Func(ty.try_clone()?),
1210 Self::Struct(ty) => Self::Struct(ty.try_clone()?),
1211 Self::Cont(ty) => Self::Cont(*ty),
1212 Self::Exn(ty) => Self::Exn(ty.try_clone()?),
1213 })
1214 }
1215}
1216
1217impl fmt::Display for WasmCompositeInnerType {
1218 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1219 match self {
1220 Self::Array(ty) => fmt::Display::fmt(ty, f),
1221 Self::Func(ty) => fmt::Display::fmt(ty, f),
1222 Self::Struct(ty) => fmt::Display::fmt(ty, f),
1223 Self::Cont(ty) => fmt::Display::fmt(ty, f),
1224 Self::Exn(ty) => fmt::Display::fmt(ty, f),
1225 }
1226 }
1227}
1228
1229#[expect(missing_docs, reason = "self-describing functions")]
1230impl WasmCompositeInnerType {
1231 #[inline]
1232 pub fn is_array(&self) -> bool {
1233 matches!(self, Self::Array(_))
1234 }
1235
1236 #[inline]
1237 pub fn as_array(&self) -> Option<&WasmArrayType> {
1238 match self {
1239 Self::Array(f) => Some(f),
1240 _ => None,
1241 }
1242 }
1243
1244 #[inline]
1245 pub fn unwrap_array(&self) -> &WasmArrayType {
1246 self.as_array().unwrap()
1247 }
1248
1249 #[inline]
1250 pub fn is_func(&self) -> bool {
1251 matches!(self, Self::Func(_))
1252 }
1253
1254 #[inline]
1255 pub fn as_func(&self) -> Option<&WasmFuncType> {
1256 match self {
1257 Self::Func(f) => Some(f),
1258 _ => None,
1259 }
1260 }
1261
1262 #[inline]
1263 pub fn unwrap_func(&self) -> &WasmFuncType {
1264 self.as_func().unwrap()
1265 }
1266
1267 #[inline]
1268 pub fn is_struct(&self) -> bool {
1269 matches!(self, Self::Struct(_))
1270 }
1271
1272 #[inline]
1273 pub fn as_struct(&self) -> Option<&WasmStructType> {
1274 match self {
1275 Self::Struct(f) => Some(f),
1276 _ => None,
1277 }
1278 }
1279
1280 #[inline]
1281 pub fn unwrap_struct(&self) -> &WasmStructType {
1282 self.as_struct().unwrap()
1283 }
1284
1285 #[inline]
1286 pub fn is_cont(&self) -> bool {
1287 matches!(self, Self::Cont(_))
1288 }
1289
1290 #[inline]
1291 pub fn as_cont(&self) -> Option<&WasmContType> {
1292 match self {
1293 Self::Cont(f) => Some(f),
1294 _ => None,
1295 }
1296 }
1297
1298 #[inline]
1299 pub fn unwrap_cont(&self) -> &WasmContType {
1300 self.as_cont().unwrap()
1301 }
1302
1303 #[inline]
1304 pub fn is_exn(&self) -> bool {
1305 matches!(self, Self::Exn(_))
1306 }
1307
1308 #[inline]
1309 pub fn as_exn(&self) -> Option<&WasmExnType> {
1310 match self {
1311 Self::Exn(f) => Some(f),
1312 _ => None,
1313 }
1314 }
1315
1316 #[inline]
1317 pub fn unwrap_exn(&self) -> &WasmExnType {
1318 self.as_exn().unwrap()
1319 }
1320}
1321
1322impl TypeTrace for WasmCompositeType {
1323 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1324 where
1325 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1326 {
1327 match &self.inner {
1328 WasmCompositeInnerType::Array(a) => a.trace(func),
1329 WasmCompositeInnerType::Func(f) => f.trace(func),
1330 WasmCompositeInnerType::Struct(a) => a.trace(func),
1331 WasmCompositeInnerType::Cont(c) => c.trace(func),
1332 WasmCompositeInnerType::Exn(e) => e.trace(func),
1333 }
1334 }
1335
1336 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1337 where
1338 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1339 {
1340 match &mut self.inner {
1341 WasmCompositeInnerType::Array(a) => a.trace_mut(func),
1342 WasmCompositeInnerType::Func(f) => f.trace_mut(func),
1343 WasmCompositeInnerType::Struct(a) => a.trace_mut(func),
1344 WasmCompositeInnerType::Cont(c) => c.trace_mut(func),
1345 WasmCompositeInnerType::Exn(e) => e.trace_mut(func),
1346 }
1347 }
1348}
1349
1350#[derive(Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1352pub struct WasmSubType {
1353 pub is_final: bool,
1356
1357 pub supertype: Option<EngineOrModuleTypeIndex>,
1359
1360 pub composite_type: WasmCompositeType,
1362}
1363
1364impl TryClone for WasmSubType {
1365 fn try_clone(&self) -> Result<Self, OutOfMemory> {
1366 Ok(Self {
1367 is_final: self.is_final,
1368 supertype: self.supertype,
1369 composite_type: self.composite_type.try_clone()?,
1370 })
1371 }
1372}
1373
1374impl fmt::Display for WasmSubType {
1375 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1376 if self.is_final && self.supertype.is_none() {
1377 fmt::Display::fmt(&self.composite_type, f)
1378 } else {
1379 write!(f, "(sub")?;
1380 if self.is_final {
1381 write!(f, " final")?;
1382 }
1383 if let Some(sup) = self.supertype {
1384 write!(f, " {sup}")?;
1385 }
1386 write!(f, " {})", self.composite_type)
1387 }
1388 }
1389}
1390
1391#[expect(missing_docs, reason = "self-describing functions")]
1395impl WasmSubType {
1396 #[inline]
1397 pub fn is_func(&self) -> bool {
1398 self.composite_type.inner.is_func() && !self.composite_type.shared
1399 }
1400
1401 #[inline]
1402 pub fn as_func(&self) -> Option<&WasmFuncType> {
1403 if self.composite_type.shared {
1404 None
1405 } else {
1406 self.composite_type.inner.as_func()
1407 }
1408 }
1409
1410 #[inline]
1411 pub fn unwrap_func(&self) -> &WasmFuncType {
1412 assert!(!self.composite_type.shared);
1413 self.composite_type.inner.unwrap_func()
1414 }
1415
1416 #[inline]
1417 pub fn is_array(&self) -> bool {
1418 self.composite_type.inner.is_array() && !self.composite_type.shared
1419 }
1420
1421 #[inline]
1422 pub fn as_array(&self) -> Option<&WasmArrayType> {
1423 if self.composite_type.shared {
1424 None
1425 } else {
1426 self.composite_type.inner.as_array()
1427 }
1428 }
1429
1430 #[inline]
1431 pub fn unwrap_array(&self) -> &WasmArrayType {
1432 assert!(!self.composite_type.shared);
1433 self.composite_type.inner.unwrap_array()
1434 }
1435
1436 #[inline]
1437 pub fn is_struct(&self) -> bool {
1438 self.composite_type.inner.is_struct() && !self.composite_type.shared
1439 }
1440
1441 #[inline]
1442 pub fn as_struct(&self) -> Option<&WasmStructType> {
1443 if self.composite_type.shared {
1444 None
1445 } else {
1446 self.composite_type.inner.as_struct()
1447 }
1448 }
1449
1450 #[inline]
1451 pub fn unwrap_struct(&self) -> &WasmStructType {
1452 assert!(!self.composite_type.shared);
1453 self.composite_type.inner.unwrap_struct()
1454 }
1455
1456 #[inline]
1457 pub fn is_cont(&self) -> bool {
1458 self.composite_type.inner.is_cont() && !self.composite_type.shared
1459 }
1460
1461 #[inline]
1462 pub fn as_cont(&self) -> Option<&WasmContType> {
1463 if self.composite_type.shared {
1464 None
1465 } else {
1466 self.composite_type.inner.as_cont()
1467 }
1468 }
1469
1470 #[inline]
1471 pub fn unwrap_cont(&self) -> &WasmContType {
1472 assert!(!self.composite_type.shared);
1473 self.composite_type.inner.unwrap_cont()
1474 }
1475
1476 #[inline]
1477 pub fn is_exn(&self) -> bool {
1478 self.composite_type.inner.is_exn() && !self.composite_type.shared
1479 }
1480
1481 #[inline]
1482 pub fn as_exn(&self) -> Option<&WasmExnType> {
1483 if self.composite_type.shared {
1484 None
1485 } else {
1486 self.composite_type.inner.as_exn()
1487 }
1488 }
1489
1490 #[inline]
1491 pub fn unwrap_exn(&self) -> &WasmExnType {
1492 assert!(!self.composite_type.shared);
1493 self.composite_type.inner.unwrap_exn()
1494 }
1495}
1496
1497impl TypeTrace for WasmSubType {
1498 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1499 where
1500 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1501 {
1502 if let Some(sup) = self.supertype {
1503 func(sup)?;
1504 }
1505 self.composite_type.trace(func)
1506 }
1507
1508 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1509 where
1510 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1511 {
1512 if let Some(sup) = self.supertype.as_mut() {
1513 func(sup)?;
1514 }
1515 self.composite_type.trace_mut(func)
1516 }
1517}
1518
1519#[derive(Debug, Default, Eq, PartialEq, Hash, Serialize, Deserialize)]
1530pub struct WasmRecGroup {
1531 pub types: Box<[WasmSubType]>,
1533}
1534
1535impl TypeTrace for WasmRecGroup {
1536 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1537 where
1538 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1539 {
1540 for ty in self.types.iter() {
1541 ty.trace(func)?;
1542 }
1543 Ok(())
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 for ty in self.types.iter_mut() {
1551 ty.trace_mut(func)?;
1552 }
1553 Ok(())
1554 }
1555}
1556
1557macro_rules! entity_impl_with_try_clone {
1558 ( $ty:ident ) => {
1559 cranelift_entity::entity_impl!($ty);
1560
1561 impl TryClone for $ty {
1562 #[inline]
1563 fn try_clone(&self) -> Result<Self, $crate::error::OutOfMemory> {
1564 Ok(*self)
1565 }
1566 }
1567 };
1568}
1569
1570#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1572pub struct FuncIndex(u32);
1573entity_impl_with_try_clone!(FuncIndex);
1574
1575#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1577pub struct DefinedFuncIndex(u32);
1578entity_impl_with_try_clone!(DefinedFuncIndex);
1579
1580#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1582pub struct DefinedTableIndex(u32);
1583entity_impl_with_try_clone!(DefinedTableIndex);
1584
1585#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1587pub struct DefinedMemoryIndex(u32);
1588entity_impl_with_try_clone!(DefinedMemoryIndex);
1589
1590#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1592pub struct OwnedMemoryIndex(u32);
1593entity_impl_with_try_clone!(OwnedMemoryIndex);
1594
1595#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1597pub struct DefinedGlobalIndex(u32);
1598entity_impl_with_try_clone!(DefinedGlobalIndex);
1599
1600#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1602pub struct TableIndex(u32);
1603entity_impl_with_try_clone!(TableIndex);
1604
1605#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1607pub struct GlobalIndex(u32);
1608entity_impl_with_try_clone!(GlobalIndex);
1609
1610#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1612pub struct MemoryIndex(u32);
1613entity_impl_with_try_clone!(MemoryIndex);
1614
1615#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1618pub struct ModuleInternedRecGroupIndex(u32);
1619entity_impl_with_try_clone!(ModuleInternedRecGroupIndex);
1620
1621#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1624pub struct EngineInternedRecGroupIndex(u32);
1625entity_impl_with_try_clone!(EngineInternedRecGroupIndex);
1626
1627#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1629pub struct TypeIndex(u32);
1630entity_impl_with_try_clone!(TypeIndex);
1631
1632#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1638pub struct RecGroupRelativeTypeIndex(u32);
1639entity_impl_with_try_clone!(RecGroupRelativeTypeIndex);
1640
1641#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1649pub struct ModuleInternedTypeIndex(u32);
1650entity_impl_with_try_clone!(ModuleInternedTypeIndex);
1651
1652#[repr(transparent)] #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1661pub struct VMSharedTypeIndex(u32);
1662entity_impl_with_try_clone!(VMSharedTypeIndex);
1663
1664impl VMSharedTypeIndex {
1665 #[inline]
1667 pub fn new(value: u32) -> Self {
1668 assert_ne!(
1669 value,
1670 u32::MAX,
1671 "u32::MAX is reserved for the default value"
1672 );
1673 Self(value)
1674 }
1675
1676 #[inline]
1678 pub fn bits(&self) -> u32 {
1679 self.0
1680 }
1681}
1682
1683impl Default for VMSharedTypeIndex {
1684 #[inline]
1685 fn default() -> Self {
1686 Self(u32::MAX)
1687 }
1688}
1689
1690#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1692pub struct DataIndex(u32);
1693entity_impl_with_try_clone!(DataIndex);
1694
1695#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1697pub struct ElemIndex(u32);
1698entity_impl_with_try_clone!(ElemIndex);
1699
1700#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1702pub struct DefinedTagIndex(u32);
1703entity_impl_with_try_clone!(DefinedTagIndex);
1704
1705#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1707pub struct TagIndex(u32);
1708entity_impl_with_try_clone!(TagIndex);
1709
1710#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1715pub struct StaticModuleIndex(u32);
1716entity_impl_with_try_clone!(StaticModuleIndex);
1717
1718#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1720pub enum EntityIndex {
1721 Function(FuncIndex),
1723 Table(TableIndex),
1725 Memory(MemoryIndex),
1727 Global(GlobalIndex),
1729 Tag(TagIndex),
1731}
1732
1733impl From<FuncIndex> for EntityIndex {
1734 fn from(idx: FuncIndex) -> EntityIndex {
1735 EntityIndex::Function(idx)
1736 }
1737}
1738
1739impl From<TableIndex> for EntityIndex {
1740 fn from(idx: TableIndex) -> EntityIndex {
1741 EntityIndex::Table(idx)
1742 }
1743}
1744
1745impl From<MemoryIndex> for EntityIndex {
1746 fn from(idx: MemoryIndex) -> EntityIndex {
1747 EntityIndex::Memory(idx)
1748 }
1749}
1750
1751impl From<GlobalIndex> for EntityIndex {
1752 fn from(idx: GlobalIndex) -> EntityIndex {
1753 EntityIndex::Global(idx)
1754 }
1755}
1756
1757impl From<TagIndex> for EntityIndex {
1758 fn from(idx: TagIndex) -> EntityIndex {
1759 EntityIndex::Tag(idx)
1760 }
1761}
1762
1763#[derive(Clone, Debug, Serialize, Deserialize)]
1766pub enum EntityType {
1767 Global(Global),
1769 Memory(Memory),
1771 Tag(Tag),
1773 Table(Table),
1775 Function(EngineOrModuleTypeIndex),
1778}
1779
1780impl TypeTrace for EntityType {
1781 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1782 where
1783 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1784 {
1785 match self {
1786 Self::Global(g) => g.trace(func),
1787 Self::Table(t) => t.trace(func),
1788 Self::Function(idx) => func(*idx),
1789 Self::Memory(_) => Ok(()),
1790 Self::Tag(t) => t.trace(func),
1791 }
1792 }
1793
1794 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1795 where
1796 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1797 {
1798 match self {
1799 Self::Global(g) => g.trace_mut(func),
1800 Self::Table(t) => t.trace_mut(func),
1801 Self::Function(idx) => func(idx),
1802 Self::Memory(_) => Ok(()),
1803 Self::Tag(t) => t.trace_mut(func),
1804 }
1805 }
1806}
1807
1808impl EntityType {
1809 pub fn unwrap_global(&self) -> &Global {
1811 match self {
1812 EntityType::Global(g) => g,
1813 _ => panic!("not a global"),
1814 }
1815 }
1816
1817 pub fn unwrap_memory(&self) -> &Memory {
1819 match self {
1820 EntityType::Memory(g) => g,
1821 _ => panic!("not a memory"),
1822 }
1823 }
1824
1825 pub fn unwrap_tag(&self) -> &Tag {
1827 match self {
1828 EntityType::Tag(g) => g,
1829 _ => panic!("not a tag"),
1830 }
1831 }
1832
1833 pub fn unwrap_table(&self) -> &Table {
1835 match self {
1836 EntityType::Table(g) => g,
1837 _ => panic!("not a table"),
1838 }
1839 }
1840
1841 pub fn unwrap_func(&self) -> EngineOrModuleTypeIndex {
1843 match self {
1844 EntityType::Function(g) => *g,
1845 _ => panic!("not a func"),
1846 }
1847 }
1848}
1849
1850#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1858pub struct Global {
1859 pub wasm_ty: crate::WasmValType,
1861 pub mutability: bool,
1863}
1864
1865impl TypeTrace for Global {
1866 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1867 where
1868 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1869 {
1870 let Global {
1871 wasm_ty,
1872 mutability: _,
1873 } = self;
1874 wasm_ty.trace(func)
1875 }
1876
1877 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1878 where
1879 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1880 {
1881 let Global {
1882 wasm_ty,
1883 mutability: _,
1884 } = self;
1885 wasm_ty.trace_mut(func)
1886 }
1887}
1888
1889#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1893pub struct ConstExpr {
1894 ops: SmallVec<[ConstOp; 2]>,
1895}
1896
1897impl ConstExpr {
1898 pub fn new(ops: impl IntoIterator<Item = ConstOp>) -> Self {
1904 let ops = ops.into_iter().collect::<SmallVec<[ConstOp; 2]>>();
1905 assert!(!ops.is_empty());
1906 ConstExpr { ops }
1907 }
1908
1909 pub fn from_wasmparser(
1914 env: &dyn TypeConvert,
1915 expr: wasmparser::ConstExpr<'_>,
1916 ) -> WasmResult<(Self, SmallVec<[FuncIndex; 1]>)> {
1917 let mut iter = expr
1918 .get_operators_reader()
1919 .into_iter_with_offsets()
1920 .peekable();
1921
1922 let mut ops = SmallVec::<[ConstOp; 2]>::new();
1923 let mut escaped = SmallVec::<[FuncIndex; 1]>::new();
1924 while let Some(res) = iter.next() {
1925 let (op, offset) = res?;
1926
1927 if matches!(op, wasmparser::Operator::End) && iter.peek().is_none() {
1931 break;
1932 }
1933
1934 if let wasmparser::Operator::RefFunc { function_index } = &op {
1937 escaped.push(FuncIndex::from_u32(*function_index));
1938 }
1939
1940 ops.push(ConstOp::from_wasmparser(env, op, offset)?);
1941 }
1942 Ok((Self { ops }, escaped))
1943 }
1944
1945 #[inline]
1947 pub fn ops(&self) -> &[ConstOp] {
1948 &self.ops
1949 }
1950
1951 pub fn provably_nonzero_i32(&self) -> bool {
1961 match self.const_eval() {
1962 Some(GlobalConstValue::I32(x)) => x != 0,
1963
1964 _ => false,
1967 }
1968 }
1969
1970 pub fn const_eval(&self) -> Option<GlobalConstValue> {
1972 match self.ops() {
1975 [ConstOp::I32Const(x)] => Some(GlobalConstValue::I32(*x)),
1976 [ConstOp::I64Const(x)] => Some(GlobalConstValue::I64(*x)),
1977 [ConstOp::F32Const(x)] => Some(GlobalConstValue::F32(*x)),
1978 [ConstOp::F64Const(x)] => Some(GlobalConstValue::F64(*x)),
1979 [ConstOp::V128Const(x)] => Some(GlobalConstValue::V128(*x)),
1980 _ => None,
1981 }
1982 }
1983}
1984
1985#[expect(missing_docs, reason = "self-describing variants")]
1987#[derive(Clone, Copy)]
1988pub enum GlobalConstValue {
1989 I32(i32),
1990 I64(i64),
1991 F32(u32),
1992 F64(u64),
1993 V128(u128),
1994}
1995
1996#[expect(missing_docs, reason = "self-describing variants")]
1998#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1999pub enum ConstOp {
2000 I32Const(i32),
2001 I64Const(i64),
2002 F32Const(u32),
2003 F64Const(u64),
2004 V128Const(u128),
2005 GlobalGet(GlobalIndex),
2006 RefI31,
2007 RefNull(WasmHeapTopType),
2008 RefFunc(FuncIndex),
2009 I32Add,
2010 I32Sub,
2011 I32Mul,
2012 I64Add,
2013 I64Sub,
2014 I64Mul,
2015 StructNew {
2016 struct_type_index: TypeIndex,
2017 },
2018 StructNewDefault {
2019 struct_type_index: TypeIndex,
2020 },
2021 ArrayNew {
2022 array_type_index: TypeIndex,
2023 },
2024 ArrayNewDefault {
2025 array_type_index: TypeIndex,
2026 },
2027 ArrayNewFixed {
2028 array_type_index: TypeIndex,
2029 array_size: u32,
2030 },
2031 ExternConvertAny,
2032 AnyConvertExtern,
2033}
2034
2035impl ConstOp {
2036 pub fn from_wasmparser(
2038 env: &dyn TypeConvert,
2039 op: wasmparser::Operator<'_>,
2040 offset: usize,
2041 ) -> WasmResult<Self> {
2042 use wasmparser::Operator as O;
2043 Ok(match op {
2044 O::I32Const { value } => Self::I32Const(value),
2045 O::I64Const { value } => Self::I64Const(value),
2046 O::F32Const { value } => Self::F32Const(value.bits()),
2047 O::F64Const { value } => Self::F64Const(value.bits()),
2048 O::V128Const { value } => Self::V128Const(u128::from_le_bytes(*value.bytes())),
2049 O::RefNull { hty } => Self::RefNull(env.convert_heap_type(hty)?.top()),
2050 O::RefFunc { function_index } => Self::RefFunc(FuncIndex::from_u32(function_index)),
2051 O::GlobalGet { global_index } => Self::GlobalGet(GlobalIndex::from_u32(global_index)),
2052 O::RefI31 => Self::RefI31,
2053 O::I32Add => Self::I32Add,
2054 O::I32Sub => Self::I32Sub,
2055 O::I32Mul => Self::I32Mul,
2056 O::I64Add => Self::I64Add,
2057 O::I64Sub => Self::I64Sub,
2058 O::I64Mul => Self::I64Mul,
2059 O::StructNew { struct_type_index } => Self::StructNew {
2060 struct_type_index: TypeIndex::from_u32(struct_type_index),
2061 },
2062 O::StructNewDefault { struct_type_index } => Self::StructNewDefault {
2063 struct_type_index: TypeIndex::from_u32(struct_type_index),
2064 },
2065 O::ArrayNew { array_type_index } => Self::ArrayNew {
2066 array_type_index: TypeIndex::from_u32(array_type_index),
2067 },
2068 O::ArrayNewDefault { array_type_index } => Self::ArrayNewDefault {
2069 array_type_index: TypeIndex::from_u32(array_type_index),
2070 },
2071 O::ArrayNewFixed {
2072 array_type_index,
2073 array_size,
2074 } => Self::ArrayNewFixed {
2075 array_type_index: TypeIndex::from_u32(array_type_index),
2076 array_size,
2077 },
2078 O::ExternConvertAny => Self::ExternConvertAny,
2079 O::AnyConvertExtern => Self::AnyConvertExtern,
2080 op => {
2081 return Err(wasm_unsupported!(
2082 "unsupported opcode in const expression at offset {offset:#x}: {op:?}",
2083 ));
2084 }
2085 })
2086 }
2087}
2088
2089#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2091#[expect(missing_docs, reason = "self-describing variants")]
2092pub enum IndexType {
2093 I32,
2094 I64,
2095}
2096
2097#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2099#[expect(missing_docs, reason = "self-describing fields")]
2100pub struct Limits {
2101 pub min: u64,
2102 pub max: Option<u64>,
2103}
2104
2105#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2107pub struct Table {
2108 pub idx_type: IndexType,
2110 pub limits: Limits,
2113 pub ref_type: WasmRefType,
2115}
2116
2117impl TypeTrace for Table {
2118 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2119 where
2120 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2121 {
2122 let Table {
2123 ref_type: wasm_ty,
2124 idx_type: _,
2125 limits: _,
2126 } = self;
2127 wasm_ty.trace(func)
2128 }
2129
2130 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2131 where
2132 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2133 {
2134 let Table {
2135 ref_type: wasm_ty,
2136 idx_type: _,
2137 limits: _,
2138 } = self;
2139 wasm_ty.trace_mut(func)
2140 }
2141}
2142
2143#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2145pub struct Memory {
2146 pub idx_type: IndexType,
2148 pub limits: Limits,
2151 pub shared: bool,
2153 pub page_size_log2: u8,
2158}
2159
2160pub const WASM32_MAX_SIZE: u64 = 1 << 32;
2162
2163impl Memory {
2164 pub const DEFAULT_PAGE_SIZE: u32 = 0x10000;
2166
2167 pub const DEFAULT_PAGE_SIZE_LOG2: u8 = {
2169 let log2 = 16;
2170 assert!(1 << log2 == Memory::DEFAULT_PAGE_SIZE);
2171 log2
2172 };
2173
2174 pub fn minimum_byte_size(&self) -> Result<u64, SizeOverflow> {
2182 self.limits
2183 .min
2184 .checked_mul(self.page_size())
2185 .ok_or(SizeOverflow)
2186 }
2187
2188 pub fn maximum_byte_size(&self) -> Result<u64, SizeOverflow> {
2203 match self.limits.max {
2204 Some(max) => max.checked_mul(self.page_size()).ok_or(SizeOverflow),
2205 None => {
2206 let min = self.minimum_byte_size()?;
2207 Ok(min.max(self.max_size_based_on_index_type()))
2208 }
2209 }
2210 }
2211
2212 pub fn page_size(&self) -> u64 {
2214 debug_assert!(
2215 self.page_size_log2 == 16 || self.page_size_log2 == 0,
2216 "invalid page_size_log2: {}; must be 16 or 0",
2217 self.page_size_log2
2218 );
2219 1 << self.page_size_log2
2220 }
2221
2222 pub fn max_size_based_on_index_type(&self) -> u64 {
2227 match self.idx_type {
2228 IndexType::I64 =>
2229 {
2237 0_u64.wrapping_sub(self.page_size())
2238 }
2239 IndexType::I32 => WASM32_MAX_SIZE,
2240 }
2241 }
2242
2243 pub fn can_use_virtual_memory(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
2255 tunables.signals_based_traps && self.page_size_log2 >= host_page_size_log2
2256 }
2257
2258 pub fn can_elide_bounds_check(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
2278 self.can_use_virtual_memory(tunables, host_page_size_log2)
2279 && self.idx_type == IndexType::I32
2280 && tunables.memory_reservation + tunables.memory_guard_size >= (1 << 32)
2281 }
2282
2283 pub fn static_heap_size(&self) -> Option<u64> {
2287 let min = self.minimum_byte_size().ok()?;
2288 let max = self.maximum_byte_size().ok()?;
2289 if min == max { Some(min) } else { None }
2290 }
2291
2292 pub fn memory_may_move(&self, tunables: &Tunables) -> bool {
2299 if self.shared {
2303 return false;
2304 }
2305
2306 if !tunables.memory_may_move {
2309 return false;
2310 }
2311
2312 if self.limits.max.is_some_and(|max| self.limits.min == max) {
2315 return false;
2316 }
2317
2318 let max = self.maximum_byte_size().unwrap_or(u64::MAX);
2321 max > tunables.memory_reservation
2322 }
2323}
2324
2325#[derive(Copy, Clone, Debug)]
2326#[expect(missing_docs, reason = "self-describing error struct")]
2327pub struct SizeOverflow;
2328
2329impl fmt::Display for SizeOverflow {
2330 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2331 f.write_str("size overflow calculating memory size")
2332 }
2333}
2334
2335impl core::error::Error for SizeOverflow {}
2336
2337impl From<wasmparser::MemoryType> for Memory {
2338 fn from(ty: wasmparser::MemoryType) -> Memory {
2339 let idx_type = match ty.memory64 {
2340 false => IndexType::I32,
2341 true => IndexType::I64,
2342 };
2343 let limits = Limits {
2344 min: ty.initial,
2345 max: ty.maximum,
2346 };
2347 let page_size_log2 = u8::try_from(ty.page_size_log2.unwrap_or(16)).unwrap();
2348 debug_assert!(
2349 page_size_log2 == 16 || page_size_log2 == 0,
2350 "invalid page_size_log2: {page_size_log2}; must be 16 or 0"
2351 );
2352 Memory {
2353 idx_type,
2354 limits,
2355 shared: ty.shared,
2356 page_size_log2,
2357 }
2358 }
2359}
2360
2361#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2363pub struct Tag {
2364 pub signature: EngineOrModuleTypeIndex,
2366 pub exception: EngineOrModuleTypeIndex,
2368}
2369
2370impl TypeTrace for Tag {
2371 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2372 where
2373 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2374 {
2375 func(self.signature)?;
2376 func(self.exception)?;
2377 Ok(())
2378 }
2379
2380 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2381 where
2382 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2383 {
2384 func(&mut self.signature)?;
2385 func(&mut self.exception)?;
2386 Ok(())
2387 }
2388}
2389
2390#[expect(missing_docs, reason = "self-describing functions")]
2392pub trait TypeConvert {
2393 fn convert_global_type(&self, ty: &wasmparser::GlobalType) -> WasmResult<Global> {
2395 Ok(Global {
2396 wasm_ty: self.convert_valtype(ty.content_type)?,
2397 mutability: ty.mutable,
2398 })
2399 }
2400
2401 fn convert_table_type(&self, ty: &wasmparser::TableType) -> WasmResult<Table> {
2403 let idx_type = match ty.table64 {
2404 false => IndexType::I32,
2405 true => IndexType::I64,
2406 };
2407 let limits = Limits {
2408 min: ty.initial,
2409 max: ty.maximum,
2410 };
2411 Ok(Table {
2412 idx_type,
2413 limits,
2414 ref_type: self.convert_ref_type(ty.element_type)?,
2415 })
2416 }
2417
2418 fn convert_sub_type(&self, ty: &wasmparser::SubType) -> WasmResult<WasmSubType> {
2419 Ok(WasmSubType {
2420 is_final: ty.is_final,
2421 supertype: ty.supertype_idx.map(|i| self.lookup_type_index(i.unpack())),
2422 composite_type: self.convert_composite_type(&ty.composite_type)?,
2423 })
2424 }
2425
2426 fn convert_composite_type(
2427 &self,
2428 ty: &wasmparser::CompositeType,
2429 ) -> WasmResult<WasmCompositeType> {
2430 let inner = match &ty.inner {
2431 wasmparser::CompositeInnerType::Func(f) => {
2432 WasmCompositeInnerType::Func(self.convert_func_type(f)?)
2433 }
2434 wasmparser::CompositeInnerType::Array(a) => {
2435 WasmCompositeInnerType::Array(self.convert_array_type(a)?)
2436 }
2437 wasmparser::CompositeInnerType::Struct(s) => {
2438 WasmCompositeInnerType::Struct(self.convert_struct_type(s)?)
2439 }
2440 wasmparser::CompositeInnerType::Cont(c) => {
2441 WasmCompositeInnerType::Cont(self.convert_cont_type(c))
2442 }
2443 };
2444 Ok(WasmCompositeType {
2445 inner,
2446 shared: ty.shared,
2447 })
2448 }
2449
2450 fn convert_cont_type(&self, ty: &wasmparser::ContType) -> WasmContType {
2452 if let WasmHeapType::ConcreteFunc(sigidx) = self.lookup_heap_type(ty.0.unpack()) {
2453 WasmContType::new(sigidx)
2454 } else {
2455 panic!("Failed to extract signature index for continuation type.")
2456 }
2457 }
2458
2459 fn convert_struct_type(&self, ty: &wasmparser::StructType) -> WasmResult<WasmStructType> {
2460 Ok(WasmStructType {
2461 fields: ty
2462 .fields
2463 .iter()
2464 .map(|f| self.convert_field_type(f))
2465 .collect::<WasmResult<_>>()?,
2466 })
2467 }
2468
2469 fn convert_array_type(&self, ty: &wasmparser::ArrayType) -> WasmResult<WasmArrayType> {
2470 Ok(WasmArrayType(self.convert_field_type(&ty.0)?))
2471 }
2472
2473 fn convert_field_type(&self, ty: &wasmparser::FieldType) -> WasmResult<WasmFieldType> {
2474 Ok(WasmFieldType {
2475 element_type: self.convert_storage_type(&ty.element_type)?,
2476 mutable: ty.mutable,
2477 })
2478 }
2479
2480 fn convert_storage_type(&self, ty: &wasmparser::StorageType) -> WasmResult<WasmStorageType> {
2481 Ok(match ty {
2482 wasmparser::StorageType::I8 => WasmStorageType::I8,
2483 wasmparser::StorageType::I16 => WasmStorageType::I16,
2484 wasmparser::StorageType::Val(v) => WasmStorageType::Val(self.convert_valtype(*v)?),
2485 })
2486 }
2487
2488 fn convert_func_type(&self, ty: &wasmparser::FuncType) -> WasmResult<WasmFuncType> {
2490 let params = ty
2491 .params()
2492 .iter()
2493 .map(|t| self.convert_valtype(*t))
2494 .collect::<WasmResult<Vec<_>>>()?;
2495 let results = ty
2496 .results()
2497 .iter()
2498 .map(|t| self.convert_valtype(*t))
2499 .collect::<WasmResult<Vec<_>>>()?;
2500 Ok(WasmFuncType::new(params, results).panic_on_oom())
2501 }
2502
2503 fn convert_valtype(&self, ty: wasmparser::ValType) -> WasmResult<WasmValType> {
2505 Ok(match ty {
2506 wasmparser::ValType::I32 => WasmValType::I32,
2507 wasmparser::ValType::I64 => WasmValType::I64,
2508 wasmparser::ValType::F32 => WasmValType::F32,
2509 wasmparser::ValType::F64 => WasmValType::F64,
2510 wasmparser::ValType::V128 => WasmValType::V128,
2511 wasmparser::ValType::Ref(t) => WasmValType::Ref(self.convert_ref_type(t)?),
2512 })
2513 }
2514
2515 fn convert_ref_type(&self, ty: wasmparser::RefType) -> WasmResult<WasmRefType> {
2517 Ok(WasmRefType {
2518 nullable: ty.is_nullable(),
2519 heap_type: self.convert_heap_type(ty.heap_type())?,
2520 })
2521 }
2522
2523 fn convert_heap_type(&self, ty: wasmparser::HeapType) -> WasmResult<WasmHeapType> {
2525 Ok(match ty {
2526 wasmparser::HeapType::Concrete(i) => self.lookup_heap_type(i),
2527 wasmparser::HeapType::Abstract { ty, shared: false } => match ty {
2528 wasmparser::AbstractHeapType::Extern => WasmHeapType::Extern,
2529 wasmparser::AbstractHeapType::NoExtern => WasmHeapType::NoExtern,
2530 wasmparser::AbstractHeapType::Func => WasmHeapType::Func,
2531 wasmparser::AbstractHeapType::NoFunc => WasmHeapType::NoFunc,
2532 wasmparser::AbstractHeapType::Any => WasmHeapType::Any,
2533 wasmparser::AbstractHeapType::Eq => WasmHeapType::Eq,
2534 wasmparser::AbstractHeapType::I31 => WasmHeapType::I31,
2535 wasmparser::AbstractHeapType::Array => WasmHeapType::Array,
2536 wasmparser::AbstractHeapType::Struct => WasmHeapType::Struct,
2537 wasmparser::AbstractHeapType::None => WasmHeapType::None,
2538 wasmparser::AbstractHeapType::Cont => WasmHeapType::Cont,
2539 wasmparser::AbstractHeapType::NoCont => WasmHeapType::NoCont,
2540 wasmparser::AbstractHeapType::Exn => WasmHeapType::Exn,
2541 wasmparser::AbstractHeapType::NoExn => WasmHeapType::NoExn,
2542 },
2543 _ => return Err(wasm_unsupported!("unsupported heap type {ty:?}")),
2544 })
2545 }
2546
2547 fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType;
2550
2551 fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex;
2554}
2555
2556#[cfg(test)]
2557mod tests {
2558 use super::*;
2559
2560 #[test]
2561 fn wasm_func_type_new() -> Result<()> {
2562 let i32 = WasmValType::I32;
2563 let anyref = WasmValType::Ref(WasmRefType {
2564 nullable: true,
2565 heap_type: WasmHeapType::Any,
2566 });
2567 let ty = WasmFuncType::new([i32, i32, anyref, anyref], [i32, anyref])?;
2568 assert_eq!(ty.params(), &[i32, i32, anyref, anyref]);
2569 assert_eq!(ty.non_i31_gc_ref_params_count(), 2);
2570 assert_eq!(ty.results(), &[i32, anyref]);
2571 assert_eq!(ty.non_i31_gc_ref_results_count(), 1);
2572 Ok(())
2573 }
2574}