1use crate::runtime::vm::TableElement;
2use crate::store::{AutoAssertNoGc, StoreOpaque};
3use crate::{
4 AnyRef, ArrayRef, AsContext, AsContextMut, ExnRef, ExternRef, Func, HeapType, RefType, Rooted,
5 RootedGcRefImpl, StructRef, V128, ValType, prelude::*,
6};
7use core::ptr;
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 fn default_for_ty(ty: &ValType) -> Option<Val> {
120 match ty {
121 ValType::I32 => Some(Val::I32(0)),
122 ValType::I64 => Some(Val::I64(0)),
123 ValType::F32 => Some(Val::F32(0)),
124 ValType::F64 => Some(Val::F64(0)),
125 ValType::V128 => Some(Val::V128(V128::from(0))),
126 ValType::Ref(ref_ty) => {
127 if ref_ty.is_nullable() {
128 Some(Val::null_ref(ref_ty.heap_type()))
129 } else {
130 None
131 }
132 }
133 }
134 }
135
136 #[inline]
147 pub fn ty(&self, store: impl AsContext) -> Result<ValType> {
148 self.load_ty(&store.as_context().0)
149 }
150
151 #[inline]
152 pub(crate) fn load_ty(&self, store: &StoreOpaque) -> Result<ValType> {
153 Ok(match self {
154 Val::I32(_) => ValType::I32,
155 Val::I64(_) => ValType::I64,
156 Val::F32(_) => ValType::F32,
157 Val::F64(_) => ValType::F64,
158 Val::V128(_) => ValType::V128,
159 Val::ExternRef(Some(_)) => ValType::EXTERNREF,
160 Val::ExternRef(None) => ValType::NULLFUNCREF,
161 Val::FuncRef(None) => ValType::NULLFUNCREF,
162 Val::FuncRef(Some(f)) => ValType::Ref(RefType::new(
163 false,
164 HeapType::ConcreteFunc(f.load_ty(store)),
165 )),
166 Val::AnyRef(None) => ValType::NULLREF,
167 Val::AnyRef(Some(a)) => ValType::Ref(RefType::new(false, a._ty(store)?)),
168 Val::ExnRef(None) => ValType::NULLEXNREF,
169 Val::ExnRef(Some(e)) => ValType::Ref(RefType::new(false, e._ty(store)?.into())),
170 })
171 }
172
173 pub fn matches_ty(&self, store: impl AsContext, ty: &ValType) -> Result<bool> {
181 self._matches_ty(&store.as_context().0, ty)
182 }
183
184 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &ValType) -> Result<bool> {
185 assert!(self.comes_from_same_store(store));
186 assert!(ty.comes_from_same_engine(store.engine()));
187 Ok(match (self, ty) {
188 (Val::I32(_), ValType::I32)
189 | (Val::I64(_), ValType::I64)
190 | (Val::F32(_), ValType::F32)
191 | (Val::F64(_), ValType::F64)
192 | (Val::V128(_), ValType::V128) => true,
193
194 (Val::FuncRef(f), ValType::Ref(ref_ty)) => Ref::from(*f)._matches_ty(store, ref_ty)?,
195 (Val::ExternRef(e), ValType::Ref(ref_ty)) => {
196 Ref::from(*e)._matches_ty(store, ref_ty)?
197 }
198 (Val::AnyRef(a), ValType::Ref(ref_ty)) => Ref::from(*a)._matches_ty(store, ref_ty)?,
199 (Val::ExnRef(e), ValType::Ref(ref_ty)) => Ref::from(*e)._matches_ty(store, ref_ty)?,
200
201 (Val::I32(_), _)
202 | (Val::I64(_), _)
203 | (Val::F32(_), _)
204 | (Val::F64(_), _)
205 | (Val::V128(_), _)
206 | (Val::FuncRef(_), _)
207 | (Val::ExternRef(_), _)
208 | (Val::AnyRef(_), _)
209 | (Val::ExnRef(_), _) => false,
210 })
211 }
212
213 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &ValType) -> Result<()> {
214 if !self.comes_from_same_store(store) {
215 bail!("value used with wrong store")
216 }
217 if !ty.comes_from_same_engine(store.engine()) {
218 bail!("type used with wrong engine")
219 }
220 if self._matches_ty(store, ty)? {
221 Ok(())
222 } else {
223 let actual_ty = self.load_ty(store)?;
224 bail!("type mismatch: expected {ty}, found {actual_ty}")
225 }
226 }
227
228 pub fn to_raw(&self, store: impl AsContextMut) -> Result<ValRaw> {
239 match self {
240 Val::I32(i) => Ok(ValRaw::i32(*i)),
241 Val::I64(i) => Ok(ValRaw::i64(*i)),
242 Val::F32(u) => Ok(ValRaw::f32(*u)),
243 Val::F64(u) => Ok(ValRaw::f64(*u)),
244 Val::V128(b) => Ok(ValRaw::v128(b.as_u128())),
245 Val::ExternRef(e) => Ok(ValRaw::externref(match e {
246 None => 0,
247 Some(e) => e.to_raw(store)?,
248 })),
249 Val::AnyRef(e) => Ok(ValRaw::anyref(match e {
250 None => 0,
251 Some(e) => e.to_raw(store)?,
252 })),
253 Val::ExnRef(e) => Ok(ValRaw::exnref(match e {
254 None => 0,
255 Some(e) => e.to_raw(store)?,
256 })),
257 Val::FuncRef(f) => Ok(ValRaw::funcref(match f {
258 Some(f) => f.to_raw(store),
259 None => ptr::null_mut(),
260 })),
261 }
262 }
263
264 pub unsafe fn from_raw(mut store: impl AsContextMut, raw: ValRaw, ty: ValType) -> Val {
272 let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
273 unsafe { Self::_from_raw(&mut store, raw, &ty) }
275 }
276
277 pub(crate) unsafe fn _from_raw(
279 store: &mut AutoAssertNoGc<'_>,
280 raw: ValRaw,
281 ty: &ValType,
282 ) -> Val {
283 match ty {
284 ValType::I32 => Val::I32(raw.get_i32()),
285 ValType::I64 => Val::I64(raw.get_i64()),
286 ValType::F32 => Val::F32(raw.get_f32()),
287 ValType::F64 => Val::F64(raw.get_f64()),
288 ValType::V128 => Val::V128(raw.get_v128().into()),
289 ValType::Ref(ref_ty) => {
290 let ref_ = match ref_ty.heap_type() {
291 HeapType::Func | HeapType::ConcreteFunc(_) => unsafe {
294 Func::_from_raw(store, raw.get_funcref()).into()
295 },
296
297 HeapType::NoFunc => Ref::Func(None),
298
299 HeapType::NoCont | HeapType::ConcreteCont(_) | HeapType::Cont => {
300 unimplemented!()
302 }
303
304 HeapType::Extern => ExternRef::_from_raw(store, raw.get_externref()).into(),
305
306 HeapType::NoExtern => Ref::Extern(None),
307
308 HeapType::Any
309 | HeapType::Eq
310 | HeapType::I31
311 | HeapType::Array
312 | HeapType::ConcreteArray(_)
313 | HeapType::Struct
314 | HeapType::ConcreteStruct(_) => {
315 AnyRef::_from_raw(store, raw.get_anyref()).into()
316 }
317
318 HeapType::Exn | HeapType::ConcreteExn(_) => {
319 ExnRef::_from_raw(store, raw.get_exnref()).into()
320 }
321 HeapType::NoExn => Ref::Exn(None),
322
323 HeapType::None => Ref::Any(None),
324 };
325 assert!(
326 ref_ty.is_nullable() || !ref_.is_null(),
327 "if the type is not nullable, we shouldn't get null; got \
328 type = {ref_ty}, ref = {ref_:?}"
329 );
330 ref_.into()
331 }
332 }
333 }
334
335 accessors! {
336 e
337 (I32(i32) i32 unwrap_i32 *e)
338 (I64(i64) i64 unwrap_i64 *e)
339 (F32(f32) f32 unwrap_f32 f32::from_bits(*e))
340 (F64(f64) f64 unwrap_f64 f64::from_bits(*e))
341 (FuncRef(Option<&Func>) func_ref unwrap_func_ref e.as_ref())
342 (ExternRef(Option<&Rooted<ExternRef>>) extern_ref unwrap_extern_ref e.as_ref())
343 (AnyRef(Option<&Rooted<AnyRef>>) any_ref unwrap_any_ref e.as_ref())
344 (V128(V128) v128 unwrap_v128 *e)
345 }
346
347 #[inline]
349 pub fn ref_(self) -> Option<Ref> {
350 match self {
351 Val::FuncRef(f) => Some(Ref::Func(f)),
352 Val::ExternRef(e) => Some(Ref::Extern(e)),
353 Val::AnyRef(a) => Some(Ref::Any(a)),
354 Val::ExnRef(e) => Some(Ref::Exn(e)),
355 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => None,
356 }
357 }
358
359 #[inline]
367 pub fn externref(&self) -> Option<Option<&Rooted<ExternRef>>> {
368 match self {
369 Val::ExternRef(None) => Some(None),
370 Val::ExternRef(Some(e)) => Some(Some(e)),
371 _ => None,
372 }
373 }
374
375 #[inline]
386 pub fn unwrap_externref(&self) -> Option<&Rooted<ExternRef>> {
387 self.externref().expect("expected externref")
388 }
389
390 #[inline]
398 pub fn anyref(&self) -> Option<Option<&Rooted<AnyRef>>> {
399 match self {
400 Val::AnyRef(None) => Some(None),
401 Val::AnyRef(Some(e)) => Some(Some(e)),
402 _ => None,
403 }
404 }
405
406 #[inline]
417 pub fn unwrap_anyref(&self) -> Option<&Rooted<AnyRef>> {
418 self.anyref().expect("expected anyref")
419 }
420
421 #[inline]
429 pub fn exnref(&self) -> Option<Option<&Rooted<ExnRef>>> {
430 match self {
431 Val::ExnRef(None) => Some(None),
432 Val::ExnRef(Some(e)) => Some(Some(e)),
433 _ => None,
434 }
435 }
436
437 #[inline]
448 pub fn unwrap_exnref(&self) -> Option<&Rooted<ExnRef>> {
449 self.exnref().expect("expected exnref")
450 }
451
452 #[inline]
460 pub fn funcref(&self) -> Option<Option<&Func>> {
461 match self {
462 Val::FuncRef(None) => Some(None),
463 Val::FuncRef(Some(f)) => Some(Some(f)),
464 _ => None,
465 }
466 }
467
468 #[inline]
479 pub fn unwrap_funcref(&self) -> Option<&Func> {
480 self.funcref().expect("expected funcref")
481 }
482
483 #[inline]
484 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
485 match self {
486 Val::FuncRef(Some(f)) => f.comes_from_same_store(store),
487 Val::FuncRef(None) => true,
488
489 Val::ExternRef(Some(x)) => x.comes_from_same_store(store),
490 Val::ExternRef(None) => true,
491
492 Val::AnyRef(Some(a)) => a.comes_from_same_store(store),
493 Val::AnyRef(None) => true,
494
495 Val::ExnRef(Some(e)) => e.comes_from_same_store(store),
496 Val::ExnRef(None) => true,
497
498 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true,
502 }
503 }
504}
505
506impl From<i32> for Val {
507 #[inline]
508 fn from(val: i32) -> Val {
509 Val::I32(val)
510 }
511}
512
513impl From<i64> for Val {
514 #[inline]
515 fn from(val: i64) -> Val {
516 Val::I64(val)
517 }
518}
519
520impl From<f32> for Val {
521 #[inline]
522 fn from(val: f32) -> Val {
523 Val::F32(val.to_bits())
524 }
525}
526
527impl From<f64> for Val {
528 #[inline]
529 fn from(val: f64) -> Val {
530 Val::F64(val.to_bits())
531 }
532}
533
534impl From<Ref> for Val {
535 #[inline]
536 fn from(val: Ref) -> Val {
537 match val {
538 Ref::Extern(e) => Val::ExternRef(e),
539 Ref::Func(f) => Val::FuncRef(f),
540 Ref::Any(a) => Val::AnyRef(a),
541 Ref::Exn(e) => Val::ExnRef(e),
542 }
543 }
544}
545
546impl From<Rooted<ExternRef>> for Val {
547 #[inline]
548 fn from(val: Rooted<ExternRef>) -> Val {
549 Val::ExternRef(Some(val))
550 }
551}
552
553impl From<Option<Rooted<ExternRef>>> for Val {
554 #[inline]
555 fn from(val: Option<Rooted<ExternRef>>) -> Val {
556 Val::ExternRef(val)
557 }
558}
559
560impl From<Rooted<AnyRef>> for Val {
561 #[inline]
562 fn from(val: Rooted<AnyRef>) -> Val {
563 Val::AnyRef(Some(val))
564 }
565}
566
567impl From<Option<Rooted<AnyRef>>> for Val {
568 #[inline]
569 fn from(val: Option<Rooted<AnyRef>>) -> Val {
570 Val::AnyRef(val)
571 }
572}
573
574impl From<Rooted<StructRef>> for Val {
575 #[inline]
576 fn from(val: Rooted<StructRef>) -> Val {
577 Val::AnyRef(Some(val.into()))
578 }
579}
580
581impl From<Option<Rooted<StructRef>>> for Val {
582 #[inline]
583 fn from(val: Option<Rooted<StructRef>>) -> Val {
584 Val::AnyRef(val.map(Into::into))
585 }
586}
587
588impl From<Rooted<ArrayRef>> for Val {
589 #[inline]
590 fn from(val: Rooted<ArrayRef>) -> Val {
591 Val::AnyRef(Some(val.into()))
592 }
593}
594
595impl From<Option<Rooted<ArrayRef>>> for Val {
596 #[inline]
597 fn from(val: Option<Rooted<ArrayRef>>) -> Val {
598 Val::AnyRef(val.map(Into::into))
599 }
600}
601
602impl From<Rooted<ExnRef>> for Val {
603 #[inline]
604 fn from(val: Rooted<ExnRef>) -> Val {
605 Val::ExnRef(Some(val))
606 }
607}
608
609impl From<Option<Rooted<ExnRef>>> for Val {
610 #[inline]
611 fn from(val: Option<Rooted<ExnRef>>) -> Val {
612 Val::ExnRef(val)
613 }
614}
615
616impl From<Func> for Val {
617 #[inline]
618 fn from(val: Func) -> Val {
619 Val::FuncRef(Some(val))
620 }
621}
622
623impl From<Option<Func>> for Val {
624 #[inline]
625 fn from(val: Option<Func>) -> Val {
626 Val::FuncRef(val)
627 }
628}
629
630impl From<u128> for Val {
631 #[inline]
632 fn from(val: u128) -> Val {
633 Val::V128(val.into())
634 }
635}
636
637impl From<V128> for Val {
638 #[inline]
639 fn from(val: V128) -> Val {
640 Val::V128(val)
641 }
642}
643
644#[derive(Debug, Clone)]
669pub enum Ref {
670 Func(Option<Func>),
707
708 Extern(Option<Rooted<ExternRef>>),
718
719 Any(Option<Rooted<AnyRef>>),
728
729 Exn(Option<Rooted<ExnRef>>),
736}
737
738impl From<Func> for Ref {
739 #[inline]
740 fn from(f: Func) -> Ref {
741 Ref::Func(Some(f))
742 }
743}
744
745impl From<Option<Func>> for Ref {
746 #[inline]
747 fn from(f: Option<Func>) -> Ref {
748 Ref::Func(f)
749 }
750}
751
752impl From<Rooted<ExternRef>> for Ref {
753 #[inline]
754 fn from(e: Rooted<ExternRef>) -> Ref {
755 Ref::Extern(Some(e))
756 }
757}
758
759impl From<Option<Rooted<ExternRef>>> for Ref {
760 #[inline]
761 fn from(e: Option<Rooted<ExternRef>>) -> Ref {
762 Ref::Extern(e)
763 }
764}
765
766impl From<Rooted<AnyRef>> for Ref {
767 #[inline]
768 fn from(e: Rooted<AnyRef>) -> Ref {
769 Ref::Any(Some(e))
770 }
771}
772
773impl From<Option<Rooted<AnyRef>>> for Ref {
774 #[inline]
775 fn from(e: Option<Rooted<AnyRef>>) -> Ref {
776 Ref::Any(e)
777 }
778}
779
780impl From<Rooted<StructRef>> for Ref {
781 #[inline]
782 fn from(e: Rooted<StructRef>) -> Ref {
783 Ref::Any(Some(e.into()))
784 }
785}
786
787impl From<Option<Rooted<StructRef>>> for Ref {
788 #[inline]
789 fn from(e: Option<Rooted<StructRef>>) -> Ref {
790 Ref::Any(e.map(Into::into))
791 }
792}
793
794impl From<Rooted<ArrayRef>> for Ref {
795 #[inline]
796 fn from(e: Rooted<ArrayRef>) -> Ref {
797 Ref::Any(Some(e.into()))
798 }
799}
800
801impl From<Option<Rooted<ArrayRef>>> for Ref {
802 #[inline]
803 fn from(e: Option<Rooted<ArrayRef>>) -> Ref {
804 Ref::Any(e.map(Into::into))
805 }
806}
807
808impl From<Rooted<ExnRef>> for Ref {
809 #[inline]
810 fn from(e: Rooted<ExnRef>) -> Ref {
811 Ref::Exn(Some(e))
812 }
813}
814
815impl From<Option<Rooted<ExnRef>>> for Ref {
816 #[inline]
817 fn from(e: Option<Rooted<ExnRef>>) -> Ref {
818 Ref::Exn(e)
819 }
820}
821
822impl Ref {
823 #[inline]
825 pub fn null(heap_type: &HeapType) -> Self {
826 match heap_type.top() {
827 HeapType::Any => Ref::Any(None),
828 HeapType::Extern => Ref::Extern(None),
829 HeapType::Func => Ref::Func(None),
830 ty => unreachable!("not a heap type: {ty:?}"),
831 }
832 }
833
834 #[inline]
836 pub fn is_null(&self) -> bool {
837 match self {
838 Ref::Any(None) | Ref::Extern(None) | Ref::Func(None) | Ref::Exn(None) => true,
839 Ref::Any(Some(_)) | Ref::Extern(Some(_)) | Ref::Func(Some(_)) | Ref::Exn(Some(_)) => {
840 false
841 }
842 }
843 }
844
845 #[inline]
847 pub fn is_non_null(&self) -> bool {
848 !self.is_null()
849 }
850
851 #[inline]
853 pub fn is_extern(&self) -> bool {
854 matches!(self, Ref::Extern(_))
855 }
856
857 #[inline]
866 pub fn as_extern(&self) -> Option<Option<&Rooted<ExternRef>>> {
867 match self {
868 Ref::Extern(e) => Some(e.as_ref()),
869 _ => None,
870 }
871 }
872
873 #[inline]
880 pub fn unwrap_extern(&self) -> Option<&Rooted<ExternRef>> {
881 self.as_extern()
882 .expect("Ref::unwrap_extern on non-extern reference")
883 }
884
885 #[inline]
887 pub fn is_any(&self) -> bool {
888 matches!(self, Ref::Any(_))
889 }
890
891 #[inline]
900 pub fn as_any(&self) -> Option<Option<&Rooted<AnyRef>>> {
901 match self {
902 Ref::Any(e) => Some(e.as_ref()),
903 _ => None,
904 }
905 }
906
907 #[inline]
914 pub fn unwrap_any(&self) -> Option<&Rooted<AnyRef>> {
915 self.as_any().expect("Ref::unwrap_any on non-any reference")
916 }
917
918 #[inline]
920 pub fn is_exn(&self) -> bool {
921 matches!(self, Ref::Exn(_))
922 }
923
924 #[inline]
933 pub fn as_exn(&self) -> Option<Option<&Rooted<ExnRef>>> {
934 match self {
935 Ref::Exn(e) => Some(e.as_ref()),
936 _ => None,
937 }
938 }
939
940 #[inline]
947 pub fn unwrap_exn(&self) -> Option<&Rooted<ExnRef>> {
948 self.as_exn().expect("Ref::unwrap_exn on non-exn reference")
949 }
950
951 #[inline]
953 pub fn is_func(&self) -> bool {
954 matches!(self, Ref::Func(_))
955 }
956
957 #[inline]
966 pub fn as_func(&self) -> Option<Option<&Func>> {
967 match self {
968 Ref::Func(f) => Some(f.as_ref()),
969 _ => None,
970 }
971 }
972
973 #[inline]
980 pub fn unwrap_func(&self) -> Option<&Func> {
981 self.as_func()
982 .expect("Ref::unwrap_func on non-func reference")
983 }
984
985 pub fn ty(&self, store: impl AsContext) -> Result<RefType> {
995 self.load_ty(&store.as_context().0)
996 }
997
998 pub(crate) fn load_ty(&self, store: &StoreOpaque) -> Result<RefType> {
999 assert!(self.comes_from_same_store(store));
1000 Ok(RefType::new(
1001 self.is_null(),
1002 match self {
1006 Ref::Extern(None) => HeapType::NoExtern,
1007 Ref::Extern(Some(_)) => HeapType::Extern,
1008
1009 Ref::Func(None) => HeapType::NoFunc,
1010 Ref::Func(Some(f)) => HeapType::ConcreteFunc(f.load_ty(store)),
1011
1012 Ref::Any(None) => HeapType::None,
1013 Ref::Any(Some(a)) => a._ty(store)?,
1014
1015 Ref::Exn(None) => HeapType::None,
1016 Ref::Exn(Some(e)) => e._ty(store)?.into(),
1017 },
1018 ))
1019 }
1020
1021 pub fn matches_ty(&self, store: impl AsContext, ty: &RefType) -> Result<bool> {
1029 self._matches_ty(&store.as_context().0, ty)
1030 }
1031
1032 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<bool> {
1033 assert!(self.comes_from_same_store(store));
1034 assert!(ty.comes_from_same_engine(store.engine()));
1035 if self.is_null() && !ty.is_nullable() {
1036 return Ok(false);
1037 }
1038 Ok(match (self, ty.heap_type()) {
1039 (Ref::Extern(_), HeapType::Extern) => true,
1040 (Ref::Extern(None), HeapType::NoExtern) => true,
1041 (Ref::Extern(_), _) => false,
1042
1043 (Ref::Func(_), HeapType::Func) => true,
1044 (Ref::Func(None), HeapType::NoFunc | HeapType::ConcreteFunc(_)) => true,
1045 (Ref::Func(Some(f)), HeapType::ConcreteFunc(func_ty)) => f._matches_ty(store, func_ty),
1046 (Ref::Func(_), _) => false,
1047
1048 (Ref::Any(_), HeapType::Any) => true,
1049 (Ref::Any(Some(a)), HeapType::I31) => a._is_i31(store)?,
1050 (Ref::Any(Some(a)), HeapType::Struct) => a._is_struct(store)?,
1051 (Ref::Any(Some(a)), HeapType::ConcreteStruct(_ty)) => match a._as_struct(store)? {
1052 None => false,
1053 Some(s) => s._matches_ty(store, _ty)?,
1054 },
1055 (Ref::Any(Some(a)), HeapType::Eq) => a._is_eqref(store)?,
1056 (Ref::Any(Some(a)), HeapType::Array) => a._is_array(store)?,
1057 (Ref::Any(Some(a)), HeapType::ConcreteArray(_ty)) => match a._as_array(store)? {
1058 None => false,
1059 Some(a) => a._matches_ty(store, _ty)?,
1060 },
1061 (
1062 Ref::Any(None),
1063 HeapType::None
1064 | HeapType::I31
1065 | HeapType::ConcreteStruct(_)
1066 | HeapType::Struct
1067 | HeapType::ConcreteArray(_)
1068 | HeapType::Array
1069 | HeapType::Eq,
1070 ) => true,
1071 (Ref::Any(_), _) => false,
1072
1073 (Ref::Exn(_), HeapType::Exn) => true,
1074 (Ref::Exn(None), HeapType::NoExn | HeapType::ConcreteExn(_)) => true,
1075 (Ref::Exn(Some(e)), HeapType::ConcreteExn(_)) => {
1076 e._matches_ty(store, &ty.heap_type())?
1077 }
1078 (Ref::Exn(_), _) => false,
1079 })
1080 }
1081
1082 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<()> {
1083 if !self.comes_from_same_store(store) {
1084 bail!("reference used with wrong store")
1085 }
1086 if !ty.comes_from_same_engine(store.engine()) {
1087 bail!("type used with wrong engine")
1088 }
1089 if self._matches_ty(store, ty)? {
1090 Ok(())
1091 } else {
1092 let actual_ty = self.load_ty(store)?;
1093 bail!("type mismatch: expected {ty}, found {actual_ty}")
1094 }
1095 }
1096
1097 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
1098 match self {
1099 Ref::Func(Some(f)) => f.comes_from_same_store(store),
1100 Ref::Func(None) => true,
1101 Ref::Extern(Some(x)) => x.comes_from_same_store(store),
1102 Ref::Extern(None) => true,
1103 Ref::Any(Some(a)) => a.comes_from_same_store(store),
1104 Ref::Any(None) => true,
1105 Ref::Exn(Some(e)) => e.comes_from_same_store(store),
1106 Ref::Exn(None) => true,
1107 }
1108 }
1109
1110 pub(crate) fn into_table_element(
1111 self,
1112 store: &mut StoreOpaque,
1113 ty: &RefType,
1114 ) -> Result<TableElement> {
1115 let mut store = AutoAssertNoGc::new(store);
1116 self.ensure_matches_ty(&store, &ty)
1117 .context("type mismatch: value does not match table element type")?;
1118
1119 match (self, ty.heap_type().top()) {
1120 (Ref::Func(None), HeapType::Func) => {
1121 assert!(ty.is_nullable());
1122 Ok(TableElement::FuncRef(None))
1123 }
1124 (Ref::Func(Some(f)), HeapType::Func) => {
1125 debug_assert!(
1126 f.comes_from_same_store(&store),
1127 "checked in `ensure_matches_ty`"
1128 );
1129 Ok(TableElement::FuncRef(Some(f.vm_func_ref(&store))))
1130 }
1131
1132 (Ref::Extern(e), HeapType::Extern) => match e {
1133 None => {
1134 assert!(ty.is_nullable());
1135 Ok(TableElement::GcRef(None))
1136 }
1137 Some(e) => {
1138 let gc_ref = e.try_clone_gc_ref(&mut store)?;
1139 Ok(TableElement::GcRef(Some(gc_ref)))
1140 }
1141 },
1142
1143 (Ref::Any(a), HeapType::Any) => match a {
1144 None => {
1145 assert!(ty.is_nullable());
1146 Ok(TableElement::GcRef(None))
1147 }
1148 Some(a) => {
1149 let gc_ref = a.try_clone_gc_ref(&mut store)?;
1150 Ok(TableElement::GcRef(Some(gc_ref)))
1151 }
1152 },
1153
1154 (Ref::Exn(e), HeapType::Exn) => match e {
1155 None => {
1156 assert!(ty.is_nullable());
1157 Ok(TableElement::GcRef(None))
1158 }
1159 Some(e) => {
1160 let gc_ref = e.try_clone_gc_ref(&mut store)?;
1161 Ok(TableElement::GcRef(Some(gc_ref)))
1162 }
1163 },
1164
1165 _ => unreachable!("checked that the value matches the type above"),
1166 }
1167 }
1168}
1169
1170#[cfg(test)]
1171mod tests {
1172 use crate::*;
1173
1174 #[test]
1175 fn size_of_val() {
1176 let expected = if cfg!(target_arch = "x86_64")
1179 || cfg!(target_arch = "aarch64")
1180 || cfg!(target_arch = "s390x")
1181 || cfg!(target_arch = "riscv64")
1182 || cfg!(target_arch = "arm")
1183 {
1184 24
1185 } else if cfg!(target_arch = "x86") {
1186 20
1187 } else {
1188 panic!("unsupported architecture")
1189 };
1190 assert_eq!(std::mem::size_of::<Val>(), expected);
1191 }
1192
1193 #[test]
1194 fn size_of_ref() {
1195 let expected = if cfg!(target_arch = "x86_64")
1198 || cfg!(target_arch = "aarch64")
1199 || cfg!(target_arch = "s390x")
1200 || cfg!(target_arch = "riscv64")
1201 || cfg!(target_arch = "arm")
1202 {
1203 24
1204 } else if cfg!(target_arch = "x86") {
1205 20
1206 } else {
1207 panic!("unsupported architecture")
1208 };
1209 assert_eq!(std::mem::size_of::<Ref>(), expected);
1210 }
1211
1212 #[test]
1213 #[should_panic]
1214 fn val_matches_ty_wrong_engine() {
1215 let e1 = Engine::default();
1216 let e2 = Engine::default();
1217
1218 let t1 = FuncType::new(&e1, None, None);
1219 let t2 = FuncType::new(&e2, None, None);
1220
1221 let mut s1 = Store::new(&e1, ());
1222 let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1223
1224 let _ = Val::FuncRef(Some(f)).matches_ty(
1226 &s1,
1227 &ValType::Ref(RefType::new(true, HeapType::ConcreteFunc(t2))),
1228 );
1229 }
1230
1231 #[test]
1232 #[should_panic]
1233 fn ref_matches_ty_wrong_engine() {
1234 let e1 = Engine::default();
1235 let e2 = Engine::default();
1236
1237 let t1 = FuncType::new(&e1, None, None);
1238 let t2 = FuncType::new(&e2, None, None);
1239
1240 let mut s1 = Store::new(&e1, ());
1241 let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1242
1243 let _ = Ref::Func(Some(f)).matches_ty(&s1, &RefType::new(true, HeapType::ConcreteFunc(t2)));
1245 }
1246}