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!("invaid 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 pub fn unwrap_engine_type_index(self) -> VMSharedTypeIndex {
374 self.as_engine_type_index()
375 .unwrap_or_else(|| panic!("`unwrap_engine_type_index` on {self:?}"))
376 }
377
378 pub fn is_module_type_index(self) -> bool {
380 matches!(self, Self::Module(_))
381 }
382
383 pub fn as_module_type_index(self) -> Option<ModuleInternedTypeIndex> {
385 match self {
386 Self::Module(e) => Some(e),
387 Self::RecGroup(_) | Self::Engine(_) => None,
388 }
389 }
390
391 pub fn unwrap_module_type_index(self) -> ModuleInternedTypeIndex {
393 self.as_module_type_index()
394 .unwrap_or_else(|| panic!("`unwrap_module_type_index` on {self:?}"))
395 }
396
397 pub fn is_rec_group_type_index(self) -> bool {
399 matches!(self, Self::RecGroup(_))
400 }
401
402 pub fn as_rec_group_type_index(self) -> Option<RecGroupRelativeTypeIndex> {
404 match self {
405 Self::RecGroup(r) => Some(r),
406 Self::Module(_) | Self::Engine(_) => None,
407 }
408 }
409
410 pub fn unwrap_rec_group_type_index(self) -> RecGroupRelativeTypeIndex {
412 self.as_rec_group_type_index()
413 .unwrap_or_else(|| panic!("`unwrap_rec_group_type_index` on {self:?}"))
414 }
415}
416
417#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
419#[allow(missing_docs, reason = "self-describing variants")]
420pub enum WasmHeapType {
421 Extern,
423 NoExtern,
424
425 Func,
427 ConcreteFunc(EngineOrModuleTypeIndex),
428 NoFunc,
429
430 Any,
432 Eq,
433 I31,
434 Array,
435 ConcreteArray(EngineOrModuleTypeIndex),
436 Struct,
437 ConcreteStruct(EngineOrModuleTypeIndex),
438 None,
439}
440
441impl From<WasmHeapTopType> for WasmHeapType {
442 #[inline]
443 fn from(value: WasmHeapTopType) -> Self {
444 match value {
445 WasmHeapTopType::Extern => Self::Extern,
446 WasmHeapTopType::Any => Self::Any,
447 WasmHeapTopType::Func => Self::Func,
448 }
449 }
450}
451
452impl From<WasmHeapBottomType> for WasmHeapType {
453 #[inline]
454 fn from(value: WasmHeapBottomType) -> Self {
455 match value {
456 WasmHeapBottomType::NoExtern => Self::NoExtern,
457 WasmHeapBottomType::None => Self::None,
458 WasmHeapBottomType::NoFunc => Self::NoFunc,
459 }
460 }
461}
462
463impl fmt::Display for WasmHeapType {
464 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
465 match self {
466 Self::Extern => write!(f, "extern"),
467 Self::NoExtern => write!(f, "noextern"),
468 Self::Func => write!(f, "func"),
469 Self::ConcreteFunc(i) => write!(f, "func {i}"),
470 Self::NoFunc => write!(f, "nofunc"),
471 Self::Any => write!(f, "any"),
472 Self::Eq => write!(f, "eq"),
473 Self::I31 => write!(f, "i31"),
474 Self::Array => write!(f, "array"),
475 Self::ConcreteArray(i) => write!(f, "array {i}"),
476 Self::Struct => write!(f, "struct"),
477 Self::ConcreteStruct(i) => write!(f, "struct {i}"),
478 Self::None => write!(f, "none"),
479 }
480 }
481}
482
483impl TypeTrace for WasmHeapType {
484 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
485 where
486 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
487 {
488 match *self {
489 Self::ConcreteArray(i) => func(i),
490 Self::ConcreteFunc(i) => func(i),
491 Self::ConcreteStruct(i) => func(i),
492 _ => Ok(()),
493 }
494 }
495
496 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
497 where
498 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
499 {
500 match self {
501 Self::ConcreteArray(i) => func(i),
502 Self::ConcreteFunc(i) => func(i),
503 Self::ConcreteStruct(i) => func(i),
504 _ => Ok(()),
505 }
506 }
507}
508
509impl WasmHeapType {
510 #[inline]
512 pub fn is_vmgcref_type(&self) -> bool {
513 match self.top() {
514 WasmHeapTopType::Any | WasmHeapTopType::Extern => true,
517
518 WasmHeapTopType::Func => false,
520 }
521 }
522
523 #[inline]
529 pub fn is_vmgcref_type_and_not_i31(&self) -> bool {
530 self.is_vmgcref_type() && *self != Self::I31
531 }
532
533 #[inline]
535 pub fn is_top(&self) -> bool {
536 *self == Self::from(self.top())
537 }
538
539 #[inline]
541 pub fn top(&self) -> WasmHeapTopType {
542 match self {
543 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapTopType::Extern,
544
545 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
546 WasmHeapTopType::Func
547 }
548
549 WasmHeapType::Any
550 | WasmHeapType::Eq
551 | WasmHeapType::I31
552 | WasmHeapType::Array
553 | WasmHeapType::ConcreteArray(_)
554 | WasmHeapType::Struct
555 | WasmHeapType::ConcreteStruct(_)
556 | WasmHeapType::None => WasmHeapTopType::Any,
557 }
558 }
559
560 #[inline]
562 pub fn is_bottom(&self) -> bool {
563 *self == Self::from(self.bottom())
564 }
565
566 #[inline]
568 pub fn bottom(&self) -> WasmHeapBottomType {
569 match self {
570 WasmHeapType::Extern | WasmHeapType::NoExtern => WasmHeapBottomType::NoExtern,
571
572 WasmHeapType::Func | WasmHeapType::ConcreteFunc(_) | WasmHeapType::NoFunc => {
573 WasmHeapBottomType::NoFunc
574 }
575
576 WasmHeapType::Any
577 | WasmHeapType::Eq
578 | WasmHeapType::I31
579 | WasmHeapType::Array
580 | WasmHeapType::ConcreteArray(_)
581 | WasmHeapType::Struct
582 | WasmHeapType::ConcreteStruct(_)
583 | WasmHeapType::None => WasmHeapBottomType::None,
584 }
585 }
586}
587
588#[derive(Debug, Clone, Copy, Eq, PartialEq)]
590pub enum WasmHeapTopType {
591 Extern,
593 Any,
595 Func,
597}
598
599#[derive(Debug, Clone, Copy, Eq, PartialEq)]
601pub enum WasmHeapBottomType {
602 NoExtern,
604 None,
606 NoFunc,
608}
609
610#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
612pub struct WasmFuncType {
613 params: Box<[WasmValType]>,
614 non_i31_gc_ref_params_count: usize,
615 returns: Box<[WasmValType]>,
616 non_i31_gc_ref_returns_count: usize,
617}
618
619impl fmt::Display for WasmFuncType {
620 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
621 write!(f, "(func")?;
622 if !self.params.is_empty() {
623 write!(f, " (param")?;
624 for p in self.params.iter() {
625 write!(f, " {p}")?;
626 }
627 write!(f, ")")?;
628 }
629 if !self.returns.is_empty() {
630 write!(f, " (result")?;
631 for r in self.returns.iter() {
632 write!(f, " {r}")?;
633 }
634 write!(f, ")")?;
635 }
636 write!(f, ")")
637 }
638}
639
640impl TypeTrace for WasmFuncType {
641 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
642 where
643 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
644 {
645 for p in self.params.iter() {
646 p.trace(func)?;
647 }
648 for r in self.returns.iter() {
649 r.trace(func)?;
650 }
651 Ok(())
652 }
653
654 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
655 where
656 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
657 {
658 for p in self.params.iter_mut() {
659 p.trace_mut(func)?;
660 }
661 for r in self.returns.iter_mut() {
662 r.trace_mut(func)?;
663 }
664 Ok(())
665 }
666}
667
668impl WasmFuncType {
669 #[inline]
671 pub fn new(params: Box<[WasmValType]>, returns: Box<[WasmValType]>) -> Self {
672 let non_i31_gc_ref_params_count = params
673 .iter()
674 .filter(|p| p.is_vmgcref_type_and_not_i31())
675 .count();
676 let non_i31_gc_ref_returns_count = returns
677 .iter()
678 .filter(|r| r.is_vmgcref_type_and_not_i31())
679 .count();
680 WasmFuncType {
681 params,
682 non_i31_gc_ref_params_count,
683 returns,
684 non_i31_gc_ref_returns_count,
685 }
686 }
687
688 #[inline]
690 pub fn params(&self) -> &[WasmValType] {
691 &self.params
692 }
693
694 #[inline]
696 pub fn non_i31_gc_ref_params_count(&self) -> usize {
697 self.non_i31_gc_ref_params_count
698 }
699
700 #[inline]
702 pub fn returns(&self) -> &[WasmValType] {
703 &self.returns
704 }
705
706 #[inline]
708 pub fn non_i31_gc_ref_returns_count(&self) -> usize {
709 self.non_i31_gc_ref_returns_count
710 }
711
712 pub fn is_trampoline_type(&self) -> bool {
714 self.params().iter().all(|p| *p == p.trampoline_type())
715 && self.returns().iter().all(|r| *r == r.trampoline_type())
716 }
717
718 pub fn trampoline_type(&self) -> Cow<'_, Self> {
744 if self.is_trampoline_type() {
745 return Cow::Borrowed(self);
746 }
747
748 Cow::Owned(Self::new(
749 self.params().iter().map(|p| p.trampoline_type()).collect(),
750 self.returns().iter().map(|r| r.trampoline_type()).collect(),
751 ))
752 }
753}
754
755#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
757pub enum WasmStorageType {
758 I8,
760 I16,
762 Val(WasmValType),
764}
765
766impl fmt::Display for WasmStorageType {
767 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
768 match self {
769 WasmStorageType::I8 => write!(f, "i8"),
770 WasmStorageType::I16 => write!(f, "i16"),
771 WasmStorageType::Val(v) => fmt::Display::fmt(v, f),
772 }
773 }
774}
775
776impl TypeTrace for WasmStorageType {
777 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
778 where
779 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
780 {
781 match self {
782 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
783 WasmStorageType::Val(v) => v.trace(func),
784 }
785 }
786
787 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
788 where
789 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
790 {
791 match self {
792 WasmStorageType::I8 | WasmStorageType::I16 => Ok(()),
793 WasmStorageType::Val(v) => v.trace_mut(func),
794 }
795 }
796}
797
798#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
800pub struct WasmFieldType {
801 pub element_type: WasmStorageType,
803
804 pub mutable: bool,
806}
807
808impl fmt::Display for WasmFieldType {
809 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
810 if self.mutable {
811 write!(f, "(mut {})", self.element_type)
812 } else {
813 fmt::Display::fmt(&self.element_type, f)
814 }
815 }
816}
817
818impl TypeTrace for WasmFieldType {
819 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
820 where
821 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
822 {
823 self.element_type.trace(func)
824 }
825
826 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
827 where
828 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
829 {
830 self.element_type.trace_mut(func)
831 }
832}
833
834#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
836pub struct WasmArrayType(pub WasmFieldType);
837
838impl fmt::Display for WasmArrayType {
839 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
840 write!(f, "(array {})", self.0)
841 }
842}
843
844impl TypeTrace for WasmArrayType {
845 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
846 where
847 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
848 {
849 self.0.trace(func)
850 }
851
852 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
853 where
854 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
855 {
856 self.0.trace_mut(func)
857 }
858}
859
860#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
862pub struct WasmStructType {
863 pub fields: Box<[WasmFieldType]>,
865}
866
867impl fmt::Display for WasmStructType {
868 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
869 write!(f, "(struct")?;
870 for ty in self.fields.iter() {
871 write!(f, " {ty}")?;
872 }
873 write!(f, ")")
874 }
875}
876
877impl TypeTrace for WasmStructType {
878 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
879 where
880 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
881 {
882 for f in self.fields.iter() {
883 f.trace(func)?;
884 }
885 Ok(())
886 }
887
888 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
889 where
890 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
891 {
892 for f in self.fields.iter_mut() {
893 f.trace_mut(func)?;
894 }
895 Ok(())
896 }
897}
898
899#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
900#[allow(missing_docs, reason = "self-describing type")]
901pub struct WasmCompositeType {
902 pub inner: WasmCompositeInnerType,
904 pub shared: bool,
907}
908
909impl fmt::Display for WasmCompositeType {
910 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
911 if self.shared {
912 write!(f, "(shared ")?;
913 }
914 fmt::Display::fmt(&self.inner, f)?;
915 if self.shared {
916 write!(f, ")")?;
917 }
918 Ok(())
919 }
920}
921
922#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
924#[allow(missing_docs, reason = "self-describing variants")]
925pub enum WasmCompositeInnerType {
926 Array(WasmArrayType),
927 Func(WasmFuncType),
928 Struct(WasmStructType),
929}
930
931impl fmt::Display for WasmCompositeInnerType {
932 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
933 match self {
934 Self::Array(ty) => fmt::Display::fmt(ty, f),
935 Self::Func(ty) => fmt::Display::fmt(ty, f),
936 Self::Struct(ty) => fmt::Display::fmt(ty, f),
937 }
938 }
939}
940
941#[allow(missing_docs, reason = "self-describing functions")]
942impl WasmCompositeInnerType {
943 #[inline]
944 pub fn is_array(&self) -> bool {
945 matches!(self, Self::Array(_))
946 }
947
948 #[inline]
949 pub fn as_array(&self) -> Option<&WasmArrayType> {
950 match self {
951 Self::Array(f) => Some(f),
952 _ => None,
953 }
954 }
955
956 #[inline]
957 pub fn unwrap_array(&self) -> &WasmArrayType {
958 self.as_array().unwrap()
959 }
960
961 #[inline]
962 pub fn is_func(&self) -> bool {
963 matches!(self, Self::Func(_))
964 }
965
966 #[inline]
967 pub fn as_func(&self) -> Option<&WasmFuncType> {
968 match self {
969 Self::Func(f) => Some(f),
970 _ => None,
971 }
972 }
973
974 #[inline]
975 pub fn unwrap_func(&self) -> &WasmFuncType {
976 self.as_func().unwrap()
977 }
978
979 #[inline]
980 pub fn is_struct(&self) -> bool {
981 matches!(self, Self::Struct(_))
982 }
983
984 #[inline]
985 pub fn as_struct(&self) -> Option<&WasmStructType> {
986 match self {
987 Self::Struct(f) => Some(f),
988 _ => None,
989 }
990 }
991
992 #[inline]
993 pub fn unwrap_struct(&self) -> &WasmStructType {
994 self.as_struct().unwrap()
995 }
996}
997
998impl TypeTrace for WasmCompositeType {
999 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1000 where
1001 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1002 {
1003 match &self.inner {
1004 WasmCompositeInnerType::Array(a) => a.trace(func),
1005 WasmCompositeInnerType::Func(f) => f.trace(func),
1006 WasmCompositeInnerType::Struct(a) => a.trace(func),
1007 }
1008 }
1009
1010 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1011 where
1012 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1013 {
1014 match &mut self.inner {
1015 WasmCompositeInnerType::Array(a) => a.trace_mut(func),
1016 WasmCompositeInnerType::Func(f) => f.trace_mut(func),
1017 WasmCompositeInnerType::Struct(a) => a.trace_mut(func),
1018 }
1019 }
1020}
1021
1022#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1024pub struct WasmSubType {
1025 pub is_final: bool,
1028
1029 pub supertype: Option<EngineOrModuleTypeIndex>,
1031
1032 pub composite_type: WasmCompositeType,
1034}
1035
1036impl fmt::Display for WasmSubType {
1037 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1038 if self.is_final && self.supertype.is_none() {
1039 fmt::Display::fmt(&self.composite_type, f)
1040 } else {
1041 write!(f, "(sub")?;
1042 if self.is_final {
1043 write!(f, " final")?;
1044 }
1045 if let Some(sup) = self.supertype {
1046 write!(f, " {sup}")?;
1047 }
1048 write!(f, " {})", self.composite_type)
1049 }
1050 }
1051}
1052
1053#[allow(missing_docs, reason = "self-describing functions")]
1057impl WasmSubType {
1058 #[inline]
1059 pub fn is_func(&self) -> bool {
1060 self.composite_type.inner.is_func() && !self.composite_type.shared
1061 }
1062
1063 #[inline]
1064 pub fn as_func(&self) -> Option<&WasmFuncType> {
1065 if self.composite_type.shared {
1066 None
1067 } else {
1068 self.composite_type.inner.as_func()
1069 }
1070 }
1071
1072 #[inline]
1073 pub fn unwrap_func(&self) -> &WasmFuncType {
1074 assert!(!self.composite_type.shared);
1075 self.composite_type.inner.unwrap_func()
1076 }
1077
1078 #[inline]
1079 pub fn is_array(&self) -> bool {
1080 self.composite_type.inner.is_array() && !self.composite_type.shared
1081 }
1082
1083 #[inline]
1084 pub fn as_array(&self) -> Option<&WasmArrayType> {
1085 if self.composite_type.shared {
1086 None
1087 } else {
1088 self.composite_type.inner.as_array()
1089 }
1090 }
1091
1092 #[inline]
1093 pub fn unwrap_array(&self) -> &WasmArrayType {
1094 assert!(!self.composite_type.shared);
1095 self.composite_type.inner.unwrap_array()
1096 }
1097
1098 #[inline]
1099 pub fn is_struct(&self) -> bool {
1100 self.composite_type.inner.is_struct() && !self.composite_type.shared
1101 }
1102
1103 #[inline]
1104 pub fn as_struct(&self) -> Option<&WasmStructType> {
1105 if self.composite_type.shared {
1106 None
1107 } else {
1108 self.composite_type.inner.as_struct()
1109 }
1110 }
1111
1112 #[inline]
1113 pub fn unwrap_struct(&self) -> &WasmStructType {
1114 assert!(!self.composite_type.shared);
1115 self.composite_type.inner.unwrap_struct()
1116 }
1117}
1118
1119impl TypeTrace for WasmSubType {
1120 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1121 where
1122 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1123 {
1124 if let Some(sup) = self.supertype {
1125 func(sup)?;
1126 }
1127 self.composite_type.trace(func)
1128 }
1129
1130 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1131 where
1132 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1133 {
1134 if let Some(sup) = self.supertype.as_mut() {
1135 func(sup)?;
1136 }
1137 self.composite_type.trace_mut(func)
1138 }
1139}
1140
1141#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
1152pub struct WasmRecGroup {
1153 pub types: Box<[WasmSubType]>,
1155}
1156
1157impl TypeTrace for WasmRecGroup {
1158 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1159 where
1160 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1161 {
1162 for ty in self.types.iter() {
1163 ty.trace(func)?;
1164 }
1165 Ok(())
1166 }
1167
1168 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1169 where
1170 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1171 {
1172 for ty in self.types.iter_mut() {
1173 ty.trace_mut(func)?;
1174 }
1175 Ok(())
1176 }
1177}
1178
1179#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1181pub struct FuncIndex(u32);
1182entity_impl!(FuncIndex);
1183
1184#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1186pub struct DefinedFuncIndex(u32);
1187entity_impl!(DefinedFuncIndex);
1188
1189#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1191pub struct DefinedTableIndex(u32);
1192entity_impl!(DefinedTableIndex);
1193
1194#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1196pub struct DefinedMemoryIndex(u32);
1197entity_impl!(DefinedMemoryIndex);
1198
1199#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1201pub struct OwnedMemoryIndex(u32);
1202entity_impl!(OwnedMemoryIndex);
1203
1204#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1206pub struct DefinedGlobalIndex(u32);
1207entity_impl!(DefinedGlobalIndex);
1208
1209#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1211pub struct TableIndex(u32);
1212entity_impl!(TableIndex);
1213
1214#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1216pub struct GlobalIndex(u32);
1217entity_impl!(GlobalIndex);
1218
1219#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1221pub struct MemoryIndex(u32);
1222entity_impl!(MemoryIndex);
1223
1224#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1227pub struct ModuleInternedRecGroupIndex(u32);
1228entity_impl!(ModuleInternedRecGroupIndex);
1229
1230#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1233pub struct EngineInternedRecGroupIndex(u32);
1234entity_impl!(EngineInternedRecGroupIndex);
1235
1236#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1238pub struct TypeIndex(u32);
1239entity_impl!(TypeIndex);
1240
1241#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1247pub struct RecGroupRelativeTypeIndex(u32);
1248entity_impl!(RecGroupRelativeTypeIndex);
1249
1250#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1258pub struct ModuleInternedTypeIndex(u32);
1259entity_impl!(ModuleInternedTypeIndex);
1260
1261#[repr(transparent)] #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1270pub struct VMSharedTypeIndex(u32);
1271entity_impl!(VMSharedTypeIndex);
1272
1273impl VMSharedTypeIndex {
1274 #[inline]
1276 pub fn new(value: u32) -> Self {
1277 assert_ne!(
1278 value,
1279 u32::MAX,
1280 "u32::MAX is reserved for the default value"
1281 );
1282 Self(value)
1283 }
1284
1285 #[inline]
1287 pub fn bits(&self) -> u32 {
1288 self.0
1289 }
1290}
1291
1292impl Default for VMSharedTypeIndex {
1293 #[inline]
1294 fn default() -> Self {
1295 Self(u32::MAX)
1296 }
1297}
1298
1299#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1301pub struct DataIndex(u32);
1302entity_impl!(DataIndex);
1303
1304#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1306pub struct ElemIndex(u32);
1307entity_impl!(ElemIndex);
1308
1309#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1311pub struct TagIndex(u32);
1312entity_impl!(TagIndex);
1313
1314#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1319pub struct StaticModuleIndex(u32);
1320entity_impl!(StaticModuleIndex);
1321
1322#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
1324pub enum EntityIndex {
1325 Function(FuncIndex),
1327 Table(TableIndex),
1329 Memory(MemoryIndex),
1331 Global(GlobalIndex),
1333}
1334
1335impl From<FuncIndex> for EntityIndex {
1336 fn from(idx: FuncIndex) -> EntityIndex {
1337 EntityIndex::Function(idx)
1338 }
1339}
1340
1341impl From<TableIndex> for EntityIndex {
1342 fn from(idx: TableIndex) -> EntityIndex {
1343 EntityIndex::Table(idx)
1344 }
1345}
1346
1347impl From<MemoryIndex> for EntityIndex {
1348 fn from(idx: MemoryIndex) -> EntityIndex {
1349 EntityIndex::Memory(idx)
1350 }
1351}
1352
1353impl From<GlobalIndex> for EntityIndex {
1354 fn from(idx: GlobalIndex) -> EntityIndex {
1355 EntityIndex::Global(idx)
1356 }
1357}
1358
1359#[derive(Clone, Debug, Serialize, Deserialize)]
1362pub enum EntityType {
1363 Global(Global),
1365 Memory(Memory),
1367 Tag(Tag),
1369 Table(Table),
1371 Function(EngineOrModuleTypeIndex),
1374}
1375
1376impl TypeTrace for EntityType {
1377 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1378 where
1379 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1380 {
1381 match self {
1382 Self::Global(g) => g.trace(func),
1383 Self::Table(t) => t.trace(func),
1384 Self::Function(idx) => func(*idx),
1385 Self::Memory(_) | Self::Tag(_) => Ok(()),
1386 }
1387 }
1388
1389 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1390 where
1391 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1392 {
1393 match self {
1394 Self::Global(g) => g.trace_mut(func),
1395 Self::Table(t) => t.trace_mut(func),
1396 Self::Function(idx) => func(idx),
1397 Self::Memory(_) | Self::Tag(_) => Ok(()),
1398 }
1399 }
1400}
1401
1402impl EntityType {
1403 pub fn unwrap_global(&self) -> &Global {
1405 match self {
1406 EntityType::Global(g) => g,
1407 _ => panic!("not a global"),
1408 }
1409 }
1410
1411 pub fn unwrap_memory(&self) -> &Memory {
1413 match self {
1414 EntityType::Memory(g) => g,
1415 _ => panic!("not a memory"),
1416 }
1417 }
1418
1419 pub fn unwrap_tag(&self) -> &Tag {
1421 match self {
1422 EntityType::Tag(g) => g,
1423 _ => panic!("not a tag"),
1424 }
1425 }
1426
1427 pub fn unwrap_table(&self) -> &Table {
1429 match self {
1430 EntityType::Table(g) => g,
1431 _ => panic!("not a table"),
1432 }
1433 }
1434
1435 pub fn unwrap_func(&self) -> EngineOrModuleTypeIndex {
1437 match self {
1438 EntityType::Function(g) => *g,
1439 _ => panic!("not a func"),
1440 }
1441 }
1442}
1443
1444#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1452pub struct Global {
1453 pub wasm_ty: crate::WasmValType,
1455 pub mutability: bool,
1457}
1458
1459impl TypeTrace for Global {
1460 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1461 where
1462 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1463 {
1464 let Global {
1465 wasm_ty,
1466 mutability: _,
1467 } = self;
1468 wasm_ty.trace(func)
1469 }
1470
1471 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1472 where
1473 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1474 {
1475 let Global {
1476 wasm_ty,
1477 mutability: _,
1478 } = self;
1479 wasm_ty.trace_mut(func)
1480 }
1481}
1482
1483#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1487pub struct ConstExpr {
1488 ops: SmallVec<[ConstOp; 2]>,
1489}
1490
1491impl ConstExpr {
1492 pub fn new(ops: impl IntoIterator<Item = ConstOp>) -> Self {
1498 let ops = ops.into_iter().collect::<SmallVec<[ConstOp; 2]>>();
1499 assert!(!ops.is_empty());
1500 ConstExpr { ops }
1501 }
1502
1503 pub fn from_wasmparser(
1508 expr: wasmparser::ConstExpr<'_>,
1509 ) -> WasmResult<(Self, SmallVec<[FuncIndex; 1]>)> {
1510 let mut iter = expr
1511 .get_operators_reader()
1512 .into_iter_with_offsets()
1513 .peekable();
1514
1515 let mut ops = SmallVec::<[ConstOp; 2]>::new();
1516 let mut escaped = SmallVec::<[FuncIndex; 1]>::new();
1517 while let Some(res) = iter.next() {
1518 let (op, offset) = res?;
1519
1520 if matches!(op, wasmparser::Operator::End) && iter.peek().is_none() {
1524 break;
1525 }
1526
1527 if let wasmparser::Operator::RefFunc { function_index } = &op {
1530 escaped.push(FuncIndex::from_u32(*function_index));
1531 }
1532
1533 ops.push(ConstOp::from_wasmparser(op, offset)?);
1534 }
1535 Ok((Self { ops }, escaped))
1536 }
1537
1538 pub fn ops(&self) -> &[ConstOp] {
1540 &self.ops
1541 }
1542
1543 pub fn provably_nonzero_i32(&self) -> bool {
1553 assert!(self.ops.len() > 0);
1554 if self.ops.len() > 1 {
1555 return false;
1558 }
1559 match self.ops[0] {
1561 ConstOp::I32Const(0) => false,
1563 ConstOp::I32Const(_) => true,
1566 _ => false,
1568 }
1569 }
1570}
1571
1572#[allow(missing_docs, reason = "self-describing variants")]
1574#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
1575pub enum ConstOp {
1576 I32Const(i32),
1577 I64Const(i64),
1578 F32Const(u32),
1579 F64Const(u64),
1580 V128Const(u128),
1581 GlobalGet(GlobalIndex),
1582 RefI31,
1583 RefNull,
1584 RefFunc(FuncIndex),
1585 I32Add,
1586 I32Sub,
1587 I32Mul,
1588 I64Add,
1589 I64Sub,
1590 I64Mul,
1591 StructNew {
1592 struct_type_index: TypeIndex,
1593 },
1594 StructNewDefault {
1595 struct_type_index: TypeIndex,
1596 },
1597 ArrayNew {
1598 array_type_index: TypeIndex,
1599 },
1600 ArrayNewDefault {
1601 array_type_index: TypeIndex,
1602 },
1603 ArrayNewFixed {
1604 array_type_index: TypeIndex,
1605 array_size: u32,
1606 },
1607}
1608
1609impl ConstOp {
1610 pub fn from_wasmparser(op: wasmparser::Operator<'_>, offset: usize) -> WasmResult<Self> {
1612 use wasmparser::Operator as O;
1613 Ok(match op {
1614 O::I32Const { value } => Self::I32Const(value),
1615 O::I64Const { value } => Self::I64Const(value),
1616 O::F32Const { value } => Self::F32Const(value.bits()),
1617 O::F64Const { value } => Self::F64Const(value.bits()),
1618 O::V128Const { value } => Self::V128Const(u128::from_le_bytes(*value.bytes())),
1619 O::RefNull { hty: _ } => Self::RefNull,
1620 O::RefFunc { function_index } => Self::RefFunc(FuncIndex::from_u32(function_index)),
1621 O::GlobalGet { global_index } => Self::GlobalGet(GlobalIndex::from_u32(global_index)),
1622 O::RefI31 => Self::RefI31,
1623 O::I32Add => Self::I32Add,
1624 O::I32Sub => Self::I32Sub,
1625 O::I32Mul => Self::I32Mul,
1626 O::I64Add => Self::I64Add,
1627 O::I64Sub => Self::I64Sub,
1628 O::I64Mul => Self::I64Mul,
1629 O::StructNew { struct_type_index } => Self::StructNew {
1630 struct_type_index: TypeIndex::from_u32(struct_type_index),
1631 },
1632 O::StructNewDefault { struct_type_index } => Self::StructNewDefault {
1633 struct_type_index: TypeIndex::from_u32(struct_type_index),
1634 },
1635 O::ArrayNew { array_type_index } => Self::ArrayNew {
1636 array_type_index: TypeIndex::from_u32(array_type_index),
1637 },
1638 O::ArrayNewDefault { array_type_index } => Self::ArrayNewDefault {
1639 array_type_index: TypeIndex::from_u32(array_type_index),
1640 },
1641 O::ArrayNewFixed {
1642 array_type_index,
1643 array_size,
1644 } => Self::ArrayNewFixed {
1645 array_type_index: TypeIndex::from_u32(array_type_index),
1646 array_size,
1647 },
1648 op => {
1649 return Err(wasm_unsupported!(
1650 "unsupported opcode in const expression at offset {offset:#x}: {op:?}",
1651 ));
1652 }
1653 })
1654 }
1655}
1656
1657#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1659#[allow(missing_docs, reason = "self-describing variants")]
1660pub enum IndexType {
1661 I32,
1662 I64,
1663}
1664
1665#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1667#[allow(missing_docs, reason = "self-describing fields")]
1668pub struct Limits {
1669 pub min: u64,
1670 pub max: Option<u64>,
1671}
1672
1673#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1675pub struct Table {
1676 pub idx_type: IndexType,
1678 pub limits: Limits,
1681 pub ref_type: WasmRefType,
1683}
1684
1685impl TypeTrace for Table {
1686 fn trace<F, E>(&self, func: &mut F) -> Result<(), E>
1687 where
1688 F: FnMut(EngineOrModuleTypeIndex) -> Result<(), E>,
1689 {
1690 let Table {
1691 ref_type: wasm_ty,
1692 idx_type: _,
1693 limits: _,
1694 } = self;
1695 wasm_ty.trace(func)
1696 }
1697
1698 fn trace_mut<F, E>(&mut self, func: &mut F) -> Result<(), E>
1699 where
1700 F: FnMut(&mut EngineOrModuleTypeIndex) -> Result<(), E>,
1701 {
1702 let Table {
1703 ref_type: wasm_ty,
1704 idx_type: _,
1705 limits: _,
1706 } = self;
1707 wasm_ty.trace_mut(func)
1708 }
1709}
1710
1711#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1713pub struct Memory {
1714 pub idx_type: IndexType,
1716 pub limits: Limits,
1719 pub shared: bool,
1721 pub page_size_log2: u8,
1726}
1727
1728pub const WASM32_MAX_SIZE: u64 = 1 << 32;
1730
1731impl Memory {
1732 pub const DEFAULT_PAGE_SIZE: u32 = 0x10000;
1734
1735 pub const DEFAULT_PAGE_SIZE_LOG2: u8 = {
1737 let log2 = 16;
1738 assert!(1 << log2 == Memory::DEFAULT_PAGE_SIZE);
1739 log2
1740 };
1741
1742 pub fn minimum_byte_size(&self) -> Result<u64, SizeOverflow> {
1750 self.limits
1751 .min
1752 .checked_mul(self.page_size())
1753 .ok_or(SizeOverflow)
1754 }
1755
1756 pub fn maximum_byte_size(&self) -> Result<u64, SizeOverflow> {
1771 match self.limits.max {
1772 Some(max) => max.checked_mul(self.page_size()).ok_or(SizeOverflow),
1773 None => {
1774 let min = self.minimum_byte_size()?;
1775 Ok(min.max(self.max_size_based_on_index_type()))
1776 }
1777 }
1778 }
1779
1780 pub fn page_size(&self) -> u64 {
1782 debug_assert!(
1783 self.page_size_log2 == 16 || self.page_size_log2 == 0,
1784 "invalid page_size_log2: {}; must be 16 or 0",
1785 self.page_size_log2
1786 );
1787 1 << self.page_size_log2
1788 }
1789
1790 pub fn max_size_based_on_index_type(&self) -> u64 {
1795 match self.idx_type {
1796 IndexType::I64 =>
1797 {
1805 0_u64.wrapping_sub(self.page_size())
1806 }
1807 IndexType::I32 => WASM32_MAX_SIZE,
1808 }
1809 }
1810
1811 pub fn can_use_virtual_memory(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
1823 tunables.signals_based_traps && self.page_size_log2 >= host_page_size_log2
1824 }
1825
1826 pub fn can_elide_bounds_check(&self, tunables: &Tunables, host_page_size_log2: u8) -> bool {
1846 self.can_use_virtual_memory(tunables, host_page_size_log2)
1847 && self.idx_type == IndexType::I32
1848 && tunables.memory_reservation >= (1 << 32)
1849 }
1850
1851 pub fn static_heap_size(&self) -> Option<u64> {
1855 let min = self.minimum_byte_size().ok()?;
1856 let max = self.maximum_byte_size().ok()?;
1857 if min == max {
1858 Some(min)
1859 } else {
1860 None
1861 }
1862 }
1863
1864 pub fn memory_may_move(&self, tunables: &Tunables) -> bool {
1871 if self.shared {
1875 return false;
1876 }
1877
1878 if !tunables.memory_may_move {
1881 return false;
1882 }
1883
1884 let max = self.maximum_byte_size().unwrap_or(u64::MAX);
1887 max > tunables.memory_reservation
1888 }
1889}
1890
1891#[derive(Copy, Clone, Debug)]
1892#[allow(missing_docs, reason = "self-describing error struct")]
1893pub struct SizeOverflow;
1894
1895impl fmt::Display for SizeOverflow {
1896 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1897 f.write_str("size overflow calculating memory size")
1898 }
1899}
1900
1901impl core::error::Error for SizeOverflow {}
1902
1903impl From<wasmparser::MemoryType> for Memory {
1904 fn from(ty: wasmparser::MemoryType) -> Memory {
1905 let idx_type = match ty.memory64 {
1906 false => IndexType::I32,
1907 true => IndexType::I64,
1908 };
1909 let limits = Limits {
1910 min: ty.initial,
1911 max: ty.maximum,
1912 };
1913 let page_size_log2 = u8::try_from(ty.page_size_log2.unwrap_or(16)).unwrap();
1914 debug_assert!(
1915 page_size_log2 == 16 || page_size_log2 == 0,
1916 "invalid page_size_log2: {page_size_log2}; must be 16 or 0"
1917 );
1918 Memory {
1919 idx_type,
1920 limits,
1921 shared: ty.shared,
1922 page_size_log2,
1923 }
1924 }
1925}
1926
1927#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
1929pub struct Tag {
1930 pub ty: TypeIndex,
1932}
1933
1934impl From<wasmparser::TagType> for Tag {
1935 fn from(ty: wasmparser::TagType) -> Tag {
1936 match ty.kind {
1937 wasmparser::TagKind::Exception => Tag {
1938 ty: TypeIndex::from_u32(ty.func_type_idx),
1939 },
1940 }
1941 }
1942}
1943
1944#[allow(missing_docs, reason = "self-describing functions")]
1946pub trait TypeConvert {
1947 fn convert_global_type(&self, ty: &wasmparser::GlobalType) -> Global {
1949 Global {
1950 wasm_ty: self.convert_valtype(ty.content_type),
1951 mutability: ty.mutable,
1952 }
1953 }
1954
1955 fn convert_table_type(&self, ty: &wasmparser::TableType) -> WasmResult<Table> {
1957 let idx_type = match ty.table64 {
1958 false => IndexType::I32,
1959 true => IndexType::I64,
1960 };
1961 let limits = Limits {
1962 min: ty.initial.try_into().unwrap(),
1963 max: ty.maximum.map(|i| i.try_into().unwrap()),
1964 };
1965 Ok(Table {
1966 idx_type,
1967 limits,
1968 ref_type: self.convert_ref_type(ty.element_type),
1969 })
1970 }
1971
1972 fn convert_sub_type(&self, ty: &wasmparser::SubType) -> WasmSubType {
1973 WasmSubType {
1974 is_final: ty.is_final,
1975 supertype: ty.supertype_idx.map(|i| self.lookup_type_index(i.unpack())),
1976 composite_type: self.convert_composite_type(&ty.composite_type),
1977 }
1978 }
1979
1980 fn convert_composite_type(&self, ty: &wasmparser::CompositeType) -> WasmCompositeType {
1981 let inner = match &ty.inner {
1982 wasmparser::CompositeInnerType::Func(f) => {
1983 WasmCompositeInnerType::Func(self.convert_func_type(f))
1984 }
1985 wasmparser::CompositeInnerType::Array(a) => {
1986 WasmCompositeInnerType::Array(self.convert_array_type(a))
1987 }
1988 wasmparser::CompositeInnerType::Struct(s) => {
1989 WasmCompositeInnerType::Struct(self.convert_struct_type(s))
1990 }
1991 wasmparser::CompositeInnerType::Cont(_) => {
1992 unimplemented!("continuation types")
1993 }
1994 };
1995 WasmCompositeType {
1996 inner,
1997 shared: ty.shared,
1998 }
1999 }
2000
2001 fn convert_struct_type(&self, ty: &wasmparser::StructType) -> WasmStructType {
2002 WasmStructType {
2003 fields: ty
2004 .fields
2005 .iter()
2006 .map(|f| self.convert_field_type(f))
2007 .collect(),
2008 }
2009 }
2010
2011 fn convert_array_type(&self, ty: &wasmparser::ArrayType) -> WasmArrayType {
2012 WasmArrayType(self.convert_field_type(&ty.0))
2013 }
2014
2015 fn convert_field_type(&self, ty: &wasmparser::FieldType) -> WasmFieldType {
2016 WasmFieldType {
2017 element_type: self.convert_storage_type(&ty.element_type),
2018 mutable: ty.mutable,
2019 }
2020 }
2021
2022 fn convert_storage_type(&self, ty: &wasmparser::StorageType) -> WasmStorageType {
2023 match ty {
2024 wasmparser::StorageType::I8 => WasmStorageType::I8,
2025 wasmparser::StorageType::I16 => WasmStorageType::I16,
2026 wasmparser::StorageType::Val(v) => WasmStorageType::Val(self.convert_valtype(*v)),
2027 }
2028 }
2029
2030 fn convert_func_type(&self, ty: &wasmparser::FuncType) -> WasmFuncType {
2032 let params = ty
2033 .params()
2034 .iter()
2035 .map(|t| self.convert_valtype(*t))
2036 .collect();
2037 let results = ty
2038 .results()
2039 .iter()
2040 .map(|t| self.convert_valtype(*t))
2041 .collect();
2042 WasmFuncType::new(params, results)
2043 }
2044
2045 fn convert_valtype(&self, ty: wasmparser::ValType) -> WasmValType {
2047 match ty {
2048 wasmparser::ValType::I32 => WasmValType::I32,
2049 wasmparser::ValType::I64 => WasmValType::I64,
2050 wasmparser::ValType::F32 => WasmValType::F32,
2051 wasmparser::ValType::F64 => WasmValType::F64,
2052 wasmparser::ValType::V128 => WasmValType::V128,
2053 wasmparser::ValType::Ref(t) => WasmValType::Ref(self.convert_ref_type(t)),
2054 }
2055 }
2056
2057 fn convert_ref_type(&self, ty: wasmparser::RefType) -> WasmRefType {
2059 WasmRefType {
2060 nullable: ty.is_nullable(),
2061 heap_type: self.convert_heap_type(ty.heap_type()),
2062 }
2063 }
2064
2065 fn convert_heap_type(&self, ty: wasmparser::HeapType) -> WasmHeapType {
2067 match ty {
2068 wasmparser::HeapType::Concrete(i) => self.lookup_heap_type(i),
2069 wasmparser::HeapType::Abstract { ty, shared: false } => match ty {
2070 wasmparser::AbstractHeapType::Extern => WasmHeapType::Extern,
2071 wasmparser::AbstractHeapType::NoExtern => WasmHeapType::NoExtern,
2072 wasmparser::AbstractHeapType::Func => WasmHeapType::Func,
2073 wasmparser::AbstractHeapType::NoFunc => WasmHeapType::NoFunc,
2074 wasmparser::AbstractHeapType::Any => WasmHeapType::Any,
2075 wasmparser::AbstractHeapType::Eq => WasmHeapType::Eq,
2076 wasmparser::AbstractHeapType::I31 => WasmHeapType::I31,
2077 wasmparser::AbstractHeapType::Array => WasmHeapType::Array,
2078 wasmparser::AbstractHeapType::Struct => WasmHeapType::Struct,
2079 wasmparser::AbstractHeapType::None => WasmHeapType::None,
2080
2081 wasmparser::AbstractHeapType::Exn
2082 | wasmparser::AbstractHeapType::NoExn
2083 | wasmparser::AbstractHeapType::Cont
2084 | wasmparser::AbstractHeapType::NoCont => {
2085 unimplemented!("unsupported heap type {ty:?}");
2086 }
2087 },
2088 _ => unimplemented!("unsupported heap type {ty:?}"),
2089 }
2090 }
2091
2092 fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType;
2095
2096 fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex;
2099}