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)]
16pub struct ContRef;
17
18#[derive(Debug, Clone, Copy)]
24pub enum Val {
25 I32(i32),
30
31 I64(i64),
33
34 F32(u32),
39
40 F64(u64),
45
46 V128(V128),
48
49 FuncRef(Option<Func>),
51
52 ExternRef(Option<Rooted<ExternRef>>),
54
55 AnyRef(Option<Rooted<AnyRef>>),
57
58 ExnRef(Option<Rooted<ExnRef>>),
60
61 ContRef(Option<ContRef>),
66}
67
68macro_rules! accessors {
69 ($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($(
70 #[inline]
73 pub fn $get(&self) -> Option<$ty> {
74 if let Val::$variant($bind) = self {
75 Some($cvt)
76 } else {
77 None
78 }
79 }
80
81 #[inline]
88 pub fn $unwrap(&self) -> $ty {
89 self.$get().expect(concat!("expected ", stringify!($ty)))
90 }
91 )*)
92}
93
94impl Val {
95 #[inline]
97 pub fn null_ref(heap_type: &HeapType) -> Val {
98 Ref::null(&heap_type).into()
99 }
100
101 #[inline]
106 pub const fn null_func_ref() -> Val {
107 Val::FuncRef(None)
108 }
109
110 #[inline]
115 pub const fn null_extern_ref() -> Val {
116 Val::ExternRef(None)
117 }
118
119 #[inline]
124 pub const fn null_any_ref() -> Val {
125 Val::AnyRef(None)
126 }
127
128 pub(crate) const fn null_top(top: WasmHeapTopType) -> Val {
129 match top {
130 WasmHeapTopType::Func => Val::FuncRef(None),
131 WasmHeapTopType::Extern => Val::ExternRef(None),
132 WasmHeapTopType::Any => Val::AnyRef(None),
133 WasmHeapTopType::Exn => Val::ExnRef(None),
134 WasmHeapTopType::Cont => Val::ContRef(None),
135 }
136 }
137
138 pub fn default_for_ty(ty: &ValType) -> Option<Val> {
143 match ty {
144 ValType::I32 => Some(Val::I32(0)),
145 ValType::I64 => Some(Val::I64(0)),
146 ValType::F32 => Some(Val::F32(0)),
147 ValType::F64 => Some(Val::F64(0)),
148 ValType::V128 => Some(Val::V128(V128::from(0))),
149 ValType::Ref(ref_ty) => {
150 if ref_ty.is_nullable() {
151 Some(Val::null_ref(ref_ty.heap_type()))
152 } else {
153 None
154 }
155 }
156 }
157 }
158
159 #[inline]
170 pub fn ty(&self, store: impl AsContext) -> Result<ValType> {
171 self.load_ty(&store.as_context().0)
172 }
173
174 #[inline]
175 pub(crate) fn load_ty(&self, store: &StoreOpaque) -> Result<ValType> {
176 Ok(match self {
177 Val::I32(_) => ValType::I32,
178 Val::I64(_) => ValType::I64,
179 Val::F32(_) => ValType::F32,
180 Val::F64(_) => ValType::F64,
181 Val::V128(_) => ValType::V128,
182 Val::ExternRef(Some(_)) => ValType::EXTERNREF,
183 Val::ExternRef(None) => ValType::NULLFUNCREF,
184 Val::FuncRef(None) => ValType::NULLFUNCREF,
185 Val::FuncRef(Some(f)) => ValType::Ref(RefType::new(
186 false,
187 HeapType::ConcreteFunc(f.load_ty(store)),
188 )),
189 Val::AnyRef(None) => ValType::NULLREF,
190 Val::AnyRef(Some(a)) => ValType::Ref(RefType::new(false, a._ty(store)?)),
191 Val::ExnRef(None) => ValType::NULLEXNREF,
192 Val::ExnRef(Some(e)) => ValType::Ref(RefType::new(false, e._ty(store)?.into())),
193 Val::ContRef(_) => {
194 return Err(anyhow::anyhow!(
196 "continuation references not yet supported in embedder API"
197 ));
198 }
199 })
200 }
201
202 pub fn matches_ty(&self, store: impl AsContext, ty: &ValType) -> Result<bool> {
210 self._matches_ty(&store.as_context().0, ty)
211 }
212
213 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &ValType) -> Result<bool> {
214 assert!(self.comes_from_same_store(store));
215 assert!(ty.comes_from_same_engine(store.engine()));
216 Ok(match (self, ty) {
217 (Val::I32(_), ValType::I32)
218 | (Val::I64(_), ValType::I64)
219 | (Val::F32(_), ValType::F32)
220 | (Val::F64(_), ValType::F64)
221 | (Val::V128(_), ValType::V128) => true,
222
223 (Val::FuncRef(f), ValType::Ref(ref_ty)) => Ref::from(*f)._matches_ty(store, ref_ty)?,
224 (Val::ExternRef(e), ValType::Ref(ref_ty)) => {
225 Ref::from(*e)._matches_ty(store, ref_ty)?
226 }
227 (Val::AnyRef(a), ValType::Ref(ref_ty)) => Ref::from(*a)._matches_ty(store, ref_ty)?,
228 (Val::ExnRef(e), ValType::Ref(ref_ty)) => Ref::from(*e)._matches_ty(store, ref_ty)?,
229
230 (Val::I32(_), _)
231 | (Val::I64(_), _)
232 | (Val::F32(_), _)
233 | (Val::F64(_), _)
234 | (Val::V128(_), _)
235 | (Val::FuncRef(_), _)
236 | (Val::ExternRef(_), _)
237 | (Val::AnyRef(_), _)
238 | (Val::ExnRef(_), _)
239 | (Val::ContRef(_), _) => false,
240 })
241 }
242
243 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &ValType) -> Result<()> {
244 if !self.comes_from_same_store(store) {
245 bail!("value used with wrong store")
246 }
247 if !ty.comes_from_same_engine(store.engine()) {
248 bail!("type used with wrong engine")
249 }
250 if self._matches_ty(store, ty)? {
251 Ok(())
252 } else {
253 let actual_ty = self.load_ty(store)?;
254 bail!("type mismatch: expected {ty}, found {actual_ty}")
255 }
256 }
257
258 pub fn to_raw(&self, store: impl AsContextMut) -> Result<ValRaw> {
269 match self {
270 Val::I32(i) => Ok(ValRaw::i32(*i)),
271 Val::I64(i) => Ok(ValRaw::i64(*i)),
272 Val::F32(u) => Ok(ValRaw::f32(*u)),
273 Val::F64(u) => Ok(ValRaw::f64(*u)),
274 Val::V128(b) => Ok(ValRaw::v128(b.as_u128())),
275 Val::ExternRef(e) => Ok(ValRaw::externref(match e {
276 None => 0,
277 Some(e) => e.to_raw(store)?,
278 })),
279 Val::AnyRef(e) => Ok(ValRaw::anyref(match e {
280 None => 0,
281 Some(e) => e.to_raw(store)?,
282 })),
283 Val::ExnRef(e) => Ok(ValRaw::exnref(match e {
284 None => 0,
285 Some(e) => e.to_raw(store)?,
286 })),
287 Val::FuncRef(f) => Ok(ValRaw::funcref(match f {
288 Some(f) => f.to_raw(store),
289 None => ptr::null_mut(),
290 })),
291 Val::ContRef(_) => {
292 Err(anyhow::anyhow!(
294 "continuation references not yet supported in to_raw conversion"
295 ))
296 }
297 }
298 }
299
300 pub unsafe fn from_raw(mut store: impl AsContextMut, raw: ValRaw, ty: ValType) -> Val {
308 let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
309 unsafe { Self::_from_raw(&mut store, raw, &ty) }
311 }
312
313 pub(crate) unsafe fn _from_raw(
315 store: &mut AutoAssertNoGc<'_>,
316 raw: ValRaw,
317 ty: &ValType,
318 ) -> Val {
319 match ty {
320 ValType::I32 => Val::I32(raw.get_i32()),
321 ValType::I64 => Val::I64(raw.get_i64()),
322 ValType::F32 => Val::F32(raw.get_f32()),
323 ValType::F64 => Val::F64(raw.get_f64()),
324 ValType::V128 => Val::V128(raw.get_v128().into()),
325 ValType::Ref(ref_ty) => {
326 let ref_ = match ref_ty.heap_type() {
327 HeapType::Func | HeapType::ConcreteFunc(_) => unsafe {
330 Func::_from_raw(store, raw.get_funcref()).into()
331 },
332
333 HeapType::NoFunc => Ref::Func(None),
334
335 HeapType::NoCont | HeapType::ConcreteCont(_) | HeapType::Cont => {
336 unimplemented!()
338 }
339
340 HeapType::Extern => ExternRef::_from_raw(store, raw.get_externref()).into(),
341
342 HeapType::NoExtern => Ref::Extern(None),
343
344 HeapType::Any
345 | HeapType::Eq
346 | HeapType::I31
347 | HeapType::Array
348 | HeapType::ConcreteArray(_)
349 | HeapType::Struct
350 | HeapType::ConcreteStruct(_) => {
351 AnyRef::_from_raw(store, raw.get_anyref()).into()
352 }
353
354 HeapType::Exn | HeapType::ConcreteExn(_) => {
355 ExnRef::_from_raw(store, raw.get_exnref()).into()
356 }
357 HeapType::NoExn => Ref::Exn(None),
358
359 HeapType::None => Ref::Any(None),
360 };
361 assert!(
362 ref_ty.is_nullable() || !ref_.is_null(),
363 "if the type is not nullable, we shouldn't get null; got \
364 type = {ref_ty}, ref = {ref_:?}"
365 );
366 ref_.into()
367 }
368 }
369 }
370
371 accessors! {
372 e
373 (I32(i32) i32 unwrap_i32 *e)
374 (I64(i64) i64 unwrap_i64 *e)
375 (F32(f32) f32 unwrap_f32 f32::from_bits(*e))
376 (F64(f64) f64 unwrap_f64 f64::from_bits(*e))
377 (FuncRef(Option<&Func>) func_ref unwrap_func_ref e.as_ref())
378 (ExternRef(Option<&Rooted<ExternRef>>) extern_ref unwrap_extern_ref e.as_ref())
379 (AnyRef(Option<&Rooted<AnyRef>>) any_ref unwrap_any_ref e.as_ref())
380 (V128(V128) v128 unwrap_v128 *e)
381 }
382
383 #[inline]
385 pub fn ref_(self) -> Option<Ref> {
386 match self {
387 Val::FuncRef(f) => Some(Ref::Func(f)),
388 Val::ExternRef(e) => Some(Ref::Extern(e)),
389 Val::AnyRef(a) => Some(Ref::Any(a)),
390 Val::ExnRef(e) => Some(Ref::Exn(e)),
391 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => None,
392 Val::ContRef(_) => None, }
394 }
395
396 #[inline]
404 pub fn externref(&self) -> Option<Option<&Rooted<ExternRef>>> {
405 match self {
406 Val::ExternRef(None) => Some(None),
407 Val::ExternRef(Some(e)) => Some(Some(e)),
408 _ => None,
409 }
410 }
411
412 #[inline]
423 pub fn unwrap_externref(&self) -> Option<&Rooted<ExternRef>> {
424 self.externref().expect("expected externref")
425 }
426
427 #[inline]
435 pub fn anyref(&self) -> Option<Option<&Rooted<AnyRef>>> {
436 match self {
437 Val::AnyRef(None) => Some(None),
438 Val::AnyRef(Some(e)) => Some(Some(e)),
439 _ => None,
440 }
441 }
442
443 #[inline]
454 pub fn unwrap_anyref(&self) -> Option<&Rooted<AnyRef>> {
455 self.anyref().expect("expected anyref")
456 }
457
458 #[inline]
466 pub fn exnref(&self) -> Option<Option<&Rooted<ExnRef>>> {
467 match self {
468 Val::ExnRef(None) => Some(None),
469 Val::ExnRef(Some(e)) => Some(Some(e)),
470 _ => None,
471 }
472 }
473
474 #[inline]
485 pub fn unwrap_exnref(&self) -> Option<&Rooted<ExnRef>> {
486 self.exnref().expect("expected exnref")
487 }
488
489 #[inline]
497 pub fn funcref(&self) -> Option<Option<&Func>> {
498 match self {
499 Val::FuncRef(None) => Some(None),
500 Val::FuncRef(Some(f)) => Some(Some(f)),
501 _ => None,
502 }
503 }
504
505 #[inline]
516 pub fn unwrap_funcref(&self) -> Option<&Func> {
517 self.funcref().expect("expected funcref")
518 }
519
520 #[inline]
521 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
522 match self {
523 Val::FuncRef(Some(f)) => f.comes_from_same_store(store),
524 Val::FuncRef(None) => true,
525
526 Val::ExternRef(Some(x)) => x.comes_from_same_store(store),
527 Val::ExternRef(None) => true,
528
529 Val::AnyRef(Some(a)) => a.comes_from_same_store(store),
530 Val::AnyRef(None) => true,
531
532 Val::ExnRef(Some(e)) => e.comes_from_same_store(store),
533 Val::ExnRef(None) => true,
534
535 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true,
539
540 Val::ContRef(_) => true, }
543 }
544}
545
546impl From<i32> for Val {
547 #[inline]
548 fn from(val: i32) -> Val {
549 Val::I32(val)
550 }
551}
552
553impl From<i64> for Val {
554 #[inline]
555 fn from(val: i64) -> Val {
556 Val::I64(val)
557 }
558}
559
560impl From<f32> for Val {
561 #[inline]
562 fn from(val: f32) -> Val {
563 Val::F32(val.to_bits())
564 }
565}
566
567impl From<f64> for Val {
568 #[inline]
569 fn from(val: f64) -> Val {
570 Val::F64(val.to_bits())
571 }
572}
573
574impl From<Ref> for Val {
575 #[inline]
576 fn from(val: Ref) -> Val {
577 match val {
578 Ref::Extern(e) => Val::ExternRef(e),
579 Ref::Func(f) => Val::FuncRef(f),
580 Ref::Any(a) => Val::AnyRef(a),
581 Ref::Exn(e) => Val::ExnRef(e),
582 }
583 }
584}
585
586impl From<Rooted<ExternRef>> for Val {
587 #[inline]
588 fn from(val: Rooted<ExternRef>) -> Val {
589 Val::ExternRef(Some(val))
590 }
591}
592
593impl From<Option<Rooted<ExternRef>>> for Val {
594 #[inline]
595 fn from(val: Option<Rooted<ExternRef>>) -> Val {
596 Val::ExternRef(val)
597 }
598}
599
600impl From<Rooted<AnyRef>> for Val {
601 #[inline]
602 fn from(val: Rooted<AnyRef>) -> Val {
603 Val::AnyRef(Some(val))
604 }
605}
606
607impl From<Option<Rooted<AnyRef>>> for Val {
608 #[inline]
609 fn from(val: Option<Rooted<AnyRef>>) -> Val {
610 Val::AnyRef(val)
611 }
612}
613
614impl From<Rooted<StructRef>> for Val {
615 #[inline]
616 fn from(val: Rooted<StructRef>) -> Val {
617 Val::AnyRef(Some(val.into()))
618 }
619}
620
621impl From<Option<Rooted<StructRef>>> for Val {
622 #[inline]
623 fn from(val: Option<Rooted<StructRef>>) -> Val {
624 Val::AnyRef(val.map(Into::into))
625 }
626}
627
628impl From<Rooted<ArrayRef>> for Val {
629 #[inline]
630 fn from(val: Rooted<ArrayRef>) -> Val {
631 Val::AnyRef(Some(val.into()))
632 }
633}
634
635impl From<Option<Rooted<ArrayRef>>> for Val {
636 #[inline]
637 fn from(val: Option<Rooted<ArrayRef>>) -> Val {
638 Val::AnyRef(val.map(Into::into))
639 }
640}
641
642impl From<Rooted<ExnRef>> for Val {
643 #[inline]
644 fn from(val: Rooted<ExnRef>) -> Val {
645 Val::ExnRef(Some(val))
646 }
647}
648
649impl From<Option<Rooted<ExnRef>>> for Val {
650 #[inline]
651 fn from(val: Option<Rooted<ExnRef>>) -> Val {
652 Val::ExnRef(val)
653 }
654}
655
656impl From<Func> for Val {
657 #[inline]
658 fn from(val: Func) -> Val {
659 Val::FuncRef(Some(val))
660 }
661}
662
663impl From<Option<Func>> for Val {
664 #[inline]
665 fn from(val: Option<Func>) -> Val {
666 Val::FuncRef(val)
667 }
668}
669
670impl From<u128> for Val {
671 #[inline]
672 fn from(val: u128) -> Val {
673 Val::V128(val.into())
674 }
675}
676
677impl From<V128> for Val {
678 #[inline]
679 fn from(val: V128) -> Val {
680 Val::V128(val)
681 }
682}
683
684#[derive(Debug, Clone)]
709pub enum Ref {
710 Func(Option<Func>),
747
748 Extern(Option<Rooted<ExternRef>>),
758
759 Any(Option<Rooted<AnyRef>>),
768
769 Exn(Option<Rooted<ExnRef>>),
776}
777
778impl From<Func> for Ref {
779 #[inline]
780 fn from(f: Func) -> Ref {
781 Ref::Func(Some(f))
782 }
783}
784
785impl From<Option<Func>> for Ref {
786 #[inline]
787 fn from(f: Option<Func>) -> Ref {
788 Ref::Func(f)
789 }
790}
791
792impl From<Rooted<ExternRef>> for Ref {
793 #[inline]
794 fn from(e: Rooted<ExternRef>) -> Ref {
795 Ref::Extern(Some(e))
796 }
797}
798
799impl From<Option<Rooted<ExternRef>>> for Ref {
800 #[inline]
801 fn from(e: Option<Rooted<ExternRef>>) -> Ref {
802 Ref::Extern(e)
803 }
804}
805
806impl From<Rooted<AnyRef>> for Ref {
807 #[inline]
808 fn from(e: Rooted<AnyRef>) -> Ref {
809 Ref::Any(Some(e))
810 }
811}
812
813impl From<Option<Rooted<AnyRef>>> for Ref {
814 #[inline]
815 fn from(e: Option<Rooted<AnyRef>>) -> Ref {
816 Ref::Any(e)
817 }
818}
819
820impl From<Rooted<StructRef>> for Ref {
821 #[inline]
822 fn from(e: Rooted<StructRef>) -> Ref {
823 Ref::Any(Some(e.into()))
824 }
825}
826
827impl From<Option<Rooted<StructRef>>> for Ref {
828 #[inline]
829 fn from(e: Option<Rooted<StructRef>>) -> Ref {
830 Ref::Any(e.map(Into::into))
831 }
832}
833
834impl From<Rooted<ArrayRef>> for Ref {
835 #[inline]
836 fn from(e: Rooted<ArrayRef>) -> Ref {
837 Ref::Any(Some(e.into()))
838 }
839}
840
841impl From<Option<Rooted<ArrayRef>>> for Ref {
842 #[inline]
843 fn from(e: Option<Rooted<ArrayRef>>) -> Ref {
844 Ref::Any(e.map(Into::into))
845 }
846}
847
848impl From<Rooted<ExnRef>> for Ref {
849 #[inline]
850 fn from(e: Rooted<ExnRef>) -> Ref {
851 Ref::Exn(Some(e))
852 }
853}
854
855impl From<Option<Rooted<ExnRef>>> for Ref {
856 #[inline]
857 fn from(e: Option<Rooted<ExnRef>>) -> Ref {
858 Ref::Exn(e)
859 }
860}
861
862impl Ref {
863 #[inline]
865 pub fn null(heap_type: &HeapType) -> Self {
866 match heap_type.top() {
867 HeapType::Any => Ref::Any(None),
868 HeapType::Extern => Ref::Extern(None),
869 HeapType::Func => Ref::Func(None),
870 HeapType::Exn => Ref::Exn(None),
871 ty => unreachable!("not a heap type: {ty:?}"),
872 }
873 }
874
875 #[inline]
877 pub fn is_null(&self) -> bool {
878 match self {
879 Ref::Any(None) | Ref::Extern(None) | Ref::Func(None) | Ref::Exn(None) => true,
880 Ref::Any(Some(_)) | Ref::Extern(Some(_)) | Ref::Func(Some(_)) | Ref::Exn(Some(_)) => {
881 false
882 }
883 }
884 }
885
886 #[inline]
888 pub fn is_non_null(&self) -> bool {
889 !self.is_null()
890 }
891
892 #[inline]
894 pub fn is_extern(&self) -> bool {
895 matches!(self, Ref::Extern(_))
896 }
897
898 #[inline]
907 pub fn as_extern(&self) -> Option<Option<&Rooted<ExternRef>>> {
908 match self {
909 Ref::Extern(e) => Some(e.as_ref()),
910 _ => None,
911 }
912 }
913
914 #[inline]
921 pub fn unwrap_extern(&self) -> Option<&Rooted<ExternRef>> {
922 self.as_extern()
923 .expect("Ref::unwrap_extern on non-extern reference")
924 }
925
926 #[inline]
928 pub fn is_any(&self) -> bool {
929 matches!(self, Ref::Any(_))
930 }
931
932 #[inline]
941 pub fn as_any(&self) -> Option<Option<&Rooted<AnyRef>>> {
942 match self {
943 Ref::Any(e) => Some(e.as_ref()),
944 _ => None,
945 }
946 }
947
948 #[inline]
955 pub fn unwrap_any(&self) -> Option<&Rooted<AnyRef>> {
956 self.as_any().expect("Ref::unwrap_any on non-any reference")
957 }
958
959 #[inline]
961 pub fn is_exn(&self) -> bool {
962 matches!(self, Ref::Exn(_))
963 }
964
965 #[inline]
974 pub fn as_exn(&self) -> Option<Option<&Rooted<ExnRef>>> {
975 match self {
976 Ref::Exn(e) => Some(e.as_ref()),
977 _ => None,
978 }
979 }
980
981 #[inline]
988 pub fn unwrap_exn(&self) -> Option<&Rooted<ExnRef>> {
989 self.as_exn().expect("Ref::unwrap_exn on non-exn reference")
990 }
991
992 #[inline]
994 pub fn is_func(&self) -> bool {
995 matches!(self, Ref::Func(_))
996 }
997
998 #[inline]
1007 pub fn as_func(&self) -> Option<Option<&Func>> {
1008 match self {
1009 Ref::Func(f) => Some(f.as_ref()),
1010 _ => None,
1011 }
1012 }
1013
1014 #[inline]
1021 pub fn unwrap_func(&self) -> Option<&Func> {
1022 self.as_func()
1023 .expect("Ref::unwrap_func on non-func reference")
1024 }
1025
1026 pub fn ty(&self, store: impl AsContext) -> Result<RefType> {
1036 self.load_ty(&store.as_context().0)
1037 }
1038
1039 pub(crate) fn load_ty(&self, store: &StoreOpaque) -> Result<RefType> {
1040 assert!(self.comes_from_same_store(store));
1041 Ok(RefType::new(
1042 self.is_null(),
1043 match self {
1047 Ref::Extern(None) => HeapType::NoExtern,
1048 Ref::Extern(Some(_)) => HeapType::Extern,
1049
1050 Ref::Func(None) => HeapType::NoFunc,
1051 Ref::Func(Some(f)) => HeapType::ConcreteFunc(f.load_ty(store)),
1052
1053 Ref::Any(None) => HeapType::None,
1054 Ref::Any(Some(a)) => a._ty(store)?,
1055
1056 Ref::Exn(None) => HeapType::None,
1057 Ref::Exn(Some(e)) => e._ty(store)?.into(),
1058 },
1059 ))
1060 }
1061
1062 pub fn matches_ty(&self, store: impl AsContext, ty: &RefType) -> Result<bool> {
1070 self._matches_ty(&store.as_context().0, ty)
1071 }
1072
1073 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<bool> {
1074 assert!(self.comes_from_same_store(store));
1075 assert!(ty.comes_from_same_engine(store.engine()));
1076 if self.is_null() && !ty.is_nullable() {
1077 return Ok(false);
1078 }
1079 Ok(match (self, ty.heap_type()) {
1080 (Ref::Extern(_), HeapType::Extern) => true,
1081 (Ref::Extern(None), HeapType::NoExtern) => true,
1082 (Ref::Extern(_), _) => false,
1083
1084 (Ref::Func(_), HeapType::Func) => true,
1085 (Ref::Func(None), HeapType::NoFunc | HeapType::ConcreteFunc(_)) => true,
1086 (Ref::Func(Some(f)), HeapType::ConcreteFunc(func_ty)) => f._matches_ty(store, func_ty),
1087 (Ref::Func(_), _) => false,
1088
1089 (Ref::Any(_), HeapType::Any) => true,
1090 (Ref::Any(Some(a)), HeapType::I31) => a._is_i31(store)?,
1091 (Ref::Any(Some(a)), HeapType::Struct) => a._is_struct(store)?,
1092 (Ref::Any(Some(a)), HeapType::ConcreteStruct(_ty)) => match a._as_struct(store)? {
1093 None => false,
1094 Some(s) => s._matches_ty(store, _ty)?,
1095 },
1096 (Ref::Any(Some(a)), HeapType::Eq) => a._is_eqref(store)?,
1097 (Ref::Any(Some(a)), HeapType::Array) => a._is_array(store)?,
1098 (Ref::Any(Some(a)), HeapType::ConcreteArray(_ty)) => match a._as_array(store)? {
1099 None => false,
1100 Some(a) => a._matches_ty(store, _ty)?,
1101 },
1102 (
1103 Ref::Any(None),
1104 HeapType::None
1105 | HeapType::I31
1106 | HeapType::ConcreteStruct(_)
1107 | HeapType::Struct
1108 | HeapType::ConcreteArray(_)
1109 | HeapType::Array
1110 | HeapType::Eq,
1111 ) => true,
1112 (Ref::Any(_), _) => false,
1113
1114 (Ref::Exn(_), HeapType::Exn) => true,
1115 (Ref::Exn(None), HeapType::NoExn | HeapType::ConcreteExn(_)) => true,
1116 (Ref::Exn(Some(e)), HeapType::ConcreteExn(_)) => {
1117 e._matches_ty(store, &ty.heap_type())?
1118 }
1119 (Ref::Exn(_), _) => false,
1120 })
1121 }
1122
1123 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<()> {
1124 if !self.comes_from_same_store(store) {
1125 bail!("reference used with wrong store")
1126 }
1127 if !ty.comes_from_same_engine(store.engine()) {
1128 bail!("type used with wrong engine")
1129 }
1130 if self._matches_ty(store, ty)? {
1131 Ok(())
1132 } else {
1133 let actual_ty = self.load_ty(store)?;
1134 bail!("type mismatch: expected {ty}, found {actual_ty}")
1135 }
1136 }
1137
1138 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
1139 match self {
1140 Ref::Func(Some(f)) => f.comes_from_same_store(store),
1141 Ref::Func(None) => true,
1142 Ref::Extern(Some(x)) => x.comes_from_same_store(store),
1143 Ref::Extern(None) => true,
1144 Ref::Any(Some(a)) => a.comes_from_same_store(store),
1145 Ref::Any(None) => true,
1146 Ref::Exn(Some(e)) => e.comes_from_same_store(store),
1147 Ref::Exn(None) => true,
1148 }
1149 }
1150}
1151
1152#[cfg(test)]
1153mod tests {
1154 use crate::*;
1155
1156 #[test]
1157 fn size_of_val() {
1158 let expected = if cfg!(target_arch = "x86_64")
1161 || cfg!(target_arch = "aarch64")
1162 || cfg!(target_arch = "s390x")
1163 || cfg!(target_arch = "riscv64")
1164 || cfg!(target_arch = "arm")
1165 {
1166 24
1167 } else if cfg!(target_arch = "x86") {
1168 20
1169 } else {
1170 panic!("unsupported architecture")
1171 };
1172 assert_eq!(std::mem::size_of::<Val>(), expected);
1173 }
1174
1175 #[test]
1176 fn size_of_ref() {
1177 let expected = if cfg!(target_arch = "x86_64")
1180 || cfg!(target_arch = "aarch64")
1181 || cfg!(target_arch = "s390x")
1182 || cfg!(target_arch = "riscv64")
1183 || cfg!(target_arch = "arm")
1184 {
1185 24
1186 } else if cfg!(target_arch = "x86") {
1187 20
1188 } else {
1189 panic!("unsupported architecture")
1190 };
1191 assert_eq!(std::mem::size_of::<Ref>(), expected);
1192 }
1193
1194 #[test]
1195 #[should_panic]
1196 fn val_matches_ty_wrong_engine() {
1197 let e1 = Engine::default();
1198 let e2 = Engine::default();
1199
1200 let t1 = FuncType::new(&e1, None, None);
1201 let t2 = FuncType::new(&e2, None, None);
1202
1203 let mut s1 = Store::new(&e1, ());
1204 let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1205
1206 let _ = Val::FuncRef(Some(f)).matches_ty(
1208 &s1,
1209 &ValType::Ref(RefType::new(true, HeapType::ConcreteFunc(t2))),
1210 );
1211 }
1212
1213 #[test]
1214 #[should_panic]
1215 fn ref_matches_ty_wrong_engine() {
1216 let e1 = Engine::default();
1217 let e2 = Engine::default();
1218
1219 let t1 = FuncType::new(&e1, None, None);
1220 let t2 = FuncType::new(&e2, None, None);
1221
1222 let mut s1 = Store::new(&e1, ());
1223 let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1224
1225 let _ = Ref::Func(Some(f)).matches_ty(&s1, &RefType::new(true, HeapType::ConcreteFunc(t2)));
1227 }
1228}