1use crate::store::{AutoAssertNoGc, StoreOpaque};
2use crate::{
3 AnyRef, ArrayRef, AsContext, AsContextMut, ExnRef, ExternRef, Func, HeapType, RefType, Rooted,
4 StructRef, V128, ValType, prelude::*,
5};
6use core::ptr;
7use wasmtime_environ::WasmHeapTopType;
8
9pub use crate::runtime::vm::ValRaw;
10
11#[derive(Debug, Clone, Copy)]
17pub enum Val {
18 I32(i32),
23
24 I64(i64),
26
27 F32(u32),
32
33 F64(u64),
38
39 V128(V128),
41
42 FuncRef(Option<Func>),
44
45 ExternRef(Option<Rooted<ExternRef>>),
47
48 AnyRef(Option<Rooted<AnyRef>>),
50
51 ExnRef(Option<Rooted<ExnRef>>),
53}
54
55macro_rules! accessors {
56 ($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($(
57 #[inline]
60 pub fn $get(&self) -> Option<$ty> {
61 if let Val::$variant($bind) = self {
62 Some($cvt)
63 } else {
64 None
65 }
66 }
67
68 #[inline]
75 pub fn $unwrap(&self) -> $ty {
76 self.$get().expect(concat!("expected ", stringify!($ty)))
77 }
78 )*)
79}
80
81impl Val {
82 #[inline]
84 pub fn null_ref(heap_type: &HeapType) -> Val {
85 Ref::null(&heap_type).into()
86 }
87
88 #[inline]
93 pub const fn null_func_ref() -> Val {
94 Val::FuncRef(None)
95 }
96
97 #[inline]
102 pub const fn null_extern_ref() -> Val {
103 Val::ExternRef(None)
104 }
105
106 #[inline]
111 pub const fn null_any_ref() -> Val {
112 Val::AnyRef(None)
113 }
114
115 pub(crate) const fn null_top(top: WasmHeapTopType) -> Val {
116 match top {
117 WasmHeapTopType::Func => Val::FuncRef(None),
118 WasmHeapTopType::Extern => Val::ExternRef(None),
119 WasmHeapTopType::Any => Val::AnyRef(None),
120 WasmHeapTopType::Exn => Val::ExnRef(None),
121 WasmHeapTopType::Cont => todo!(), }
123 }
124
125 pub fn default_for_ty(ty: &ValType) -> Option<Val> {
130 match ty {
131 ValType::I32 => Some(Val::I32(0)),
132 ValType::I64 => Some(Val::I64(0)),
133 ValType::F32 => Some(Val::F32(0)),
134 ValType::F64 => Some(Val::F64(0)),
135 ValType::V128 => Some(Val::V128(V128::from(0))),
136 ValType::Ref(ref_ty) => {
137 if ref_ty.is_nullable() {
138 Some(Val::null_ref(ref_ty.heap_type()))
139 } else {
140 None
141 }
142 }
143 }
144 }
145
146 #[inline]
157 pub fn ty(&self, store: impl AsContext) -> Result<ValType> {
158 self.load_ty(&store.as_context().0)
159 }
160
161 #[inline]
162 pub(crate) fn load_ty(&self, store: &StoreOpaque) -> Result<ValType> {
163 Ok(match self {
164 Val::I32(_) => ValType::I32,
165 Val::I64(_) => ValType::I64,
166 Val::F32(_) => ValType::F32,
167 Val::F64(_) => ValType::F64,
168 Val::V128(_) => ValType::V128,
169 Val::ExternRef(Some(_)) => ValType::EXTERNREF,
170 Val::ExternRef(None) => ValType::NULLFUNCREF,
171 Val::FuncRef(None) => ValType::NULLFUNCREF,
172 Val::FuncRef(Some(f)) => ValType::Ref(RefType::new(
173 false,
174 HeapType::ConcreteFunc(f.load_ty(store)),
175 )),
176 Val::AnyRef(None) => ValType::NULLREF,
177 Val::AnyRef(Some(a)) => ValType::Ref(RefType::new(false, a._ty(store)?)),
178 Val::ExnRef(None) => ValType::NULLEXNREF,
179 Val::ExnRef(Some(e)) => ValType::Ref(RefType::new(false, e._ty(store)?.into())),
180 })
181 }
182
183 pub fn matches_ty(&self, store: impl AsContext, ty: &ValType) -> Result<bool> {
191 self._matches_ty(&store.as_context().0, ty)
192 }
193
194 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &ValType) -> Result<bool> {
195 assert!(self.comes_from_same_store(store));
196 assert!(ty.comes_from_same_engine(store.engine()));
197 Ok(match (self, ty) {
198 (Val::I32(_), ValType::I32)
199 | (Val::I64(_), ValType::I64)
200 | (Val::F32(_), ValType::F32)
201 | (Val::F64(_), ValType::F64)
202 | (Val::V128(_), ValType::V128) => true,
203
204 (Val::FuncRef(f), ValType::Ref(ref_ty)) => Ref::from(*f)._matches_ty(store, ref_ty)?,
205 (Val::ExternRef(e), ValType::Ref(ref_ty)) => {
206 Ref::from(*e)._matches_ty(store, ref_ty)?
207 }
208 (Val::AnyRef(a), ValType::Ref(ref_ty)) => Ref::from(*a)._matches_ty(store, ref_ty)?,
209 (Val::ExnRef(e), ValType::Ref(ref_ty)) => Ref::from(*e)._matches_ty(store, ref_ty)?,
210
211 (Val::I32(_), _)
212 | (Val::I64(_), _)
213 | (Val::F32(_), _)
214 | (Val::F64(_), _)
215 | (Val::V128(_), _)
216 | (Val::FuncRef(_), _)
217 | (Val::ExternRef(_), _)
218 | (Val::AnyRef(_), _)
219 | (Val::ExnRef(_), _) => false,
220 })
221 }
222
223 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &ValType) -> Result<()> {
224 if !self.comes_from_same_store(store) {
225 bail!("value used with wrong store")
226 }
227 if !ty.comes_from_same_engine(store.engine()) {
228 bail!("type used with wrong engine")
229 }
230 if self._matches_ty(store, ty)? {
231 Ok(())
232 } else {
233 let actual_ty = self.load_ty(store)?;
234 bail!("type mismatch: expected {ty}, found {actual_ty}")
235 }
236 }
237
238 pub fn to_raw(&self, store: impl AsContextMut) -> Result<ValRaw> {
249 match self {
250 Val::I32(i) => Ok(ValRaw::i32(*i)),
251 Val::I64(i) => Ok(ValRaw::i64(*i)),
252 Val::F32(u) => Ok(ValRaw::f32(*u)),
253 Val::F64(u) => Ok(ValRaw::f64(*u)),
254 Val::V128(b) => Ok(ValRaw::v128(b.as_u128())),
255 Val::ExternRef(e) => Ok(ValRaw::externref(match e {
256 None => 0,
257 Some(e) => e.to_raw(store)?,
258 })),
259 Val::AnyRef(e) => Ok(ValRaw::anyref(match e {
260 None => 0,
261 Some(e) => e.to_raw(store)?,
262 })),
263 Val::ExnRef(e) => Ok(ValRaw::exnref(match e {
264 None => 0,
265 Some(e) => e.to_raw(store)?,
266 })),
267 Val::FuncRef(f) => Ok(ValRaw::funcref(match f {
268 Some(f) => f.to_raw(store),
269 None => ptr::null_mut(),
270 })),
271 }
272 }
273
274 pub unsafe fn from_raw(mut store: impl AsContextMut, raw: ValRaw, ty: ValType) -> Val {
282 let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
283 unsafe { Self::_from_raw(&mut store, raw, &ty) }
285 }
286
287 pub(crate) unsafe fn _from_raw(
289 store: &mut AutoAssertNoGc<'_>,
290 raw: ValRaw,
291 ty: &ValType,
292 ) -> Val {
293 match ty {
294 ValType::I32 => Val::I32(raw.get_i32()),
295 ValType::I64 => Val::I64(raw.get_i64()),
296 ValType::F32 => Val::F32(raw.get_f32()),
297 ValType::F64 => Val::F64(raw.get_f64()),
298 ValType::V128 => Val::V128(raw.get_v128().into()),
299 ValType::Ref(ref_ty) => {
300 let ref_ = match ref_ty.heap_type() {
301 HeapType::Func | HeapType::ConcreteFunc(_) => unsafe {
304 Func::_from_raw(store, raw.get_funcref()).into()
305 },
306
307 HeapType::NoFunc => Ref::Func(None),
308
309 HeapType::NoCont | HeapType::ConcreteCont(_) | HeapType::Cont => {
310 unimplemented!()
312 }
313
314 HeapType::Extern => ExternRef::_from_raw(store, raw.get_externref()).into(),
315
316 HeapType::NoExtern => Ref::Extern(None),
317
318 HeapType::Any
319 | HeapType::Eq
320 | HeapType::I31
321 | HeapType::Array
322 | HeapType::ConcreteArray(_)
323 | HeapType::Struct
324 | HeapType::ConcreteStruct(_) => {
325 AnyRef::_from_raw(store, raw.get_anyref()).into()
326 }
327
328 HeapType::Exn | HeapType::ConcreteExn(_) => {
329 ExnRef::_from_raw(store, raw.get_exnref()).into()
330 }
331 HeapType::NoExn => Ref::Exn(None),
332
333 HeapType::None => Ref::Any(None),
334 };
335 assert!(
336 ref_ty.is_nullable() || !ref_.is_null(),
337 "if the type is not nullable, we shouldn't get null; got \
338 type = {ref_ty}, ref = {ref_:?}"
339 );
340 ref_.into()
341 }
342 }
343 }
344
345 accessors! {
346 e
347 (I32(i32) i32 unwrap_i32 *e)
348 (I64(i64) i64 unwrap_i64 *e)
349 (F32(f32) f32 unwrap_f32 f32::from_bits(*e))
350 (F64(f64) f64 unwrap_f64 f64::from_bits(*e))
351 (FuncRef(Option<&Func>) func_ref unwrap_func_ref e.as_ref())
352 (ExternRef(Option<&Rooted<ExternRef>>) extern_ref unwrap_extern_ref e.as_ref())
353 (AnyRef(Option<&Rooted<AnyRef>>) any_ref unwrap_any_ref e.as_ref())
354 (V128(V128) v128 unwrap_v128 *e)
355 }
356
357 #[inline]
359 pub fn ref_(self) -> Option<Ref> {
360 match self {
361 Val::FuncRef(f) => Some(Ref::Func(f)),
362 Val::ExternRef(e) => Some(Ref::Extern(e)),
363 Val::AnyRef(a) => Some(Ref::Any(a)),
364 Val::ExnRef(e) => Some(Ref::Exn(e)),
365 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => None,
366 }
367 }
368
369 #[inline]
377 pub fn externref(&self) -> Option<Option<&Rooted<ExternRef>>> {
378 match self {
379 Val::ExternRef(None) => Some(None),
380 Val::ExternRef(Some(e)) => Some(Some(e)),
381 _ => None,
382 }
383 }
384
385 #[inline]
396 pub fn unwrap_externref(&self) -> Option<&Rooted<ExternRef>> {
397 self.externref().expect("expected externref")
398 }
399
400 #[inline]
408 pub fn anyref(&self) -> Option<Option<&Rooted<AnyRef>>> {
409 match self {
410 Val::AnyRef(None) => Some(None),
411 Val::AnyRef(Some(e)) => Some(Some(e)),
412 _ => None,
413 }
414 }
415
416 #[inline]
427 pub fn unwrap_anyref(&self) -> Option<&Rooted<AnyRef>> {
428 self.anyref().expect("expected anyref")
429 }
430
431 #[inline]
439 pub fn exnref(&self) -> Option<Option<&Rooted<ExnRef>>> {
440 match self {
441 Val::ExnRef(None) => Some(None),
442 Val::ExnRef(Some(e)) => Some(Some(e)),
443 _ => None,
444 }
445 }
446
447 #[inline]
458 pub fn unwrap_exnref(&self) -> Option<&Rooted<ExnRef>> {
459 self.exnref().expect("expected exnref")
460 }
461
462 #[inline]
470 pub fn funcref(&self) -> Option<Option<&Func>> {
471 match self {
472 Val::FuncRef(None) => Some(None),
473 Val::FuncRef(Some(f)) => Some(Some(f)),
474 _ => None,
475 }
476 }
477
478 #[inline]
489 pub fn unwrap_funcref(&self) -> Option<&Func> {
490 self.funcref().expect("expected funcref")
491 }
492
493 #[inline]
494 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
495 match self {
496 Val::FuncRef(Some(f)) => f.comes_from_same_store(store),
497 Val::FuncRef(None) => true,
498
499 Val::ExternRef(Some(x)) => x.comes_from_same_store(store),
500 Val::ExternRef(None) => true,
501
502 Val::AnyRef(Some(a)) => a.comes_from_same_store(store),
503 Val::AnyRef(None) => true,
504
505 Val::ExnRef(Some(e)) => e.comes_from_same_store(store),
506 Val::ExnRef(None) => true,
507
508 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true,
512 }
513 }
514}
515
516impl From<i32> for Val {
517 #[inline]
518 fn from(val: i32) -> Val {
519 Val::I32(val)
520 }
521}
522
523impl From<i64> for Val {
524 #[inline]
525 fn from(val: i64) -> Val {
526 Val::I64(val)
527 }
528}
529
530impl From<f32> for Val {
531 #[inline]
532 fn from(val: f32) -> Val {
533 Val::F32(val.to_bits())
534 }
535}
536
537impl From<f64> for Val {
538 #[inline]
539 fn from(val: f64) -> Val {
540 Val::F64(val.to_bits())
541 }
542}
543
544impl From<Ref> for Val {
545 #[inline]
546 fn from(val: Ref) -> Val {
547 match val {
548 Ref::Extern(e) => Val::ExternRef(e),
549 Ref::Func(f) => Val::FuncRef(f),
550 Ref::Any(a) => Val::AnyRef(a),
551 Ref::Exn(e) => Val::ExnRef(e),
552 }
553 }
554}
555
556impl From<Rooted<ExternRef>> for Val {
557 #[inline]
558 fn from(val: Rooted<ExternRef>) -> Val {
559 Val::ExternRef(Some(val))
560 }
561}
562
563impl From<Option<Rooted<ExternRef>>> for Val {
564 #[inline]
565 fn from(val: Option<Rooted<ExternRef>>) -> Val {
566 Val::ExternRef(val)
567 }
568}
569
570impl From<Rooted<AnyRef>> for Val {
571 #[inline]
572 fn from(val: Rooted<AnyRef>) -> Val {
573 Val::AnyRef(Some(val))
574 }
575}
576
577impl From<Option<Rooted<AnyRef>>> for Val {
578 #[inline]
579 fn from(val: Option<Rooted<AnyRef>>) -> Val {
580 Val::AnyRef(val)
581 }
582}
583
584impl From<Rooted<StructRef>> for Val {
585 #[inline]
586 fn from(val: Rooted<StructRef>) -> Val {
587 Val::AnyRef(Some(val.into()))
588 }
589}
590
591impl From<Option<Rooted<StructRef>>> for Val {
592 #[inline]
593 fn from(val: Option<Rooted<StructRef>>) -> Val {
594 Val::AnyRef(val.map(Into::into))
595 }
596}
597
598impl From<Rooted<ArrayRef>> for Val {
599 #[inline]
600 fn from(val: Rooted<ArrayRef>) -> Val {
601 Val::AnyRef(Some(val.into()))
602 }
603}
604
605impl From<Option<Rooted<ArrayRef>>> for Val {
606 #[inline]
607 fn from(val: Option<Rooted<ArrayRef>>) -> Val {
608 Val::AnyRef(val.map(Into::into))
609 }
610}
611
612impl From<Rooted<ExnRef>> for Val {
613 #[inline]
614 fn from(val: Rooted<ExnRef>) -> Val {
615 Val::ExnRef(Some(val))
616 }
617}
618
619impl From<Option<Rooted<ExnRef>>> for Val {
620 #[inline]
621 fn from(val: Option<Rooted<ExnRef>>) -> Val {
622 Val::ExnRef(val)
623 }
624}
625
626impl From<Func> for Val {
627 #[inline]
628 fn from(val: Func) -> Val {
629 Val::FuncRef(Some(val))
630 }
631}
632
633impl From<Option<Func>> for Val {
634 #[inline]
635 fn from(val: Option<Func>) -> Val {
636 Val::FuncRef(val)
637 }
638}
639
640impl From<u128> for Val {
641 #[inline]
642 fn from(val: u128) -> Val {
643 Val::V128(val.into())
644 }
645}
646
647impl From<V128> for Val {
648 #[inline]
649 fn from(val: V128) -> Val {
650 Val::V128(val)
651 }
652}
653
654#[derive(Debug, Clone)]
679pub enum Ref {
680 Func(Option<Func>),
717
718 Extern(Option<Rooted<ExternRef>>),
728
729 Any(Option<Rooted<AnyRef>>),
738
739 Exn(Option<Rooted<ExnRef>>),
746}
747
748impl From<Func> for Ref {
749 #[inline]
750 fn from(f: Func) -> Ref {
751 Ref::Func(Some(f))
752 }
753}
754
755impl From<Option<Func>> for Ref {
756 #[inline]
757 fn from(f: Option<Func>) -> Ref {
758 Ref::Func(f)
759 }
760}
761
762impl From<Rooted<ExternRef>> for Ref {
763 #[inline]
764 fn from(e: Rooted<ExternRef>) -> Ref {
765 Ref::Extern(Some(e))
766 }
767}
768
769impl From<Option<Rooted<ExternRef>>> for Ref {
770 #[inline]
771 fn from(e: Option<Rooted<ExternRef>>) -> Ref {
772 Ref::Extern(e)
773 }
774}
775
776impl From<Rooted<AnyRef>> for Ref {
777 #[inline]
778 fn from(e: Rooted<AnyRef>) -> Ref {
779 Ref::Any(Some(e))
780 }
781}
782
783impl From<Option<Rooted<AnyRef>>> for Ref {
784 #[inline]
785 fn from(e: Option<Rooted<AnyRef>>) -> Ref {
786 Ref::Any(e)
787 }
788}
789
790impl From<Rooted<StructRef>> for Ref {
791 #[inline]
792 fn from(e: Rooted<StructRef>) -> Ref {
793 Ref::Any(Some(e.into()))
794 }
795}
796
797impl From<Option<Rooted<StructRef>>> for Ref {
798 #[inline]
799 fn from(e: Option<Rooted<StructRef>>) -> Ref {
800 Ref::Any(e.map(Into::into))
801 }
802}
803
804impl From<Rooted<ArrayRef>> for Ref {
805 #[inline]
806 fn from(e: Rooted<ArrayRef>) -> Ref {
807 Ref::Any(Some(e.into()))
808 }
809}
810
811impl From<Option<Rooted<ArrayRef>>> for Ref {
812 #[inline]
813 fn from(e: Option<Rooted<ArrayRef>>) -> Ref {
814 Ref::Any(e.map(Into::into))
815 }
816}
817
818impl From<Rooted<ExnRef>> for Ref {
819 #[inline]
820 fn from(e: Rooted<ExnRef>) -> Ref {
821 Ref::Exn(Some(e))
822 }
823}
824
825impl From<Option<Rooted<ExnRef>>> for Ref {
826 #[inline]
827 fn from(e: Option<Rooted<ExnRef>>) -> Ref {
828 Ref::Exn(e)
829 }
830}
831
832impl Ref {
833 #[inline]
835 pub fn null(heap_type: &HeapType) -> Self {
836 match heap_type.top() {
837 HeapType::Any => Ref::Any(None),
838 HeapType::Extern => Ref::Extern(None),
839 HeapType::Func => Ref::Func(None),
840 ty => unreachable!("not a heap type: {ty:?}"),
841 }
842 }
843
844 #[inline]
846 pub fn is_null(&self) -> bool {
847 match self {
848 Ref::Any(None) | Ref::Extern(None) | Ref::Func(None) | Ref::Exn(None) => true,
849 Ref::Any(Some(_)) | Ref::Extern(Some(_)) | Ref::Func(Some(_)) | Ref::Exn(Some(_)) => {
850 false
851 }
852 }
853 }
854
855 #[inline]
857 pub fn is_non_null(&self) -> bool {
858 !self.is_null()
859 }
860
861 #[inline]
863 pub fn is_extern(&self) -> bool {
864 matches!(self, Ref::Extern(_))
865 }
866
867 #[inline]
876 pub fn as_extern(&self) -> Option<Option<&Rooted<ExternRef>>> {
877 match self {
878 Ref::Extern(e) => Some(e.as_ref()),
879 _ => None,
880 }
881 }
882
883 #[inline]
890 pub fn unwrap_extern(&self) -> Option<&Rooted<ExternRef>> {
891 self.as_extern()
892 .expect("Ref::unwrap_extern on non-extern reference")
893 }
894
895 #[inline]
897 pub fn is_any(&self) -> bool {
898 matches!(self, Ref::Any(_))
899 }
900
901 #[inline]
910 pub fn as_any(&self) -> Option<Option<&Rooted<AnyRef>>> {
911 match self {
912 Ref::Any(e) => Some(e.as_ref()),
913 _ => None,
914 }
915 }
916
917 #[inline]
924 pub fn unwrap_any(&self) -> Option<&Rooted<AnyRef>> {
925 self.as_any().expect("Ref::unwrap_any on non-any reference")
926 }
927
928 #[inline]
930 pub fn is_exn(&self) -> bool {
931 matches!(self, Ref::Exn(_))
932 }
933
934 #[inline]
943 pub fn as_exn(&self) -> Option<Option<&Rooted<ExnRef>>> {
944 match self {
945 Ref::Exn(e) => Some(e.as_ref()),
946 _ => None,
947 }
948 }
949
950 #[inline]
957 pub fn unwrap_exn(&self) -> Option<&Rooted<ExnRef>> {
958 self.as_exn().expect("Ref::unwrap_exn on non-exn reference")
959 }
960
961 #[inline]
963 pub fn is_func(&self) -> bool {
964 matches!(self, Ref::Func(_))
965 }
966
967 #[inline]
976 pub fn as_func(&self) -> Option<Option<&Func>> {
977 match self {
978 Ref::Func(f) => Some(f.as_ref()),
979 _ => None,
980 }
981 }
982
983 #[inline]
990 pub fn unwrap_func(&self) -> Option<&Func> {
991 self.as_func()
992 .expect("Ref::unwrap_func on non-func reference")
993 }
994
995 pub fn ty(&self, store: impl AsContext) -> Result<RefType> {
1005 self.load_ty(&store.as_context().0)
1006 }
1007
1008 pub(crate) fn load_ty(&self, store: &StoreOpaque) -> Result<RefType> {
1009 assert!(self.comes_from_same_store(store));
1010 Ok(RefType::new(
1011 self.is_null(),
1012 match self {
1016 Ref::Extern(None) => HeapType::NoExtern,
1017 Ref::Extern(Some(_)) => HeapType::Extern,
1018
1019 Ref::Func(None) => HeapType::NoFunc,
1020 Ref::Func(Some(f)) => HeapType::ConcreteFunc(f.load_ty(store)),
1021
1022 Ref::Any(None) => HeapType::None,
1023 Ref::Any(Some(a)) => a._ty(store)?,
1024
1025 Ref::Exn(None) => HeapType::None,
1026 Ref::Exn(Some(e)) => e._ty(store)?.into(),
1027 },
1028 ))
1029 }
1030
1031 pub fn matches_ty(&self, store: impl AsContext, ty: &RefType) -> Result<bool> {
1039 self._matches_ty(&store.as_context().0, ty)
1040 }
1041
1042 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<bool> {
1043 assert!(self.comes_from_same_store(store));
1044 assert!(ty.comes_from_same_engine(store.engine()));
1045 if self.is_null() && !ty.is_nullable() {
1046 return Ok(false);
1047 }
1048 Ok(match (self, ty.heap_type()) {
1049 (Ref::Extern(_), HeapType::Extern) => true,
1050 (Ref::Extern(None), HeapType::NoExtern) => true,
1051 (Ref::Extern(_), _) => false,
1052
1053 (Ref::Func(_), HeapType::Func) => true,
1054 (Ref::Func(None), HeapType::NoFunc | HeapType::ConcreteFunc(_)) => true,
1055 (Ref::Func(Some(f)), HeapType::ConcreteFunc(func_ty)) => f._matches_ty(store, func_ty),
1056 (Ref::Func(_), _) => false,
1057
1058 (Ref::Any(_), HeapType::Any) => true,
1059 (Ref::Any(Some(a)), HeapType::I31) => a._is_i31(store)?,
1060 (Ref::Any(Some(a)), HeapType::Struct) => a._is_struct(store)?,
1061 (Ref::Any(Some(a)), HeapType::ConcreteStruct(_ty)) => match a._as_struct(store)? {
1062 None => false,
1063 Some(s) => s._matches_ty(store, _ty)?,
1064 },
1065 (Ref::Any(Some(a)), HeapType::Eq) => a._is_eqref(store)?,
1066 (Ref::Any(Some(a)), HeapType::Array) => a._is_array(store)?,
1067 (Ref::Any(Some(a)), HeapType::ConcreteArray(_ty)) => match a._as_array(store)? {
1068 None => false,
1069 Some(a) => a._matches_ty(store, _ty)?,
1070 },
1071 (
1072 Ref::Any(None),
1073 HeapType::None
1074 | HeapType::I31
1075 | HeapType::ConcreteStruct(_)
1076 | HeapType::Struct
1077 | HeapType::ConcreteArray(_)
1078 | HeapType::Array
1079 | HeapType::Eq,
1080 ) => true,
1081 (Ref::Any(_), _) => false,
1082
1083 (Ref::Exn(_), HeapType::Exn) => true,
1084 (Ref::Exn(None), HeapType::NoExn | HeapType::ConcreteExn(_)) => true,
1085 (Ref::Exn(Some(e)), HeapType::ConcreteExn(_)) => {
1086 e._matches_ty(store, &ty.heap_type())?
1087 }
1088 (Ref::Exn(_), _) => false,
1089 })
1090 }
1091
1092 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<()> {
1093 if !self.comes_from_same_store(store) {
1094 bail!("reference used with wrong store")
1095 }
1096 if !ty.comes_from_same_engine(store.engine()) {
1097 bail!("type used with wrong engine")
1098 }
1099 if self._matches_ty(store, ty)? {
1100 Ok(())
1101 } else {
1102 let actual_ty = self.load_ty(store)?;
1103 bail!("type mismatch: expected {ty}, found {actual_ty}")
1104 }
1105 }
1106
1107 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
1108 match self {
1109 Ref::Func(Some(f)) => f.comes_from_same_store(store),
1110 Ref::Func(None) => true,
1111 Ref::Extern(Some(x)) => x.comes_from_same_store(store),
1112 Ref::Extern(None) => true,
1113 Ref::Any(Some(a)) => a.comes_from_same_store(store),
1114 Ref::Any(None) => true,
1115 Ref::Exn(Some(e)) => e.comes_from_same_store(store),
1116 Ref::Exn(None) => true,
1117 }
1118 }
1119}
1120
1121#[cfg(test)]
1122mod tests {
1123 use crate::*;
1124
1125 #[test]
1126 fn size_of_val() {
1127 let expected = if cfg!(target_arch = "x86_64")
1130 || cfg!(target_arch = "aarch64")
1131 || cfg!(target_arch = "s390x")
1132 || cfg!(target_arch = "riscv64")
1133 || cfg!(target_arch = "arm")
1134 {
1135 24
1136 } else if cfg!(target_arch = "x86") {
1137 20
1138 } else {
1139 panic!("unsupported architecture")
1140 };
1141 assert_eq!(std::mem::size_of::<Val>(), expected);
1142 }
1143
1144 #[test]
1145 fn size_of_ref() {
1146 let expected = if cfg!(target_arch = "x86_64")
1149 || cfg!(target_arch = "aarch64")
1150 || cfg!(target_arch = "s390x")
1151 || cfg!(target_arch = "riscv64")
1152 || cfg!(target_arch = "arm")
1153 {
1154 24
1155 } else if cfg!(target_arch = "x86") {
1156 20
1157 } else {
1158 panic!("unsupported architecture")
1159 };
1160 assert_eq!(std::mem::size_of::<Ref>(), expected);
1161 }
1162
1163 #[test]
1164 #[should_panic]
1165 fn val_matches_ty_wrong_engine() {
1166 let e1 = Engine::default();
1167 let e2 = Engine::default();
1168
1169 let t1 = FuncType::new(&e1, None, None);
1170 let t2 = FuncType::new(&e2, None, None);
1171
1172 let mut s1 = Store::new(&e1, ());
1173 let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1174
1175 let _ = Val::FuncRef(Some(f)).matches_ty(
1177 &s1,
1178 &ValType::Ref(RefType::new(true, HeapType::ConcreteFunc(t2))),
1179 );
1180 }
1181
1182 #[test]
1183 #[should_panic]
1184 fn ref_matches_ty_wrong_engine() {
1185 let e1 = Engine::default();
1186 let e2 = Engine::default();
1187
1188 let t1 = FuncType::new(&e1, None, None);
1189 let t2 = FuncType::new(&e2, None, None);
1190
1191 let mut s1 = Store::new(&e1, ());
1192 let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1193
1194 let _ = Ref::Func(Some(f)).matches_ty(&s1, &RefType::new(true, HeapType::ConcreteFunc(t2)));
1196 }
1197}