wasmtime/runtime/gc/enabled/
eqref.rs1use crate::{
4 prelude::*,
5 runtime::vm::VMGcRef,
6 store::{AutoAssertNoGc, StoreOpaque},
7 AnyRef, ArrayRef, ArrayType, AsContext, GcRefImpl, GcRootIndex, HeapType, ManuallyRooted,
8 RefType, Rooted, StructRef, StructType, ValRaw, ValType, WasmTy, I31,
9};
10use core::mem::{self, MaybeUninit};
11use wasmtime_environ::VMGcKind;
12
13#[derive(Debug)]
90#[repr(transparent)]
91pub struct EqRef {
92 pub(super) inner: GcRootIndex,
93}
94
95impl From<Rooted<StructRef>> for Rooted<EqRef> {
96 #[inline]
97 fn from(s: Rooted<StructRef>) -> Self {
98 s.to_eqref()
99 }
100}
101
102impl From<ManuallyRooted<StructRef>> for ManuallyRooted<EqRef> {
103 #[inline]
104 fn from(s: ManuallyRooted<StructRef>) -> Self {
105 s.to_eqref()
106 }
107}
108
109impl From<Rooted<ArrayRef>> for Rooted<EqRef> {
110 #[inline]
111 fn from(s: Rooted<ArrayRef>) -> Self {
112 s.to_eqref()
113 }
114}
115
116impl From<ManuallyRooted<ArrayRef>> for ManuallyRooted<EqRef> {
117 #[inline]
118 fn from(s: ManuallyRooted<ArrayRef>) -> Self {
119 s.to_eqref()
120 }
121}
122
123unsafe impl GcRefImpl for EqRef {
124 #[allow(private_interfaces)]
125 fn transmute_ref(index: &GcRootIndex) -> &Self {
126 let me: &Self = unsafe { mem::transmute(index) };
128
129 assert!(matches!(
131 me,
132 Self {
133 inner: GcRootIndex { .. },
134 }
135 ));
136
137 me
138 }
139}
140
141impl Rooted<EqRef> {
142 #[inline]
144 pub fn to_anyref(self) -> Rooted<AnyRef> {
145 self.unchecked_cast()
146 }
147}
148
149impl ManuallyRooted<EqRef> {
150 #[inline]
152 pub fn to_anyref(self) -> ManuallyRooted<AnyRef> {
153 self.unchecked_cast()
154 }
155}
156
157impl EqRef {
158 pub(crate) fn from_cloned_gc_ref(
164 store: &mut AutoAssertNoGc<'_>,
165 gc_ref: VMGcRef,
166 ) -> Rooted<Self> {
167 debug_assert!(
168 gc_ref.is_i31()
169 || store
170 .unwrap_gc_store()
171 .header(&gc_ref)
172 .kind()
173 .matches(VMGcKind::EqRef)
174 );
175 Rooted::new(store, gc_ref)
176 }
177
178 #[inline]
179 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
180 self.inner.comes_from_same_store(store)
181 }
182
183 pub fn ty(&self, store: impl AsContext) -> Result<HeapType> {
193 self._ty(store.as_context().0)
194 }
195
196 pub(crate) fn _ty(&self, store: &StoreOpaque) -> Result<HeapType> {
197 let gc_ref = self.inner.try_gc_ref(store)?;
198 if gc_ref.is_i31() {
199 return Ok(HeapType::I31);
200 }
201
202 let header = store.gc_store()?.header(gc_ref);
203
204 if header.kind().matches(VMGcKind::StructRef) {
205 return Ok(HeapType::ConcreteStruct(
206 StructType::from_shared_type_index(store.engine(), header.ty().unwrap()),
207 ));
208 }
209
210 if header.kind().matches(VMGcKind::ArrayRef) {
211 return Ok(HeapType::ConcreteArray(ArrayType::from_shared_type_index(
212 store.engine(),
213 header.ty().unwrap(),
214 )));
215 }
216
217 unreachable!("no other kinds of `eqref`s")
218 }
219
220 pub fn matches_ty(&self, store: impl AsContext, ty: &HeapType) -> Result<bool> {
232 self._matches_ty(store.as_context().0, ty)
233 }
234
235 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<bool> {
236 assert!(self.comes_from_same_store(store));
237 Ok(self._ty(store)?.matches(ty))
238 }
239
240 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<()> {
241 if !self.comes_from_same_store(store) {
242 bail!("function used with wrong store");
243 }
244 if self._matches_ty(store, ty)? {
245 Ok(())
246 } else {
247 let actual_ty = self._ty(store)?;
248 bail!("type mismatch: expected `(ref {ty})`, found `(ref {actual_ty})`")
249 }
250 }
251
252 pub fn is_i31(&self, store: impl AsContext) -> Result<bool> {
262 self._is_i31(store.as_context().0)
263 }
264
265 pub(crate) fn _is_i31(&self, store: &StoreOpaque) -> Result<bool> {
266 assert!(self.comes_from_same_store(store));
267 let gc_ref = self.inner.try_gc_ref(store)?;
268 Ok(gc_ref.is_i31())
269 }
270
271 pub fn as_i31(&self, store: impl AsContext) -> Result<Option<I31>> {
285 self._as_i31(store.as_context().0)
286 }
287
288 pub(crate) fn _as_i31(&self, store: &StoreOpaque) -> Result<Option<I31>> {
289 assert!(self.comes_from_same_store(store));
290 let gc_ref = self.inner.try_gc_ref(store)?;
291 Ok(gc_ref.as_i31().map(Into::into))
292 }
293
294 pub fn unwrap_i31(&self, store: impl AsContext) -> Result<I31> {
306 Ok(self.as_i31(store)?.expect("EqRef::unwrap_i31 on non-i31"))
307 }
308
309 pub fn is_struct(&self, store: impl AsContext) -> Result<bool> {
319 self._is_struct(store.as_context().0)
320 }
321
322 pub(crate) fn _is_struct(&self, store: &StoreOpaque) -> Result<bool> {
323 let gc_ref = self.inner.try_gc_ref(store)?;
324 Ok(!gc_ref.is_i31() && store.gc_store()?.kind(gc_ref).matches(VMGcKind::StructRef))
325 }
326
327 pub fn as_struct(&self, store: impl AsContext) -> Result<Option<Rooted<StructRef>>> {
341 self._as_struct(store.as_context().0)
342 }
343
344 pub(crate) fn _as_struct(&self, store: &StoreOpaque) -> Result<Option<Rooted<StructRef>>> {
345 if self._is_struct(store)? {
346 Ok(Some(Rooted::from_gc_root_index(self.inner)))
347 } else {
348 Ok(None)
349 }
350 }
351
352 pub fn unwrap_struct(&self, store: impl AsContext) -> Result<Rooted<StructRef>> {
364 self._unwrap_struct(store.as_context().0)
365 }
366
367 pub(crate) fn _unwrap_struct(&self, store: &StoreOpaque) -> Result<Rooted<StructRef>> {
368 Ok(self
369 ._as_struct(store)?
370 .expect("EqRef::unwrap_struct on non-structref"))
371 }
372
373 pub fn is_array(&self, store: impl AsContext) -> Result<bool> {
383 self._is_array(store.as_context().0)
384 }
385
386 pub(crate) fn _is_array(&self, store: &StoreOpaque) -> Result<bool> {
387 let gc_ref = self.inner.try_gc_ref(store)?;
388 Ok(!gc_ref.is_i31() && store.gc_store()?.kind(gc_ref).matches(VMGcKind::ArrayRef))
389 }
390
391 pub fn as_array(&self, store: impl AsContext) -> Result<Option<Rooted<ArrayRef>>> {
405 self._as_array(store.as_context().0)
406 }
407
408 pub(crate) fn _as_array(&self, store: &StoreOpaque) -> Result<Option<Rooted<ArrayRef>>> {
409 if self._is_array(store)? {
410 Ok(Some(Rooted::from_gc_root_index(self.inner)))
411 } else {
412 Ok(None)
413 }
414 }
415
416 pub fn unwrap_array(&self, store: impl AsContext) -> Result<Rooted<ArrayRef>> {
428 self._unwrap_array(store.as_context().0)
429 }
430
431 pub(crate) fn _unwrap_array(&self, store: &StoreOpaque) -> Result<Rooted<ArrayRef>> {
432 Ok(self
433 ._as_array(store)?
434 .expect("EqRef::unwrap_array on non-arrayref"))
435 }
436}
437
438unsafe impl WasmTy for Rooted<EqRef> {
439 #[inline]
440 fn valtype() -> ValType {
441 ValType::Ref(RefType::new(false, HeapType::Eq))
442 }
443
444 #[inline]
445 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
446 self.comes_from_same_store(store)
447 }
448
449 #[inline]
450 fn dynamic_concrete_type_check(
451 &self,
452 store: &StoreOpaque,
453 _nullable: bool,
454 ty: &HeapType,
455 ) -> Result<()> {
456 self.ensure_matches_ty(store, ty)
457 }
458
459 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
460 self.wasm_ty_store(store, ptr, ValRaw::anyref)
461 }
462
463 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
464 Self::wasm_ty_load(store, ptr.get_anyref(), EqRef::from_cloned_gc_ref)
465 }
466}
467
468unsafe impl WasmTy for Option<Rooted<EqRef>> {
469 #[inline]
470 fn valtype() -> ValType {
471 ValType::EQREF
472 }
473
474 #[inline]
475 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
476 self.map_or(true, |x| x.comes_from_same_store(store))
477 }
478
479 #[inline]
480 fn dynamic_concrete_type_check(
481 &self,
482 store: &StoreOpaque,
483 nullable: bool,
484 ty: &HeapType,
485 ) -> Result<()> {
486 match self {
487 Some(s) => Rooted::<EqRef>::dynamic_concrete_type_check(s, store, nullable, ty),
488 None => {
489 ensure!(
490 nullable,
491 "expected a non-null reference, but found a null reference"
492 );
493 Ok(())
494 }
495 }
496 }
497
498 #[inline]
499 fn is_vmgcref_and_points_to_object(&self) -> bool {
500 self.is_some()
501 }
502
503 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
504 <Rooted<EqRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref)
505 }
506
507 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
508 <Rooted<EqRef>>::wasm_ty_option_load(store, ptr.get_anyref(), EqRef::from_cloned_gc_ref)
509 }
510}
511
512unsafe impl WasmTy for ManuallyRooted<EqRef> {
513 #[inline]
514 fn valtype() -> ValType {
515 ValType::Ref(RefType::new(false, HeapType::Eq))
516 }
517
518 #[inline]
519 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
520 self.comes_from_same_store(store)
521 }
522
523 #[inline]
524 fn dynamic_concrete_type_check(
525 &self,
526 store: &StoreOpaque,
527 _: bool,
528 ty: &HeapType,
529 ) -> Result<()> {
530 self.ensure_matches_ty(store, ty)
531 }
532
533 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
534 self.wasm_ty_store(store, ptr, ValRaw::anyref)
535 }
536
537 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
538 Self::wasm_ty_load(store, ptr.get_anyref(), EqRef::from_cloned_gc_ref)
539 }
540}
541
542unsafe impl WasmTy for Option<ManuallyRooted<EqRef>> {
543 #[inline]
544 fn valtype() -> ValType {
545 ValType::EQREF
546 }
547
548 #[inline]
549 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
550 self.as_ref()
551 .map_or(true, |x| x.comes_from_same_store(store))
552 }
553
554 #[inline]
555 fn dynamic_concrete_type_check(
556 &self,
557 store: &StoreOpaque,
558 nullable: bool,
559 ty: &HeapType,
560 ) -> Result<()> {
561 match self {
562 Some(s) => ManuallyRooted::<EqRef>::dynamic_concrete_type_check(s, store, nullable, ty),
563 None => {
564 ensure!(
565 nullable,
566 "expected a non-null reference, but found a null reference"
567 );
568 Ok(())
569 }
570 }
571 }
572
573 #[inline]
574 fn is_vmgcref_and_points_to_object(&self) -> bool {
575 self.is_some()
576 }
577
578 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
579 <ManuallyRooted<EqRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref)
580 }
581
582 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
583 <ManuallyRooted<EqRef>>::wasm_ty_option_load(
584 store,
585 ptr.get_anyref(),
586 EqRef::from_cloned_gc_ref,
587 )
588 }
589}