1use crate::{wasm_unsupported, Tunables, WasmResult};
2use alloc::borrow::Cow;
3use alloc::boxed::Box;
4use core::{fmt, ops::Range};
5use cranelift_entity::entity_impl;
6use serde_derive::{Deserialize, Serialize};
7use smallvec::SmallVec;
8
9pub trait TypeTrace {
12 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
16 where
17 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>;
18
19 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
25 where
26 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>;
27
28 fn trace_engine_indices<F, E>(&self, func: &mut F) -> Result<(), E>
30 where
31 F: FnMut(VMSharedTypeIndex) -> Result<(), E>,
32 {
33 self.trace(&mut |idx| match idx {
34 EngineOrModuleTypeIndex::Engine(idx) => func(idx),
35 EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
36 })
37 }
38
39 fn canonicalize_for_runtime_usage<F>(&mut self, module_to_engine: &mut F)
50 where
51 F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
52 {
53 self.trace_mut::<_, ()>(&mut |idx| match idx {
54 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
55 EngineOrModuleTypeIndex::Module(module_index) => {
56 let engine_index = module_to_engine(*module_index);
57 *idx = EngineOrModuleTypeIndex::Engine(engine_index);
58 Ok(())
59 }
60 EngineOrModuleTypeIndex::RecGroup(_) => {
61 panic!("should not already be canonicalized for hash consing")
62 }
63 })
64 .unwrap()
65 }
66
67 fn is_canonicalized_for_runtime_usage(&self) -> bool {
69 self.trace(&mut |idx| match idx {
70 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
71 EngineOrModuleTypeIndex::Module(_) | EngineOrModuleTypeIndex::RecGroup(_) => Err(()),
72 })
73 .is_ok()
74 }
75
76 fn canonicalize_for_hash_consing<F>(
87 &mut self,
88 rec_group_range: Range<ModuleInternedTypeIndex>,
89 module_to_engine: &mut F,
90 ) where
91 F: FnMut(ModuleInternedTypeIndex) -> VMSharedTypeIndex,
92 {
93 self.trace_mut::<_, ()>(&mut |idx| match *idx {
94 EngineOrModuleTypeIndex::Engine(_) => Ok(()),
95 EngineOrModuleTypeIndex::Module(module_index) => {
96 *idx = if rec_group_range.start <= module_index {
97 debug_assert!(module_index < rec_group_range.end);
100 let relative = module_index.as_u32() - rec_group_range.start.as_u32();
101 let relative = RecGroupRelativeTypeIndex::from_u32(relative);
102 EngineOrModuleTypeIndex::RecGroup(relative)
103 } else {
104 debug_assert!(module_index < rec_group_range.start);
107 EngineOrModuleTypeIndex::Engine(module_to_engine(module_index))
108 };
109 Ok(())
110 }
111 EngineOrModuleTypeIndex::RecGroup(_) => {
112 panic!("should not already be canonicalized for hash consing")
113 }
114 })
115 .unwrap()
116 }
117
118 fn is_canonicalized_for_hash_consing(&self) -> bool {
120 self.trace(&mut |idx| match idx {
121 EngineOrModuleTypeIndex::Engine(_) | EngineOrModuleTypeIndex::RecGroup(_) => Ok(()),
122 EngineOrModuleTypeIndex::Module(_) => Err(()),
123 })
124 .is_ok()
125 }
126}
127
128#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
130pub enum WasmValType {
131 I32,
133 I64,
135 F32,
137 F64,
139 V128,
141 Ref(WasmRefType),
143}
144
145impl fmt::Display for WasmValType {
146 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
147 match self {
148 WasmValType::I32 => write!(f, "i32"),
149 WasmValType::I64 => write!(f, "i64"),
150 WasmValType::F32 => write!(f, "f32"),
151 WasmValType::F64 => write!(f, "f64"),
152 WasmValType::V128 => write!(f, "v128"),
153 WasmValType::Ref(rt) => write!(f, "{rt}"),
154 }
155 }
156}
157
158impl TypeTrace for WasmValType {
159 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
160 where
161 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
162 {
163 match self {
164 WasmValType::Ref(r) => r.trace(func),
165 WasmValType::I32
166 | WasmValType::I64
167 | WasmValType::F32
168 | WasmValType::F64
169 | WasmValType::V128 => Ok(()),
170 }
171 }
172
173 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
174 where
175 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
176 {
177 match self {
178 WasmValType::Ref(r) => r.trace_mut(func),
179 WasmValType::I32
180 | WasmValType::I64
181 | WasmValType::F32
182 | WasmValType::F64
183 | WasmValType::V128 => Ok(()),
184 }
185 }
186}
187
188impl WasmValType {
189 #[inline]
191 pub fn is_vmgcref_type(&self) -> bool {
192 match self {
193 WasmValType::Ref(r) => r.is_vmgcref_type(),
194 _ => false,
195 }
196 }
197
198 #[inline]
204 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
205 match self {
206 WasmValType::Ref(r) => r.is_vmgcref_type_and_not_i31(),
207 _ => false,
208 }
209 }
210
211 fn trampoline_type(&self) -> Self {
212 match self {
213 WasmValType::Ref(r) => WasmValType::Ref(WasmRefType {
214 nullable: true,
215 heap_type: r.heap_type.top().into(),
216 }),
217 WasmValType::I32
218 | WasmValType::I64
219 | WasmValType::F32
220 | WasmValType::F64
221 | WasmValType::V128 => *self,
222 }
223 }
224
225 pub fn int_from_bits(bits: u8) -> Self {
229 match bits {
230 32 => Self::I32,
231 64 => Self::I64,
232 size => panic!("invalid int bits for WasmValType: {size}"),
233 }
234 }
235}
236
237#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
239pub struct WasmRefType {
240 pub nullable: bool,
242 pub heap_type: WasmHeapType,
244}
245
246impl TypeTrace for WasmRefType {
247 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
248 where
249 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
250 {
251 self.heap_type.trace(func)
252 }
253
254 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
255 where
256 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
257 {
258 self.heap_type.trace_mut(func)
259 }
260}
261
262impl WasmRefType {
263 pub const EXTERNREF: WasmRefType = WasmRefType {
265 nullable: true,
266 heap_type: WasmHeapType::Extern,
267 };
268 pub const FUNCREF: WasmRefType = WasmRefType {
270 nullable: true,
271 heap_type: WasmHeapType::Func,
272 };
273
274 #[inline]
276 pub fn is_vmgcref_type(&self) -> bool {
277 self.heap_type.is_vmgcref_type()
278 }
279
280 #[inline]
286 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
287 self.heap_type.is_vmgcref_type_and_not_i31()
288 }
289}
290
291impl fmt::Display for WasmRefType {
292 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
293 match *self {
294 Self::FUNCREF => write!(f, "funcref"),
295 Self::EXTERNREF => write!(f, "externref"),
296 _ => {
297 if self.nullable {
298 write!(f, "(ref null {})", self.heap_type)
299 } else {
300 write!(f, "(ref {})", self.heap_type)
301 }
302 }
303 }
304 }
305}
306
307#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
312pub enum EngineOrModuleTypeIndex {
313 Engine(VMSharedTypeIndex),
316
317 Module(ModuleInternedTypeIndex),
320
321 RecGroup(RecGroupRelativeTypeIndex),
325}
326
327impl From<ModuleInternedTypeIndex> for EngineOrModuleTypeIndex {
328 #[inline]
329 fn from(i: ModuleInternedTypeIndex) -> Self {
330 Self::Module(i)
331 }
332}
333
334impl From<VMSharedTypeIndex> for EngineOrModuleTypeIndex {
335 #[inline]
336 fn from(i: VMSharedTypeIndex) -> Self {
337 Self::Engine(i)
338 }
339}
340
341impl From<RecGroupRelativeTypeIndex> for EngineOrModuleTypeIndex {
342 #[inline]
343 fn from(i: RecGroupRelativeTypeIndex) -> Self {
344 Self::RecGroup(i)
345 }
346}
347
348impl fmt::Display for EngineOrModuleTypeIndex {
349 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
350 match self {
351 Self::Engine(i) => write!(f, "(engine {})", i.bits()),
352 Self::Module(i) => write!(f, "(module {})", i.as_u32()),
353 Self::RecGroup(i) => write!(f, "(recgroup {})", i.as_u32()),
354 }
355 }
356}
357
358impl EngineOrModuleTypeIndex {
359 pub fn is_engine_type_index(self) -> bool {
361 matches!(self, Self::Engine(_))
362 }
363
364 pub fn as_engine_type_index(self) -> Option<VMSharedTypeIndex> {
366 match self {
367 Self::Engine(e) => Some(e),
368 Self::RecGroup(_) | Self::Module(_) => None,
369 }
370 }
371
372 #[track_caller]
374 pub fn unwrap_engine_type_index(self) -> VMSharedTypeIndex {
375 match self.as_engine_type_index() {
376 Some(x) => x,
377 None => panic!("`unwrap_engine_type_index` on {self:?}"),
378 }
379 }
380
381 pub fn is_module_type_index(self) -> bool {
383 matches!(self, Self::Module(_))
384 }
385
386 pub fn as_module_type_index(self) -> Option<ModuleInternedTypeIndex> {
388 match self {
389 Self::Module(e) => Some(e),
390 Self::RecGroup(_) | Self::Engine(_) => None,
391 }
392 }
393
394 #[track_caller]
396 pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
397 match self.as_module_type_index() {
398 Some(x) => x,
399 None => panic!("`unwrap_module_type_index` on {self:?}"),
400 }
401 }
402
403 pub fn is_rec_group_type_index(self) -> bool {
405 matches!(self, Self::RecGroup(_))
406 }
407
408 pub fn as_rec_group_type_index(self) -> Option<RecGroupRelativeTypeIndex> {
410 match self {
411 Self::RecGroup(r) => Some(r),
412 Self::Module(_) | Self::Engine(_) => None,
413 }
414 }
415
416 #[track_caller]
418 pub fn unwrap_rec_group_type_index(self) -> RecGroupRelativeTypeIndex {
419 match self.as_rec_group_type_index() {
420 Some(x) => x,
421 None => panic!("`unwrap_rec_group_type_index` on {self:?}"),
422 }
423 }
424}
425
426#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
428#[allow(missing_docs, reason = "self-describing variants")]
429pub enum WasmHeapType {
430 Extern,
432 NoExtern,
433
434 Func,
436 ConcreteFunc(EngineOrModuleTypeIndex),
437 NoFunc,
438
439 Cont,
441 ConcreteCont(EngineOrModuleTypeIndex),
442 NoCont,
443
444 Any,
446 Eq,
447 I31,
448 Array,
449 ConcreteArray(EngineOrModuleTypeIndex),
450 Struct,
451 ConcreteStruct(EngineOrModuleTypeIndex),
452 None,
453}
454
455impl From<WasmHeapTopType> for WasmHeapType {
456 #[inline]
457 fn from(value: WasmHeapTopType) -> Self {
458 match value {
459 WasmHeapTopType::Extern => Self::Extern,
460 WasmHeapTopType::Any => Self::Any,
461 WasmHeapTopType::Func => Self::Func,
462 WasmHeapTopType::Cont => Self::Cont,
463 }
464 }
465}
466
467impl From<WasmHeapBottomType> for WasmHeapType {
468 #[inline]
469 fn from(value: WasmHeapBottomType) -> Self {
470 match value {
471 WasmHeapBottomType::NoExtern => Self::NoExtern,
472 WasmHeapBottomType::None => Self::None,
473 WasmHeapBottomType::NoFunc => Self::NoFunc,
474 WasmHeapBottomType::NoCont => Self::NoCont,
475 }
476 }
477}
478
479impl fmt::Display for WasmHeapType {
480 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
481 match self {
482 Self::Extern => write!(f, "extern"),
483 Self::NoExtern => write!(f, "noextern"),
484 Self::Func => write!(f, "func"),
485 Self::ConcreteFunc(i) => write!(f, "func {i}"),
486 Self::NoFunc => write!(f, "nofunc"),
487 Self::Cont => write!(f, "cont"),
488 Self::ConcreteCont(i) => write!(f, "cont {i}"),
489 Self::NoCont => write!(f, "nocont"),
490 Self::Any => write!(f, "any"),
491 Self::Eq => write!(f, "eq"),
492 Self::I31 => write!(f, "i31"),
493 Self::Array => write!(f, "array"),
494 Self::ConcreteArray(i) => write!(f, "array {i}"),
495 Self::Struct => write!(f, "struct"),
496 Self::ConcreteStruct(i) => write!(f, "struct {i}"),
497 Self::None => write!(f, "none"),
498 }
499 }
500}
501
502impl TypeTrace for WasmHeapType {
503 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
504 where
505 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
506 {
507 match *self {
508 Self::ConcreteArray(i) => func(i),
509 Self::ConcreteFunc(i) => func(i),
510 Self::ConcreteStruct(i) => func(i),
511 Self::ConcreteCont(i) => func(i),
512 _ => Ok(()),
513 }
514 }
515
516 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
517 where
518 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
519 {
520 match self {
521 Self::ConcreteArray(i) => func(i),
522 Self::ConcreteFunc(i) => func(i),
523 Self::ConcreteStruct(i) => func(i),
524 Self::ConcreteCont(i) => func(i),
525 _ => Ok(()),
526 }
527 }
528}
529
530impl WasmHeapType {
531 #[inline]
533 pub fn is_vmgcref_type(&self) -> bool {
534 match self.top() {
535 WasmHeapTopType::Any | WasmHeapTopType::Extern => true,
538
539 WasmHeapTopType::Func => false,
541 WasmHeapTopType::Cont => false,
542 }
543 }
544
545 #[inline]
551 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
552 self.is_vmgcref_type() && *self != Self::I31
553 }
554
555 #[inline]
557 pub fn is_top(&self) -> bool {
558 *self == Self::from(self.top())
559 }
560
561 #[inline]
563 pub fn top(&self) -> WasmHeapTopType {
564 match self {
565 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapTopType::Extern,
566
567 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
568 WasmHeapTopType::Func
569 }
570
571 WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
572 WasmHeapTopType::Cont
573 }
574
575 WasmHeapType::Any
576 | WasmHeapType::Eq
577 | WasmHeapType::I31
578 | WasmHeapType::Array
579 | WasmHeapType::ConcreteArray(_)
580 | WasmHeapType::Struct
581 | WasmHeapType::ConcreteStruct(_)
582 | WasmHeapType::None => WasmHeapTopType::Any,
583 }
584 }
585
586 #[inline]
588 pub fn is_bottom(&self) -> bool {
589 *self == Self::from(self.bottom())
590 }
591
592 #[inline]
594 pub fn bottom(&self) -> WasmHeapBottomType {
595 match self {
596 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapBottomType::NoExtern,
597
598 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
599 WasmHeapBottomType::NoFunc
600 }
601
602 WasmHeapType::Cont | WasmHeapType::ConcreteCont(_) | WasmHeapType::NoCont => {
603 WasmHeapBottomType::NoCont
604 }
605
606 WasmHeapType::Any
607 | WasmHeapType::Eq
608 | WasmHeapType::I31
609 | WasmHeapType::Array
610 | WasmHeapType::ConcreteArray(_)
611 | WasmHeapType::Struct
612 | WasmHeapType::ConcreteStruct(_)
613 | WasmHeapType::None => WasmHeapBottomType::None,
614 }
615 }
616}
617
618#[derive(Debug, Clone, Copy, Eq, PartialEq)]
620pub enum WasmHeapTopType {
621 Extern,
623 Any,
625 Func,
627 Cont,
629}
630
631#[derive(Debug, Clone, Copy, Eq, PartialEq)]
633pub enum WasmHeapBottomType {
634 NoExtern,
636 None,
638 NoFunc,
640 NoCont,
642}
643
644#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
646pub struct WasmFuncType {
647 params: Box<[WasmValType]>,
648 non_i31_gc_ref_params_count: usize,
649 returns: Box<[WasmValType]>,
650 non_i31_gc_ref_returns_count: usize,
651}
652
653impl fmt::Display for WasmFuncType {
654 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
655 write!(f, "(func")?;
656 if !self.params.is_empty() {
657 write!(f, " (param")?;
658 for p in self.params.iter() {
659 write!(f, " {p}")?;
660 }
661 write!(f, ")")?;
662 }
663 if !self.returns.is_empty() {
664 write!(f, " (result")?;
665 for r in self.returns.iter() {
666 write!(f, " {r}")?;
667 }
668 write!(f, ")")?;
669 }
670 write!(f, ")")
671 }
672}
673
674impl TypeTrace for WasmFuncType {
675 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
676 where
677 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
678 {
679 for p in self.params.iter() {
680 p.trace(func)?;
681 }
682 for r in self.returns.iter() {
683 r.trace(func)?;
684 }
685 Ok(())
686 }
687
688 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
689 where
690 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
691 {
692 for p in self.params.iter_mut() {
693 p.trace_mut(func)?;
694 }
695 for r in self.returns.iter_mut() {
696 r.trace_mut(func)?;
697 }
698 Ok(())
699 }
700}
701
702impl WasmFuncType {
703 #[inline]
705 pub fn new(params: Box<[WasmValType]>, returns: Box<[WasmValType]>) -> Self {
706 let non_i31_gc_ref_params_count = params
707 .iter()
708 .filter(|p| p.is_vmgcref_type_and_not_i31())
709 .count();
710 let non_i31_gc_ref_returns_count = returns
711 .iter()
712 .filter(|r| r.is_vmgcref_type_and_not_i31())
713 .count();
714 WasmFuncType {
715 params,
716 non_i31_gc_ref_params_count,
717 returns,
718 non_i31_gc_ref_returns_count,
719 }
720 }
721
722 #[inline]
724 pub fn params(&self) -> &[WasmValType] {
725 &self.params
726 }
727
728 #[inline]
730 pub fn non_i31_gc_ref_params_count(&self) -> usize {
731 self.non_i31_gc_ref_params_count
732 }
733
734 #[inline]
736 pub fn returns(&self) -> &[WasmValType] {
737 &self.returns
738 }
739
740 #[inline]
742 pub fn non_i31_gc_ref_returns_count(&self) -> usize {
743 self.non_i31_gc_ref_returns_count
744 }
745
746 pub fn is_trampoline_type(&self) -> bool {
748 self.params().iter().all(|p| *p == p.trampoline_type())
749 && self.returns().iter().all(|r| *r == r.trampoline_type())
750 }
751
752 pub fn trampoline_type(&self) -> Cow<'_, Self> {
778 if self.is_trampoline_type() {
779 return Cow::Borrowed(self);
780 }
781
782 Cow::Owned(Self::new(
783 self.params().iter().map(|p| p.trampoline_type()).collect(),
784 self.returns().iter().map(|r| r.trampoline_type()).collect(),
785 ))
786 }
787}
788
789#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
791pub struct WasmContType(EngineOrModuleTypeIndex);
792
793impl fmt::Display for WasmContType {
794 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
795 write!(f, "(cont {})", self.0)
796 }
797}
798
799impl WasmContType {
800 pub fn new(idx: EngineOrModuleTypeIndex) -> Self {
802 WasmContType(idx)
803 }
804}
805
806impl TypeTrace for WasmContType {
807 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
808 where
809 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
810 {
811 func(self.0)
812 }
813
814 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
815 where
816 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
817 {
818 func(&mut self.0)
819 }
820}
821
822#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
824pub enum WasmStorageType {
825 I8,
827 I16,
829 Val(WasmValType),
831}
832
833impl fmt::Display for WasmStorageType {
834 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
835 match self {
836 WasmStorageType::I8 => write!(f, "i8"),
837 WasmStorageType::I16 => write!(f, "i16"),
838 WasmStorageType::Val(v) => fmt::Display::fmt(v, f),
839 }
840 }
841}
842
843impl TypeTrace for WasmStorageType {
844 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
845 where
846 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
847 {
848 match self {
849 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
850 WasmStorageType::Val(v) => v.trace(func),
851 }
852 }
853
854 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
855 where
856 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
857 {
858 match self {
859 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
860 WasmStorageType::Val(v) => v.trace_mut(func),
861 }
862 }
863}
864
865#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
867pub struct WasmFieldType {
868 pub element_type: WasmStorageType,
870
871 pub mutable: bool,
873}
874
875impl fmt::Display for WasmFieldType {
876 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
877 if self.mutable {
878 write!(f, "(mut {})", self.element_type)
879 } else {
880 fmt::Display::fmt(&self.element_type, f)
881 }
882 }
883}
884
885impl TypeTrace for WasmFieldType {
886 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
887 where
888 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
889 {
890 self.element_type.trace(func)
891 }
892
893 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
894 where
895 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
896 {
897 self.element_type.trace_mut(func)
898 }
899}
900
901#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
903pub struct WasmArrayType(pub WasmFieldType);
904
905impl fmt::Display for WasmArrayType {
906 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
907 write!(f, "(array {})", self.0)
908 }
909}
910
911impl TypeTrace for WasmArrayType {
912 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
913 where
914 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
915 {
916 self.0.trace(func)
917 }
918
919 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
920 where
921 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
922 {
923 self.0.trace_mut(func)
924 }
925}
926
927#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
929pub struct WasmStructType {
930 pub fields: Box<[WasmFieldType]>,
932}
933
934impl fmt::Display for WasmStructType {
935 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
936 write!(f, "(struct")?;
937 for ty in self.fields.iter() {
938 write!(f, " {ty}")?;
939 }
940 write!(f, ")")
941 }
942}
943
944impl TypeTrace for WasmStructType {
945 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
946 where
947 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
948 {
949 for f in self.fields.iter() {
950 f.trace(func)?;
951 }
952 Ok(())
953 }
954
955 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
956 where
957 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
958 {
959 for f in self.fields.iter_mut() {
960 f.trace_mut(func)?;
961 }
962 Ok(())
963 }
964}
965
966#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
967#[allow(missing_docs, reason = "self-describing type")]
968pub struct WasmCompositeType {
969 pub inner: WasmCompositeInnerType,
971 pub shared: bool,
974}
975
976impl fmt::Display for WasmCompositeType {
977 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
978 if self.shared {
979 write!(f, "(shared ")?;
980 }
981 fmt::Display::fmt(&self.inner, f)?;
982 if self.shared {
983 write!(f, ")")?;
984 }
985 Ok(())
986 }
987}
988
989#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
991#[allow(missing_docs, reason = "self-describing variants")]
992pub enum WasmCompositeInnerType {
993 Array(WasmArrayType),
994 Func(WasmFuncType),
995 Struct(WasmStructType),
996 Cont(WasmContType),
997}
998
999impl fmt::Display for WasmCompositeInnerType {
1000 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1001 match self {
1002 Self::Array(ty) => fmt::Display::fmt(ty, f),
1003 Self::Func(ty) => fmt::Display::fmt(ty, f),
1004 Self::Struct(ty) => fmt::Display::fmt(ty, f),
1005 Self::Cont(ty) => fmt::Display::fmt(ty, f),
1006 }
1007 }
1008}
1009
1010#[allow(missing_docs, reason = "self-describing functions")]
1011impl WasmCompositeInnerType {
1012 #[inline]
1013 pub fn is_array(&self) -> bool {
1014 matches!(self, Self::Array(_))
1015 }
1016
1017 #[inline]
1018 pub fn as_array(&self) -> Option<&WasmArrayType> {
1019 match self {
1020 Self::Array(f) => Some(f),
1021 _ => None,
1022 }
1023 }
1024
1025 #[inline]
1026 pub fn unwrap_array(&self) -> &WasmArrayType {
1027 self.as_array().unwrap()
1028 }
1029
1030 #[inline]
1031 pub fn is_func(&self) -> bool {
1032 matches!(self, Self::Func(_))
1033 }
1034
1035 #[inline]
1036 pub fn as_func(&self) -> Option<&WasmFuncType> {
1037 match self {
1038 Self::Func(f) => Some(f),
1039 _ => None,
1040 }
1041 }
1042
1043 #[inline]
1044 pub fn unwrap_func(&self) -> &WasmFuncType {
1045 self.as_func().unwrap()
1046 }
1047
1048 #[inline]
1049 pub fn is_struct(&self) -> bool {
1050 matches!(self, Self::Struct(_))
1051 }
1052
1053 #[inline]
1054 pub fn as_struct(&self) -> Option<&WasmStructType> {
1055 match self {
1056 Self::Struct(f) => Some(f),
1057 _ => None,
1058 }
1059 }
1060
1061 #[inline]
1062 pub fn unwrap_struct(&self) -> &WasmStructType {
1063 self.as_struct().unwrap()
1064 }
1065
1066 #[inline]
1067 pub fn is_cont(&self) -> bool {
1068 matches!(self, Self::Cont(_))
1069 }
1070
1071 #[inline]
1072 pub fn as_cont(&self) -> Option<&WasmContType> {
1073 match self {
1074 Self::Cont(f) => Some(f),
1075 _ => None,
1076 }
1077 }
1078
1079 #[inline]
1080 pub fn unwrap_cont(&self) -> &WasmContType {
1081 self.as_cont().unwrap()
1082 }
1083}
1084
1085impl TypeTrace for WasmCompositeType {
1086 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1087 where
1088 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1089 {
1090 match &self.inner {
1091 WasmCompositeInnerType::Array(a) => a.trace(func),
1092 WasmCompositeInnerType::Func(f) => f.trace(func),
1093 WasmCompositeInnerType::Struct(a) => a.trace(func),
1094 WasmCompositeInnerType::Cont(c) => c.trace(func),
1095 }
1096 }
1097
1098 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1099 where
1100 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1101 {
1102 match &mut self.inner {
1103 WasmCompositeInnerType::Array(a) => a.trace_mut(func),
1104 WasmCompositeInnerType::Func(f) => f.trace_mut(func),
1105 WasmCompositeInnerType::Struct(a) => a.trace_mut(func),
1106 WasmCompositeInnerType::Cont(c) => c.trace_mut(func),
1107 }
1108 }
1109}
1110
1111#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1113pub struct WasmSubType {
1114 pub is_final: bool,
1117
1118 pub supertype: Option<EngineOrModuleTypeIndex>,
1120
1121 pub composite_type: WasmCompositeType,
1123}
1124
1125impl fmt::Display for WasmSubType {
1126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1127 if self.is_final && self.supertype.is_none() {
1128 fmt::Display::fmt(&self.composite_type, f)
1129 } else {
1130 write!(f, "(sub")?;
1131 if self.is_final {
1132 write!(f, " final")?;
1133 }
1134 if let Some(sup) = self.supertype {
1135 write!(f, " {sup}")?;
1136 }
1137 write!(f, " {})", self.composite_type)
1138 }
1139 }
1140}
1141
1142#[allow(missing_docs, reason = "self-describing functions")]
1146impl WasmSubType {
1147 #[inline]
1148 pub fn is_func(&self) -> bool {
1149 self.composite_type.inner.is_func() && !self.composite_type.shared
1150 }
1151
1152 #[inline]
1153 pub fn as_func(&self) -> Option<&WasmFuncType> {
1154 if self.composite_type.shared {
1155 None
1156 } else {
1157 self.composite_type.inner.as_func()
1158 }
1159 }
1160
1161 #[inline]
1162 pub fn unwrap_func(&self) -> &WasmFuncType {
1163 assert!(!self.composite_type.shared);
1164 self.composite_type.inner.unwrap_func()
1165 }
1166
1167 #[inline]
1168 pub fn is_array(&self) -> bool {
1169 self.composite_type.inner.is_array() && !self.composite_type.shared
1170 }
1171
1172 #[inline]
1173 pub fn as_array(&self) -> Option<&WasmArrayType> {
1174 if self.composite_type.shared {
1175 None
1176 } else {
1177 self.composite_type.inner.as_array()
1178 }
1179 }
1180
1181 #[inline]
1182 pub fn unwrap_array(&self) -> &WasmArrayType {
1183 assert!(!self.composite_type.shared);
1184 self.composite_type.inner.unwrap_array()
1185 }
1186
1187 #[inline]
1188 pub fn is_struct(&self) -> bool {
1189 self.composite_type.inner.is_struct() && !self.composite_type.shared
1190 }
1191
1192 #[inline]
1193 pub fn as_struct(&self) -> Option<&WasmStructType> {
1194 if self.composite_type.shared {
1195 None
1196 } else {
1197 self.composite_type.inner.as_struct()
1198 }
1199 }
1200
1201 #[inline]
1202 pub fn unwrap_struct(&self) -> &WasmStructType {
1203 assert!(!self.composite_type.shared);
1204 self.composite_type.inner.unwrap_struct()
1205 }
1206
1207 #[inline]
1208 pub fn is_cont(&self) -> bool {
1209 self.composite_type.inner.is_cont() && !self.composite_type.shared
1210 }
1211
1212 #[inline]
1213 pub fn as_cont(&self) -> Option<&WasmContType> {
1214 if self.composite_type.shared {
1215 None
1216 } else {
1217 self.composite_type.inner.as_cont()
1218 }
1219 }
1220
1221 #[inline]
1222 pub fn unwrap_cont(&self) -> &WasmContType {
1223 assert!(!self.composite_type.shared);
1224 self.composite_type.inner.unwrap_cont()
1225 }
1226}
1227
1228impl TypeTrace for WasmSubType {
1229 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1230 where
1231 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1232 {
1233 if let Some(sup) = self.supertype {
1234 func(sup)?;
1235 }
1236 self.composite_type.trace(func)
1237 }
1238
1239 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1240 where
1241 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1242 {
1243 if let Some(sup) = self.supertype.as_mut() {
1244 func(sup)?;
1245 }
1246 self.composite_type.trace_mut(func)
1247 }
1248}
1249
1250#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1261pub struct WasmRecGroup {
1262 pub types: Box<[WasmSubType]>,
1264}
1265
1266impl TypeTrace for WasmRecGroup {
1267 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1268 where
1269 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1270 {
1271 for ty in self.types.iter() {
1272 ty.trace(func)?;
1273 }
1274 Ok(())
1275 }
1276
1277 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1278 where
1279 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1280 {
1281 for ty in self.types.iter_mut() {
1282 ty.trace_mut(func)?;
1283 }
1284 Ok(())
1285 }
1286}
1287
1288#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1290pub struct FuncIndex(u32);
1291entity_impl!(FuncIndex);
1292
1293#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1295pub struct DefinedFuncIndex(u32);
1296entity_impl!(DefinedFuncIndex);
1297
1298#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1300pub struct DefinedTableIndex(u32);
1301entity_impl!(DefinedTableIndex);
1302
1303#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1305pub struct DefinedMemoryIndex(u32);
1306entity_impl!(DefinedMemoryIndex);
1307
1308#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1310pub struct OwnedMemoryIndex(u32);
1311entity_impl!(OwnedMemoryIndex);
1312
1313#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1315pub struct DefinedGlobalIndex(u32);
1316entity_impl!(DefinedGlobalIndex);
1317
1318#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1320pub struct TableIndex(u32);
1321entity_impl!(TableIndex);
1322
1323#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1325pub struct GlobalIndex(u32);
1326entity_impl!(GlobalIndex);
1327
1328#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1330pub struct MemoryIndex(u32);
1331entity_impl!(MemoryIndex);
1332
1333#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1336pub struct ModuleInternedRecGroupIndex(u32);
1337entity_impl!(ModuleInternedRecGroupIndex);
1338
1339#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1342pub struct EngineInternedRecGroupIndex(u32);
1343entity_impl!(EngineInternedRecGroupIndex);
1344
1345#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1347pub struct TypeIndex(u32);
1348entity_impl!(TypeIndex);
1349
1350#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1356pub struct RecGroupRelativeTypeIndex(u32);
1357entity_impl!(RecGroupRelativeTypeIndex);
1358
1359#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1367pub struct ModuleInternedTypeIndex(u32);
1368entity_impl!(ModuleInternedTypeIndex);
1369
1370#[repr(transparent)] #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1379pub struct VMSharedTypeIndex(u32);
1380entity_impl!(VMSharedTypeIndex);
1381
1382impl VMSharedTypeIndex {
1383 #[inline]
1385 pub fn new(value: u32) -> Self {
1386 assert_ne!(
1387 value,
1388 u32::MAX,
1389 "u32::MAX is reserved for the default value"
1390 );
1391 Self(value)
1392 }
1393
1394 #[inline]
1396 pub fn bits(&self) -> u32 {
1397 self.0
1398 }
1399}
1400
1401impl Default for VMSharedTypeIndex {
1402 #[inline]
1403 fn default() -> Self {
1404 Self(u32::MAX)
1405 }
1406}
1407
1408#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1410pub struct DataIndex(u32);
1411entity_impl!(DataIndex);
1412
1413#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1415pub struct ElemIndex(u32);
1416entity_impl!(ElemIndex);
1417
1418#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1420pub struct DefinedTagIndex(u32);
1421entity_impl!(DefinedTagIndex);
1422
1423#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1425pub struct TagIndex(u32);
1426entity_impl!(TagIndex);
1427
1428#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1433pub struct StaticModuleIndex(u32);
1434entity_impl!(StaticModuleIndex);
1435
1436#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1438pub enum EntityIndex {
1439 Function(FuncIndex),
1441 Table(TableIndex),
1443 Memory(MemoryIndex),
1445 Global(GlobalIndex),
1447 Tag(TagIndex),
1449}
1450
1451impl From<FuncIndex> for EntityIndex {
1452 fn from(idx: FuncIndex) -> EntityIndex {
1453 EntityIndex::Function(idx)
1454 }
1455}
1456
1457impl From<TableIndex> for EntityIndex {
1458 fn from(idx: TableIndex) -> EntityIndex {
1459 EntityIndex::Table(idx)
1460 }
1461}
1462
1463impl From<MemoryIndex> for EntityIndex {
1464 fn from(idx: MemoryIndex) -> EntityIndex {
1465 EntityIndex::Memory(idx)
1466 }
1467}
1468
1469impl From<GlobalIndex> for EntityIndex {
1470 fn from(idx: GlobalIndex) -> EntityIndex {
1471 EntityIndex::Global(idx)
1472 }
1473}
1474
1475impl From<TagIndex> for EntityIndex {
1476 fn from(idx: TagIndex) -> EntityIndex {
1477 EntityIndex::Tag(idx)
1478 }
1479}
1480
1481#[derive(Clone, Debug, Serialize, Deserialize)]
1484pub enum EntityType {
1485 Global(Global),
1487 Memory(Memory),
1489 Tag(Tag),
1491 Table(Table),
1493 Function(EngineOrModuleTypeIndex),
1496}
1497
1498impl TypeTrace for EntityType {
1499 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1500 where
1501 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1502 {
1503 match self {
1504 Self::Global(g) => g.trace(func),
1505 Self::Table(t) => t.trace(func),
1506 Self::Function(idx) => func(*idx),
1507 Self::Memory(_) => Ok(()),
1508 Self::Tag(t) => t.trace(func),
1509 }
1510 }
1511
1512 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1513 where
1514 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1515 {
1516 match self {
1517 Self::Global(g) => g.trace_mut(func),
1518 Self::Table(t) => t.trace_mut(func),
1519 Self::Function(idx) => func(idx),
1520 Self::Memory(_) => Ok(()),
1521 Self::Tag(t) => t.trace_mut(func),
1522 }
1523 }
1524}
1525
1526impl EntityType {
1527 pub fn unwrap_global(&self) -> &Global {
1529 match self {
1530 EntityType::Global(g) => g,
1531 _ => panic!("not a global"),
1532 }
1533 }
1534
1535 pub fn unwrap_memory(&self) -> &Memory {
1537 match self {
1538 EntityType::Memory(g) => g,
1539 _ => panic!("not a memory"),
1540 }
1541 }
1542
1543 pub fn unwrap_tag(&self) -> &Tag {
1545 match self {
1546 EntityType::Tag(g) => g,
1547 _ => panic!("not a tag"),
1548 }
1549 }
1550
1551 pub fn unwrap_table(&self) -> &Table {
1553 match self {
1554 EntityType::Table(g) => g,
1555 _ => panic!("not a table"),
1556 }
1557 }
1558
1559 pub fn unwrap_func(&self) -> EngineOrModuleTypeIndex {
1561 match self {
1562 EntityType::Function(g) => *g,
1563 _ => panic!("not a func"),
1564 }
1565 }
1566}
1567
1568#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1576pub struct Global {
1577 pub wasm_ty: crate::WasmValType,
1579 pub mutability: bool,
1581}
1582
1583impl TypeTrace for Global {
1584 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1585 where
1586 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1587 {
1588 let Global {
1589 wasm_ty,
1590 mutability: _,
1591 } = self;
1592 wasm_ty.trace(func)
1593 }
1594
1595 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1596 where
1597 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1598 {
1599 let Global {
1600 wasm_ty,
1601 mutability: _,
1602 } = self;
1603 wasm_ty.trace_mut(func)
1604 }
1605}
1606
1607#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1611pub struct ConstExpr {
1612 ops: SmallVec<[ConstOp; 2]>,
1613}
1614
1615impl ConstExpr {
1616 pub fn new(ops: impl IntoIterator<Item = ConstOp>) -> Self {
1622 let ops = ops.into_iter().collect::<SmallVec<[ConstOp; 2]>>();
1623 assert!(!ops.is_empty());
1624 ConstExpr { ops }
1625 }
1626
1627 pub fn from_wasmparser(
1632 expr: wasmparser::ConstExpr<'_>,
1633 ) -> WasmResult<(Self, SmallVec<[FuncIndex; 1]>)> {
1634 let mut iter = expr
1635 .get_operators_reader()
1636 .into_iter_with_offsets()
1637 .peekable();
1638
1639 let mut ops = SmallVec::<[ConstOp; 2]>::new();
1640 let mut escaped = SmallVec::<[FuncIndex; 1]>::new();
1641 while let Some(res) = iter.next() {
1642 let (op, offset) = res?;
1643
1644 if matches!(op, wasmparser::Operator::End) && iter.peek().is_none() {
1648 break;
1649 }
1650
1651 if let wasmparser::Operator::RefFunc { function_index } = &op {
1654 escaped.push(FuncIndex::from_u32(*function_index));
1655 }
1656
1657 ops.push(ConstOp::from_wasmparser(op, offset)?);
1658 }
1659 Ok((Self { ops }, escaped))
1660 }
1661
1662 pub fn ops(&self) -> &[ConstOp] {
1664 &self.ops
1665 }
1666
1667 pub fn provably_nonzero_i32(&self) -> bool {
1677 assert!(self.ops.len() > 0);
1678 if self.ops.len() > 1 {
1679 return false;
1682 }
1683 match self.ops[0] {
1685 ConstOp::I32Const(0) => false,
1687 ConstOp::I32Const(_) => true,
1690 _ => false,
1692 }
1693 }
1694}
1695
1696#[allow(missing_docs, reason = "self-describing variants")]
1698#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1699pub enum ConstOp {
1700 I32Const(i32),
1701 I64Const(i64),
1702 F32Const(u32),
1703 F64Const(u64),
1704 V128Const(u128),
1705 GlobalGet(GlobalIndex),
1706 RefI31,
1707 RefNull,
1708 RefFunc(FuncIndex),
1709 I32Add,
1710 I32Sub,
1711 I32Mul,
1712 I64Add,
1713 I64Sub,
1714 I64Mul,
1715 StructNew {
1716 struct_type_index: TypeIndex,
1717 },
1718 StructNewDefault {
1719 struct_type_index: TypeIndex,
1720 },
1721 ArrayNew {
1722 array_type_index: TypeIndex,
1723 },
1724 ArrayNewDefault {
1725 array_type_index: TypeIndex,
1726 },
1727 ArrayNewFixed {
1728 array_type_index: TypeIndex,
1729 array_size: u32,
1730 },
1731}
1732
1733impl ConstOp {
1734 pub fn from_wasmparser(op: wasmparser::Operator<'_>, offset: usize) -> WasmResult<Self> {
1736 use wasmparser::Operator as O;
1737 Ok(match op {
1738 O::I32Const { value } => Self::I32Const(value),
1739 O::I64Const { value } => Self::I64Const(value),
1740 O::F32Const { value } => Self::F32Const(value.bits()),
1741 O::F64Const { value } => Self::F64Const(value.bits()),
1742 O::V128Const { value } => Self::V128Const(u128::from_le_bytes(*value.bytes())),
1743 O::RefNull { hty: _ } => Self::RefNull,
1744 O::RefFunc { function_index } => Self::RefFunc(FuncIndex::from_u32(function_index)),
1745 O::GlobalGet { global_index } => Self::GlobalGet(GlobalIndex::from_u32(global_index)),
1746 O::RefI31 => Self::RefI31,
1747 O::I32Add => Self::I32Add,
1748 O::I32Sub => Self::I32Sub,
1749 O::I32Mul => Self::I32Mul,
1750 O::I64Add => Self::I64Add,
1751 O::I64Sub => Self::I64Sub,
1752 O::I64Mul => Self::I64Mul,
1753 O::StructNew { struct_type_index } => Self::StructNew {
1754 struct_type_index: TypeIndex::from_u32(struct_type_index),
1755 },
1756 O::StructNewDefault { struct_type_index } => Self::StructNewDefault {
1757 struct_type_index: TypeIndex::from_u32(struct_type_index),
1758 },
1759 O::ArrayNew { array_type_index } => Self::ArrayNew {
1760 array_type_index: TypeIndex::from_u32(array_type_index),
1761 },
1762 O::ArrayNewDefault { array_type_index } => Self::ArrayNewDefault {
1763 array_type_index: TypeIndex::from_u32(array_type_index),
1764 },
1765 O::ArrayNewFixed {
1766 array_type_index,
1767 array_size,
1768 } => Self::ArrayNewFixed {
1769 array_type_index: TypeIndex::from_u32(array_type_index),
1770 array_size,
1771 },
1772 op => {
1773 return Err(wasm_unsupported!(
1774 "unsupported opcode in const expression at offset {offset:#x}: {op:?}",
1775 ));
1776 }
1777 })
1778 }
1779}
1780
1781#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1783#[allow(missing_docs, reason = "self-describing variants")]
1784pub enum IndexType {
1785 I32,
1786 I64,
1787}
1788
1789#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1791#[allow(missing_docs, reason = "self-describing fields")]
1792pub struct Limits {
1793 pub min: u64,
1794 pub max: Option<u64>,
1795}
1796
1797#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1799pub struct Table {
1800 pub idx_type: IndexType,
1802 pub limits: Limits,
1805 pub ref_type: WasmRefType,
1807}
1808
1809impl TypeTrace for Table {
1810 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1811 where
1812 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1813 {
1814 let Table {
1815 ref_type: wasm_ty,
1816 idx_type: _,
1817 limits: _,
1818 } = self;
1819 wasm_ty.trace(func)
1820 }
1821
1822 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1823 where
1824 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1825 {
1826 let Table {
1827 ref_type: wasm_ty,
1828 idx_type: _,
1829 limits: _,
1830 } = self;
1831 wasm_ty.trace_mut(func)
1832 }
1833}
1834
1835#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1837pub struct Memory {
1838 pub idx_type: IndexType,
1840 pub limits: Limits,
1843 pub shared: bool,
1845 pub page_size_log2: u8,
1850}
1851
1852pub const WASM32_MAX_SIZE: u64 = 1 << 32;
1854
1855impl Memory {
1856 pub const DEFAULT_PAGE_SIZE: u32 = 0x10000;
1858
1859 pub const DEFAULT_PAGE_SIZE_LOG2: u8 = {
1861 let log2 = 16;
1862 assert!(1 << log2 == Memory::DEFAULT_PAGE_SIZE);
1863 log2
1864 };
1865
1866 pub fn minimum_byte_size(&self) -> Result<u64, SizeOverflow> {
1874 self.limits
1875 .min
1876 .checked_mul(self.page_size())
1877 .ok_or(SizeOverflow)
1878 }
1879
1880 pub fn maximum_byte_size(&self) -> Result<u64, SizeOverflow> {
1895 match self.limits.max {
1896 Some(max) => max.checked_mul(self.page_size()).ok_or(SizeOverflow),
1897 None => {
1898 let min = self.minimum_byte_size()?;
1899 Ok(min.max(self.max_size_based_on_index_type()))
1900 }
1901 }
1902 }
1903
1904 pub fn page_size(&self) -> u64 {
1906 debug_assert!(
1907 self.page_size_log2 == 16 || self.page_size_log2 == 0,
1908 "invalid page_size_log2: {}; must be 16 or 0",
1909 self.page_size_log2
1910 );
1911 1 << self.page_size_log2
1912 }
1913
1914 pub fn max_size_based_on_index_type(&self) -> u64 {
1919 match self.idx_type {
1920 IndexType::I64 =>
1921 {
1929 0_u64.wrapping_sub(self.page_size())
1930 }
1931 IndexType::I32 => WASM32_MAX_SIZE,
1932 }
1933 }
1934
1935 pub fn can_use_virtual_memory(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
1947 tunables.signals_based_traps && self.page_size_log2 >= host_page_size_log2
1948 }
1949
1950 pub fn can_elide_bounds_check(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
1970 self.can_use_virtual_memory(tunables, host_page_size_log2)
1971 && self.idx_type == IndexType::I32
1972 && tunables.memory_reservation >= (1 << 32)
1973 }
1974
1975 pub fn static_heap_size(&self) -> Option<u64> {
1979 let min = self.minimum_byte_size().ok()?;
1980 let max = self.maximum_byte_size().ok()?;
1981 if min == max {
1982 Some(min)
1983 } else {
1984 None
1985 }
1986 }
1987
1988 pub fn memory_may_move(&self, tunables: &Tunables) -> bool {
1995 if self.shared {
1999 return false;
2000 }
2001
2002 if !tunables.memory_may_move {
2005 return false;
2006 }
2007
2008 let max = self.maximum_byte_size().unwrap_or(u64::MAX);
2011 max > tunables.memory_reservation
2012 }
2013}
2014
2015#[derive(Copy, Clone, Debug)]
2016#[allow(missing_docs, reason = "self-describing error struct")]
2017pub struct SizeOverflow;
2018
2019impl fmt::Display for SizeOverflow {
2020 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2021 f.write_str("size overflow calculating memory size")
2022 }
2023}
2024
2025impl core::error::Error for SizeOverflow {}
2026
2027impl From<wasmparser::MemoryType> for Memory {
2028 fn from(ty: wasmparser::MemoryType) -> Memory {
2029 let idx_type = match ty.memory64 {
2030 false => IndexType::I32,
2031 true => IndexType::I64,
2032 };
2033 let limits = Limits {
2034 min: ty.initial,
2035 max: ty.maximum,
2036 };
2037 let page_size_log2 = u8::try_from(ty.page_size_log2.unwrap_or(16)).unwrap();
2038 debug_assert!(
2039 page_size_log2 == 16 || page_size_log2 == 0,
2040 "invalid page_size_log2: {page_size_log2}; must be 16 or 0"
2041 );
2042 Memory {
2043 idx_type,
2044 limits,
2045 shared: ty.shared,
2046 page_size_log2,
2047 }
2048 }
2049}
2050
2051#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
2053pub struct Tag {
2054 pub signature: EngineOrModuleTypeIndex,
2056}
2057
2058impl TypeTrace for Tag {
2059 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
2060 where
2061 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
2062 {
2063 func(self.signature)
2064 }
2065
2066 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
2067 where
2068 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
2069 {
2070 func(&mut self.signature)
2071 }
2072}
2073
2074#[allow(missing_docs, reason = "self-describing functions")]
2076pub trait TypeConvert {
2077 fn convert_global_type(&self, ty: &wasmparser::GlobalType) -> Global {
2079 Global {
2080 wasm_ty: self.convert_valtype(ty.content_type),
2081 mutability: ty.mutable,
2082 }
2083 }
2084
2085 fn convert_table_type(&self, ty: &wasmparser::TableType) -> WasmResult<Table> {
2087 let idx_type = match ty.table64 {
2088 false => IndexType::I32,
2089 true => IndexType::I64,
2090 };
2091 let limits = Limits {
2092 min: ty.initial.try_into().unwrap(),
2093 max: ty.maximum.map(|i| i.try_into().unwrap()),
2094 };
2095 Ok(Table {
2096 idx_type,
2097 limits,
2098 ref_type: self.convert_ref_type(ty.element_type),
2099 })
2100 }
2101
2102 fn convert_sub_type(&self, ty: &wasmparser::SubType) -> WasmSubType {
2103 WasmSubType {
2104 is_final: ty.is_final,
2105 supertype: ty.supertype_idx.map(|i| self.lookup_type_index(i.unpack())),
2106 composite_type: self.convert_composite_type(&ty.composite_type),
2107 }
2108 }
2109
2110 fn convert_composite_type(&self, ty: &wasmparser::CompositeType) -> WasmCompositeType {
2111 let inner = match &ty.inner {
2112 wasmparser::CompositeInnerType::Func(f) => {
2113 WasmCompositeInnerType::Func(self.convert_func_type(f))
2114 }
2115 wasmparser::CompositeInnerType::Array(a) => {
2116 WasmCompositeInnerType::Array(self.convert_array_type(a))
2117 }
2118 wasmparser::CompositeInnerType::Struct(s) => {
2119 WasmCompositeInnerType::Struct(self.convert_struct_type(s))
2120 }
2121 wasmparser::CompositeInnerType::Cont(c) => {
2122 WasmCompositeInnerType::Cont(self.convert_cont_type(c))
2123 }
2124 };
2125 WasmCompositeType {
2126 inner,
2127 shared: ty.shared,
2128 }
2129 }
2130
2131 fn convert_cont_type(&self, ty: &wasmparser::ContType) -> WasmContType {
2133 if let WasmHeapType::ConcreteFunc(sigidx) = self.lookup_heap_type(ty.0.unpack()) {
2134 WasmContType::new(sigidx)
2135 } else {
2136 panic!("Failed to extract signature index for continuation type.")
2137 }
2138 }
2139
2140 fn convert_struct_type(&self, ty: &wasmparser::StructType) -> WasmStructType {
2141 WasmStructType {
2142 fields: ty
2143 .fields
2144 .iter()
2145 .map(|f| self.convert_field_type(f))
2146 .collect(),
2147 }
2148 }
2149
2150 fn convert_array_type(&self, ty: &wasmparser::ArrayType) -> WasmArrayType {
2151 WasmArrayType(self.convert_field_type(&ty.0))
2152 }
2153
2154 fn convert_field_type(&self, ty: &wasmparser::FieldType) -> WasmFieldType {
2155 WasmFieldType {
2156 element_type: self.convert_storage_type(&ty.element_type),
2157 mutable: ty.mutable,
2158 }
2159 }
2160
2161 fn convert_storage_type(&self, ty: &wasmparser::StorageType) -> WasmStorageType {
2162 match ty {
2163 wasmparser::StorageType::I8 => WasmStorageType::I8,
2164 wasmparser::StorageType::I16 => WasmStorageType::I16,
2165 wasmparser::StorageType::Val(v) => WasmStorageType::Val(self.convert_valtype(*v)),
2166 }
2167 }
2168
2169 fn convert_func_type(&self, ty: &wasmparser::FuncType) -> WasmFuncType {
2171 let params = ty
2172 .params()
2173 .iter()
2174 .map(|t| self.convert_valtype(*t))
2175 .collect();
2176 let results = ty
2177 .results()
2178 .iter()
2179 .map(|t| self.convert_valtype(*t))
2180 .collect();
2181 WasmFuncType::new(params, results)
2182 }
2183
2184 fn convert_valtype(&self, ty: wasmparser::ValType) -> WasmValType {
2186 match ty {
2187 wasmparser::ValType::I32 => WasmValType::I32,
2188 wasmparser::ValType::I64 => WasmValType::I64,
2189 wasmparser::ValType::F32 => WasmValType::F32,
2190 wasmparser::ValType::F64 => WasmValType::F64,
2191 wasmparser::ValType::V128 => WasmValType::V128,
2192 wasmparser::ValType::Ref(t) => WasmValType::Ref(self.convert_ref_type(t)),
2193 }
2194 }
2195
2196 fn convert_ref_type(&self, ty: wasmparser::RefType) -> WasmRefType {
2198 WasmRefType {
2199 nullable: ty.is_nullable(),
2200 heap_type: self.convert_heap_type(ty.heap_type()),
2201 }
2202 }
2203
2204 fn convert_heap_type(&self, ty: wasmparser::HeapType) -> WasmHeapType {
2206 match ty {
2207 wasmparser::HeapType::Concrete(i) => self.lookup_heap_type(i),
2208 wasmparser::HeapType::Abstract { ty, shared: false } => match ty {
2209 wasmparser::AbstractHeapType::Extern => WasmHeapType::Extern,
2210 wasmparser::AbstractHeapType::NoExtern => WasmHeapType::NoExtern,
2211 wasmparser::AbstractHeapType::Func => WasmHeapType::Func,
2212 wasmparser::AbstractHeapType::NoFunc => WasmHeapType::NoFunc,
2213 wasmparser::AbstractHeapType::Any => WasmHeapType::Any,
2214 wasmparser::AbstractHeapType::Eq => WasmHeapType::Eq,
2215 wasmparser::AbstractHeapType::I31 => WasmHeapType::I31,
2216 wasmparser::AbstractHeapType::Array => WasmHeapType::Array,
2217 wasmparser::AbstractHeapType::Struct => WasmHeapType::Struct,
2218 wasmparser::AbstractHeapType::None => WasmHeapType::None,
2219
2220 wasmparser::AbstractHeapType::Exn
2221 | wasmparser::AbstractHeapType::NoExn
2222 | wasmparser::AbstractHeapType::Cont
2223 | wasmparser::AbstractHeapType::NoCont => {
2224 unimplemented!("unsupported heap type {ty:?}");
2225 }
2226 },
2227 _ => unimplemented!("unsupported heap type {ty:?}"),
2228 }
2229 }
2230
2231 fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType;
2234
2235 fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex;
2238}