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(crate::format_err!(
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, mut store: impl AsContextMut) -> Result<ValRaw> {
269 let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
270 self.to_raw_(&mut store)
271 }
272
273 pub(crate) fn to_raw_(&self, store: &mut AutoAssertNoGc) -> Result<ValRaw> {
274 match self {
275 Val::I32(i) => Ok(ValRaw::i32(*i)),
276 Val::I64(i) => Ok(ValRaw::i64(*i)),
277 Val::F32(u) => Ok(ValRaw::f32(*u)),
278 Val::F64(u) => Ok(ValRaw::f64(*u)),
279 Val::V128(b) => Ok(ValRaw::v128(b.as_u128())),
280 Val::ExternRef(e) => Ok(ValRaw::externref(match e {
281 None => 0,
282 Some(e) => e._to_raw(store)?,
283 })),
284 Val::AnyRef(e) => Ok(ValRaw::anyref(match e {
285 None => 0,
286 Some(e) => e._to_raw(store)?,
287 })),
288 Val::ExnRef(e) => Ok(ValRaw::exnref(match e {
289 None => 0,
290 Some(e) => e._to_raw(store)?,
291 })),
292 Val::FuncRef(f) => Ok(ValRaw::funcref(match f {
293 Some(f) => f.to_raw_(store),
294 None => ptr::null_mut(),
295 })),
296 Val::ContRef(_) => {
297 Err(crate::format_err!(
299 "continuation references not yet supported in to_raw conversion"
300 ))
301 }
302 }
303 }
304
305 pub unsafe fn from_raw(mut store: impl AsContextMut, raw: ValRaw, ty: ValType) -> Val {
313 let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
314 unsafe { Self::_from_raw(&mut store, raw, &ty) }
316 }
317
318 pub(crate) unsafe fn _from_raw(
320 store: &mut AutoAssertNoGc<'_>,
321 raw: ValRaw,
322 ty: &ValType,
323 ) -> Val {
324 match ty {
325 ValType::I32 => Val::I32(raw.get_i32()),
326 ValType::I64 => Val::I64(raw.get_i64()),
327 ValType::F32 => Val::F32(raw.get_f32()),
328 ValType::F64 => Val::F64(raw.get_f64()),
329 ValType::V128 => Val::V128(raw.get_v128().into()),
330 ValType::Ref(ref_ty) => {
331 let ref_ = match ref_ty.heap_type() {
332 HeapType::Func | HeapType::ConcreteFunc(_) => unsafe {
335 Func::_from_raw(store, raw.get_funcref()).into()
336 },
337
338 HeapType::NoFunc => Ref::Func(None),
339
340 HeapType::NoCont | HeapType::ConcreteCont(_) | HeapType::Cont => {
341 unimplemented!()
343 }
344
345 HeapType::Extern => ExternRef::_from_raw(store, raw.get_externref()).into(),
346
347 HeapType::NoExtern => Ref::Extern(None),
348
349 HeapType::Any
350 | HeapType::Eq
351 | HeapType::I31
352 | HeapType::Array
353 | HeapType::ConcreteArray(_)
354 | HeapType::Struct
355 | HeapType::ConcreteStruct(_) => {
356 AnyRef::_from_raw(store, raw.get_anyref()).into()
357 }
358
359 HeapType::Exn | HeapType::ConcreteExn(_) => {
360 ExnRef::_from_raw(store, raw.get_exnref()).into()
361 }
362 HeapType::NoExn => Ref::Exn(None),
363
364 HeapType::None => Ref::Any(None),
365 };
366 assert!(
367 ref_ty.is_nullable() || !ref_.is_null(),
368 "if the type is not nullable, we shouldn't get null; got \
369 type = {ref_ty}, ref = {ref_:?}"
370 );
371 ref_.into()
372 }
373 }
374 }
375
376 accessors! {
377 e
378 (I32(i32) i32 unwrap_i32 *e)
379 (I64(i64) i64 unwrap_i64 *e)
380 (F32(f32) f32 unwrap_f32 f32::from_bits(*e))
381 (F64(f64) f64 unwrap_f64 f64::from_bits(*e))
382 (FuncRef(Option<&Func>) func_ref unwrap_func_ref e.as_ref())
383 (ExternRef(Option<&Rooted<ExternRef>>) extern_ref unwrap_extern_ref e.as_ref())
384 (AnyRef(Option<&Rooted<AnyRef>>) any_ref unwrap_any_ref e.as_ref())
385 (V128(V128) v128 unwrap_v128 *e)
386 }
387
388 #[inline]
390 pub fn ref_(self) -> Option<Ref> {
391 match self {
392 Val::FuncRef(f) => Some(Ref::Func(f)),
393 Val::ExternRef(e) => Some(Ref::Extern(e)),
394 Val::AnyRef(a) => Some(Ref::Any(a)),
395 Val::ExnRef(e) => Some(Ref::Exn(e)),
396 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => None,
397 Val::ContRef(_) => None, }
399 }
400
401 #[inline]
409 pub fn externref(&self) -> Option<Option<&Rooted<ExternRef>>> {
410 match self {
411 Val::ExternRef(None) => Some(None),
412 Val::ExternRef(Some(e)) => Some(Some(e)),
413 _ => None,
414 }
415 }
416
417 #[inline]
428 pub fn unwrap_externref(&self) -> Option<&Rooted<ExternRef>> {
429 self.externref().expect("expected externref")
430 }
431
432 #[inline]
440 pub fn anyref(&self) -> Option<Option<&Rooted<AnyRef>>> {
441 match self {
442 Val::AnyRef(None) => Some(None),
443 Val::AnyRef(Some(e)) => Some(Some(e)),
444 _ => None,
445 }
446 }
447
448 #[inline]
459 pub fn unwrap_anyref(&self) -> Option<&Rooted<AnyRef>> {
460 self.anyref().expect("expected anyref")
461 }
462
463 #[inline]
471 pub fn exnref(&self) -> Option<Option<&Rooted<ExnRef>>> {
472 match self {
473 Val::ExnRef(None) => Some(None),
474 Val::ExnRef(Some(e)) => Some(Some(e)),
475 _ => None,
476 }
477 }
478
479 #[inline]
490 pub fn unwrap_exnref(&self) -> Option<&Rooted<ExnRef>> {
491 self.exnref().expect("expected exnref")
492 }
493
494 #[inline]
502 pub fn funcref(&self) -> Option<Option<&Func>> {
503 match self {
504 Val::FuncRef(None) => Some(None),
505 Val::FuncRef(Some(f)) => Some(Some(f)),
506 _ => None,
507 }
508 }
509
510 #[inline]
521 pub fn unwrap_funcref(&self) -> Option<&Func> {
522 self.funcref().expect("expected funcref")
523 }
524
525 #[inline]
526 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
527 match self {
528 Val::FuncRef(Some(f)) => f.comes_from_same_store(store),
529 Val::FuncRef(None) => true,
530
531 Val::ExternRef(Some(x)) => x.comes_from_same_store(store),
532 Val::ExternRef(None) => true,
533
534 Val::AnyRef(Some(a)) => a.comes_from_same_store(store),
535 Val::AnyRef(None) => true,
536
537 Val::ExnRef(Some(e)) => e.comes_from_same_store(store),
538 Val::ExnRef(None) => true,
539
540 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true,
544
545 Val::ContRef(_) => true, }
548 }
549}
550
551impl From<i32> for Val {
552 #[inline]
553 fn from(val: i32) -> Val {
554 Val::I32(val)
555 }
556}
557
558impl From<i64> for Val {
559 #[inline]
560 fn from(val: i64) -> Val {
561 Val::I64(val)
562 }
563}
564
565impl From<f32> for Val {
566 #[inline]
567 fn from(val: f32) -> Val {
568 Val::F32(val.to_bits())
569 }
570}
571
572impl From<f64> for Val {
573 #[inline]
574 fn from(val: f64) -> Val {
575 Val::F64(val.to_bits())
576 }
577}
578
579impl From<Ref> for Val {
580 #[inline]
581 fn from(val: Ref) -> Val {
582 match val {
583 Ref::Extern(e) => Val::ExternRef(e),
584 Ref::Func(f) => Val::FuncRef(f),
585 Ref::Any(a) => Val::AnyRef(a),
586 Ref::Exn(e) => Val::ExnRef(e),
587 }
588 }
589}
590
591impl From<Rooted<ExternRef>> for Val {
592 #[inline]
593 fn from(val: Rooted<ExternRef>) -> Val {
594 Val::ExternRef(Some(val))
595 }
596}
597
598impl From<Option<Rooted<ExternRef>>> for Val {
599 #[inline]
600 fn from(val: Option<Rooted<ExternRef>>) -> Val {
601 Val::ExternRef(val)
602 }
603}
604
605impl From<Rooted<AnyRef>> for Val {
606 #[inline]
607 fn from(val: Rooted<AnyRef>) -> Val {
608 Val::AnyRef(Some(val))
609 }
610}
611
612impl From<Option<Rooted<AnyRef>>> for Val {
613 #[inline]
614 fn from(val: Option<Rooted<AnyRef>>) -> Val {
615 Val::AnyRef(val)
616 }
617}
618
619impl From<Rooted<StructRef>> for Val {
620 #[inline]
621 fn from(val: Rooted<StructRef>) -> Val {
622 Val::AnyRef(Some(val.into()))
623 }
624}
625
626impl From<Option<Rooted<StructRef>>> for Val {
627 #[inline]
628 fn from(val: Option<Rooted<StructRef>>) -> Val {
629 Val::AnyRef(val.map(Into::into))
630 }
631}
632
633impl From<Rooted<ArrayRef>> for Val {
634 #[inline]
635 fn from(val: Rooted<ArrayRef>) -> Val {
636 Val::AnyRef(Some(val.into()))
637 }
638}
639
640impl From<Option<Rooted<ArrayRef>>> for Val {
641 #[inline]
642 fn from(val: Option<Rooted<ArrayRef>>) -> Val {
643 Val::AnyRef(val.map(Into::into))
644 }
645}
646
647impl From<Rooted<ExnRef>> for Val {
648 #[inline]
649 fn from(val: Rooted<ExnRef>) -> Val {
650 Val::ExnRef(Some(val))
651 }
652}
653
654impl From<Option<Rooted<ExnRef>>> for Val {
655 #[inline]
656 fn from(val: Option<Rooted<ExnRef>>) -> Val {
657 Val::ExnRef(val)
658 }
659}
660
661impl From<Func> for Val {
662 #[inline]
663 fn from(val: Func) -> Val {
664 Val::FuncRef(Some(val))
665 }
666}
667
668impl From<Option<Func>> for Val {
669 #[inline]
670 fn from(val: Option<Func>) -> Val {
671 Val::FuncRef(val)
672 }
673}
674
675impl From<u128> for Val {
676 #[inline]
677 fn from(val: u128) -> Val {
678 Val::V128(val.into())
679 }
680}
681
682impl From<V128> for Val {
683 #[inline]
684 fn from(val: V128) -> Val {
685 Val::V128(val)
686 }
687}
688
689#[derive(Debug, Clone)]
714pub enum Ref {
715 Func(Option<Func>),
752
753 Extern(Option<Rooted<ExternRef>>),
763
764 Any(Option<Rooted<AnyRef>>),
773
774 Exn(Option<Rooted<ExnRef>>),
781}
782
783impl From<Func> for Ref {
784 #[inline]
785 fn from(f: Func) -> Ref {
786 Ref::Func(Some(f))
787 }
788}
789
790impl From<Option<Func>> for Ref {
791 #[inline]
792 fn from(f: Option<Func>) -> Ref {
793 Ref::Func(f)
794 }
795}
796
797impl From<Rooted<ExternRef>> for Ref {
798 #[inline]
799 fn from(e: Rooted<ExternRef>) -> Ref {
800 Ref::Extern(Some(e))
801 }
802}
803
804impl From<Option<Rooted<ExternRef>>> for Ref {
805 #[inline]
806 fn from(e: Option<Rooted<ExternRef>>) -> Ref {
807 Ref::Extern(e)
808 }
809}
810
811impl From<Rooted<AnyRef>> for Ref {
812 #[inline]
813 fn from(e: Rooted<AnyRef>) -> Ref {
814 Ref::Any(Some(e))
815 }
816}
817
818impl From<Option<Rooted<AnyRef>>> for Ref {
819 #[inline]
820 fn from(e: Option<Rooted<AnyRef>>) -> Ref {
821 Ref::Any(e)
822 }
823}
824
825impl From<Rooted<StructRef>> for Ref {
826 #[inline]
827 fn from(e: Rooted<StructRef>) -> Ref {
828 Ref::Any(Some(e.into()))
829 }
830}
831
832impl From<Option<Rooted<StructRef>>> for Ref {
833 #[inline]
834 fn from(e: Option<Rooted<StructRef>>) -> Ref {
835 Ref::Any(e.map(Into::into))
836 }
837}
838
839impl From<Rooted<ArrayRef>> for Ref {
840 #[inline]
841 fn from(e: Rooted<ArrayRef>) -> Ref {
842 Ref::Any(Some(e.into()))
843 }
844}
845
846impl From<Option<Rooted<ArrayRef>>> for Ref {
847 #[inline]
848 fn from(e: Option<Rooted<ArrayRef>>) -> Ref {
849 Ref::Any(e.map(Into::into))
850 }
851}
852
853impl From<Rooted<ExnRef>> for Ref {
854 #[inline]
855 fn from(e: Rooted<ExnRef>) -> Ref {
856 Ref::Exn(Some(e))
857 }
858}
859
860impl From<Option<Rooted<ExnRef>>> for Ref {
861 #[inline]
862 fn from(e: Option<Rooted<ExnRef>>) -> Ref {
863 Ref::Exn(e)
864 }
865}
866
867impl Ref {
868 #[inline]
870 pub fn null(heap_type: &HeapType) -> Self {
871 match heap_type.top() {
872 HeapType::Any => Ref::Any(None),
873 HeapType::Extern => Ref::Extern(None),
874 HeapType::Func => Ref::Func(None),
875 HeapType::Exn => Ref::Exn(None),
876 ty => unreachable!("not a heap type: {ty:?}"),
877 }
878 }
879
880 #[inline]
882 pub fn is_null(&self) -> bool {
883 match self {
884 Ref::Any(None) | Ref::Extern(None) | Ref::Func(None) | Ref::Exn(None) => true,
885 Ref::Any(Some(_)) | Ref::Extern(Some(_)) | Ref::Func(Some(_)) | Ref::Exn(Some(_)) => {
886 false
887 }
888 }
889 }
890
891 #[inline]
893 pub fn is_non_null(&self) -> bool {
894 !self.is_null()
895 }
896
897 #[inline]
899 pub fn is_extern(&self) -> bool {
900 matches!(self, Ref::Extern(_))
901 }
902
903 #[inline]
912 pub fn as_extern(&self) -> Option<Option<&Rooted<ExternRef>>> {
913 match self {
914 Ref::Extern(e) => Some(e.as_ref()),
915 _ => None,
916 }
917 }
918
919 #[inline]
926 pub fn unwrap_extern(&self) -> Option<&Rooted<ExternRef>> {
927 self.as_extern()
928 .expect("Ref::unwrap_extern on non-extern reference")
929 }
930
931 #[inline]
933 pub fn is_any(&self) -> bool {
934 matches!(self, Ref::Any(_))
935 }
936
937 #[inline]
946 pub fn as_any(&self) -> Option<Option<&Rooted<AnyRef>>> {
947 match self {
948 Ref::Any(e) => Some(e.as_ref()),
949 _ => None,
950 }
951 }
952
953 #[inline]
960 pub fn unwrap_any(&self) -> Option<&Rooted<AnyRef>> {
961 self.as_any().expect("Ref::unwrap_any on non-any reference")
962 }
963
964 #[inline]
966 pub fn is_exn(&self) -> bool {
967 matches!(self, Ref::Exn(_))
968 }
969
970 #[inline]
979 pub fn as_exn(&self) -> Option<Option<&Rooted<ExnRef>>> {
980 match self {
981 Ref::Exn(e) => Some(e.as_ref()),
982 _ => None,
983 }
984 }
985
986 #[inline]
993 pub fn unwrap_exn(&self) -> Option<&Rooted<ExnRef>> {
994 self.as_exn().expect("Ref::unwrap_exn on non-exn reference")
995 }
996
997 #[inline]
999 pub fn is_func(&self) -> bool {
1000 matches!(self, Ref::Func(_))
1001 }
1002
1003 #[inline]
1012 pub fn as_func(&self) -> Option<Option<&Func>> {
1013 match self {
1014 Ref::Func(f) => Some(f.as_ref()),
1015 _ => None,
1016 }
1017 }
1018
1019 #[inline]
1026 pub fn unwrap_func(&self) -> Option<&Func> {
1027 self.as_func()
1028 .expect("Ref::unwrap_func on non-func reference")
1029 }
1030
1031 pub fn ty(&self, store: impl AsContext) -> Result<RefType> {
1041 self.load_ty(&store.as_context().0)
1042 }
1043
1044 pub(crate) fn load_ty(&self, store: &StoreOpaque) -> Result<RefType> {
1045 assert!(self.comes_from_same_store(store));
1046 Ok(RefType::new(
1047 self.is_null(),
1048 match self {
1052 Ref::Extern(None) => HeapType::NoExtern,
1053 Ref::Extern(Some(_)) => HeapType::Extern,
1054
1055 Ref::Func(None) => HeapType::NoFunc,
1056 Ref::Func(Some(f)) => HeapType::ConcreteFunc(f.load_ty(store)),
1057
1058 Ref::Any(None) => HeapType::None,
1059 Ref::Any(Some(a)) => a._ty(store)?,
1060
1061 Ref::Exn(None) => HeapType::None,
1062 Ref::Exn(Some(e)) => e._ty(store)?.into(),
1063 },
1064 ))
1065 }
1066
1067 pub fn matches_ty(&self, store: impl AsContext, ty: &RefType) -> Result<bool> {
1075 self._matches_ty(&store.as_context().0, ty)
1076 }
1077
1078 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<bool> {
1079 assert!(self.comes_from_same_store(store));
1080 assert!(ty.comes_from_same_engine(store.engine()));
1081 if self.is_null() && !ty.is_nullable() {
1082 return Ok(false);
1083 }
1084 Ok(match (self, ty.heap_type()) {
1085 (Ref::Extern(_), HeapType::Extern) => true,
1086 (Ref::Extern(None), HeapType::NoExtern) => true,
1087 (Ref::Extern(_), _) => false,
1088
1089 (Ref::Func(_), HeapType::Func) => true,
1090 (Ref::Func(None), HeapType::NoFunc | HeapType::ConcreteFunc(_)) => true,
1091 (Ref::Func(Some(f)), HeapType::ConcreteFunc(func_ty)) => f._matches_ty(store, func_ty),
1092 (Ref::Func(_), _) => false,
1093
1094 (Ref::Any(_), HeapType::Any) => true,
1095 (Ref::Any(Some(a)), HeapType::I31) => a._is_i31(store)?,
1096 (Ref::Any(Some(a)), HeapType::Struct) => a._is_struct(store)?,
1097 (Ref::Any(Some(a)), HeapType::ConcreteStruct(_ty)) => match a._as_struct(store)? {
1098 None => false,
1099 Some(s) => s._matches_ty(store, _ty)?,
1100 },
1101 (Ref::Any(Some(a)), HeapType::Eq) => a._is_eqref(store)?,
1102 (Ref::Any(Some(a)), HeapType::Array) => a._is_array(store)?,
1103 (Ref::Any(Some(a)), HeapType::ConcreteArray(_ty)) => match a._as_array(store)? {
1104 None => false,
1105 Some(a) => a._matches_ty(store, _ty)?,
1106 },
1107 (
1108 Ref::Any(None),
1109 HeapType::None
1110 | HeapType::I31
1111 | HeapType::ConcreteStruct(_)
1112 | HeapType::Struct
1113 | HeapType::ConcreteArray(_)
1114 | HeapType::Array
1115 | HeapType::Eq,
1116 ) => true,
1117 (Ref::Any(_), _) => false,
1118
1119 (Ref::Exn(_), HeapType::Exn) => true,
1120 (Ref::Exn(None), HeapType::NoExn | HeapType::ConcreteExn(_)) => true,
1121 (Ref::Exn(Some(e)), HeapType::ConcreteExn(_)) => {
1122 e._matches_ty(store, &ty.heap_type())?
1123 }
1124 (Ref::Exn(_), _) => false,
1125 })
1126 }
1127
1128 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<()> {
1129 if !self.comes_from_same_store(store) {
1130 bail!("reference used with wrong store")
1131 }
1132 if !ty.comes_from_same_engine(store.engine()) {
1133 bail!("type used with wrong engine")
1134 }
1135 if self._matches_ty(store, ty)? {
1136 Ok(())
1137 } else {
1138 let actual_ty = self.load_ty(store)?;
1139 bail!("type mismatch: expected {ty}, found {actual_ty}")
1140 }
1141 }
1142
1143 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
1144 match self {
1145 Ref::Func(Some(f)) => f.comes_from_same_store(store),
1146 Ref::Func(None) => true,
1147 Ref::Extern(Some(x)) => x.comes_from_same_store(store),
1148 Ref::Extern(None) => true,
1149 Ref::Any(Some(a)) => a.comes_from_same_store(store),
1150 Ref::Any(None) => true,
1151 Ref::Exn(Some(e)) => e.comes_from_same_store(store),
1152 Ref::Exn(None) => true,
1153 }
1154 }
1155}
1156
1157#[cfg(test)]
1158mod tests {
1159 use crate::*;
1160
1161 #[test]
1162 fn size_of_val() {
1163 let expected = if cfg!(target_arch = "x86_64")
1166 || cfg!(target_arch = "aarch64")
1167 || cfg!(target_arch = "s390x")
1168 || cfg!(target_arch = "riscv64")
1169 || cfg!(target_arch = "arm")
1170 {
1171 24
1172 } else if cfg!(target_arch = "x86") {
1173 20
1174 } else {
1175 panic!("unsupported architecture")
1176 };
1177 assert_eq!(std::mem::size_of::<Val>(), expected);
1178 }
1179
1180 #[test]
1181 fn size_of_ref() {
1182 let expected = if cfg!(target_arch = "x86_64")
1185 || cfg!(target_arch = "aarch64")
1186 || cfg!(target_arch = "s390x")
1187 || cfg!(target_arch = "riscv64")
1188 || cfg!(target_arch = "arm")
1189 {
1190 24
1191 } else if cfg!(target_arch = "x86") {
1192 20
1193 } else {
1194 panic!("unsupported architecture")
1195 };
1196 assert_eq!(std::mem::size_of::<Ref>(), expected);
1197 }
1198
1199 #[test]
1200 #[should_panic]
1201 fn val_matches_ty_wrong_engine() {
1202 let e1 = Engine::default();
1203 let e2 = Engine::default();
1204
1205 let t1 = FuncType::new(&e1, None, None);
1206 let t2 = FuncType::new(&e2, None, None);
1207
1208 let mut s1 = Store::new(&e1, ());
1209 let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1210
1211 let _ = Val::FuncRef(Some(f)).matches_ty(
1213 &s1,
1214 &ValType::Ref(RefType::new(true, HeapType::ConcreteFunc(t2))),
1215 );
1216 }
1217
1218 #[test]
1219 #[should_panic]
1220 fn ref_matches_ty_wrong_engine() {
1221 let e1 = Engine::default();
1222 let e2 = Engine::default();
1223
1224 let t1 = FuncType::new(&e1, None, None);
1225 let t2 = FuncType::new(&e2, None, None);
1226
1227 let mut s1 = Store::new(&e1, ());
1228 let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(()));
1229
1230 let _ = Ref::Func(Some(f)).matches_ty(&s1, &RefType::new(true, HeapType::ConcreteFunc(t2)));
1232 }
1233}