wasmtime/runtime/gc/enabled/
eqref.rs1use crate::{
4 AnyRef, ArrayRef, ArrayType, AsContext, GcRefImpl, GcRootIndex, HeapType, I31, ManuallyRooted,
5 RefType, Rooted, StructRef, StructType, ValRaw, ValType, WasmTy,
6 prelude::*,
7 runtime::vm::VMGcRef,
8 store::{AutoAssertNoGc, StoreOpaque},
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 fn transmute_ref(index: &GcRootIndex) -> &Self {
125 let me: &Self = unsafe { mem::transmute(index) };
127
128 assert!(matches!(
130 me,
131 Self {
132 inner: GcRootIndex { .. },
133 }
134 ));
135
136 me
137 }
138}
139
140impl Rooted<EqRef> {
141 #[inline]
143 pub fn to_anyref(self) -> Rooted<AnyRef> {
144 self.unchecked_cast()
145 }
146}
147
148impl ManuallyRooted<EqRef> {
149 #[inline]
151 pub fn to_anyref(self) -> ManuallyRooted<AnyRef> {
152 self.unchecked_cast()
153 }
154}
155
156impl EqRef {
157 pub(crate) fn from_cloned_gc_ref(
163 store: &mut AutoAssertNoGc<'_>,
164 gc_ref: VMGcRef,
165 ) -> Rooted<Self> {
166 debug_assert!(
167 gc_ref.is_i31()
168 || store
169 .unwrap_gc_store()
170 .header(&gc_ref)
171 .kind()
172 .matches(VMGcKind::EqRef)
173 );
174 Rooted::new(store, gc_ref)
175 }
176
177 #[inline]
178 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
179 self.inner.comes_from_same_store(store)
180 }
181
182 pub fn ty(&self, store: impl AsContext) -> Result<HeapType> {
192 self._ty(store.as_context().0)
193 }
194
195 pub(crate) fn _ty(&self, store: &StoreOpaque) -> Result<HeapType> {
196 let gc_ref = self.inner.try_gc_ref(store)?;
197 if gc_ref.is_i31() {
198 return Ok(HeapType::I31);
199 }
200
201 let header = store.require_gc_store()?.header(gc_ref);
202
203 if header.kind().matches(VMGcKind::StructRef) {
204 return Ok(HeapType::ConcreteStruct(
205 StructType::from_shared_type_index(store.engine(), header.ty().unwrap()),
206 ));
207 }
208
209 if header.kind().matches(VMGcKind::ArrayRef) {
210 return Ok(HeapType::ConcreteArray(ArrayType::from_shared_type_index(
211 store.engine(),
212 header.ty().unwrap(),
213 )));
214 }
215
216 unreachable!("no other kinds of `eqref`s")
217 }
218
219 pub fn matches_ty(&self, store: impl AsContext, ty: &HeapType) -> Result<bool> {
231 self._matches_ty(store.as_context().0, ty)
232 }
233
234 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<bool> {
235 assert!(self.comes_from_same_store(store));
236 Ok(self._ty(store)?.matches(ty))
237 }
238
239 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &HeapType) -> Result<()> {
240 if !self.comes_from_same_store(store) {
241 bail!("function used with wrong store");
242 }
243 if self._matches_ty(store, ty)? {
244 Ok(())
245 } else {
246 let actual_ty = self._ty(store)?;
247 bail!("type mismatch: expected `(ref {ty})`, found `(ref {actual_ty})`")
248 }
249 }
250
251 pub fn is_i31(&self, store: impl AsContext) -> Result<bool> {
261 self._is_i31(store.as_context().0)
262 }
263
264 pub(crate) fn _is_i31(&self, store: &StoreOpaque) -> Result<bool> {
265 assert!(self.comes_from_same_store(store));
266 let gc_ref = self.inner.try_gc_ref(store)?;
267 Ok(gc_ref.is_i31())
268 }
269
270 pub fn as_i31(&self, store: impl AsContext) -> Result<Option<I31>> {
284 self._as_i31(store.as_context().0)
285 }
286
287 pub(crate) fn _as_i31(&self, store: &StoreOpaque) -> Result<Option<I31>> {
288 assert!(self.comes_from_same_store(store));
289 let gc_ref = self.inner.try_gc_ref(store)?;
290 Ok(gc_ref.as_i31().map(Into::into))
291 }
292
293 pub fn unwrap_i31(&self, store: impl AsContext) -> Result<I31> {
305 Ok(self.as_i31(store)?.expect("EqRef::unwrap_i31 on non-i31"))
306 }
307
308 pub fn is_struct(&self, store: impl AsContext) -> Result<bool> {
318 self._is_struct(store.as_context().0)
319 }
320
321 pub(crate) fn _is_struct(&self, store: &StoreOpaque) -> Result<bool> {
322 let gc_ref = self.inner.try_gc_ref(store)?;
323 Ok(!gc_ref.is_i31()
324 && store
325 .require_gc_store()?
326 .kind(gc_ref)
327 .matches(VMGcKind::StructRef))
328 }
329
330 pub fn as_struct(&self, store: impl AsContext) -> Result<Option<Rooted<StructRef>>> {
344 self._as_struct(store.as_context().0)
345 }
346
347 pub(crate) fn _as_struct(&self, store: &StoreOpaque) -> Result<Option<Rooted<StructRef>>> {
348 if self._is_struct(store)? {
349 Ok(Some(Rooted::from_gc_root_index(self.inner)))
350 } else {
351 Ok(None)
352 }
353 }
354
355 pub fn unwrap_struct(&self, store: impl AsContext) -> Result<Rooted<StructRef>> {
367 self._unwrap_struct(store.as_context().0)
368 }
369
370 pub(crate) fn _unwrap_struct(&self, store: &StoreOpaque) -> Result<Rooted<StructRef>> {
371 Ok(self
372 ._as_struct(store)?
373 .expect("EqRef::unwrap_struct on non-structref"))
374 }
375
376 pub fn is_array(&self, store: impl AsContext) -> Result<bool> {
386 self._is_array(store.as_context().0)
387 }
388
389 pub(crate) fn _is_array(&self, store: &StoreOpaque) -> Result<bool> {
390 let gc_ref = self.inner.try_gc_ref(store)?;
391 Ok(!gc_ref.is_i31()
392 && store
393 .require_gc_store()?
394 .kind(gc_ref)
395 .matches(VMGcKind::ArrayRef))
396 }
397
398 pub fn as_array(&self, store: impl AsContext) -> Result<Option<Rooted<ArrayRef>>> {
412 self._as_array(store.as_context().0)
413 }
414
415 pub(crate) fn _as_array(&self, store: &StoreOpaque) -> Result<Option<Rooted<ArrayRef>>> {
416 if self._is_array(store)? {
417 Ok(Some(Rooted::from_gc_root_index(self.inner)))
418 } else {
419 Ok(None)
420 }
421 }
422
423 pub fn unwrap_array(&self, store: impl AsContext) -> Result<Rooted<ArrayRef>> {
435 self._unwrap_array(store.as_context().0)
436 }
437
438 pub(crate) fn _unwrap_array(&self, store: &StoreOpaque) -> Result<Rooted<ArrayRef>> {
439 Ok(self
440 ._as_array(store)?
441 .expect("EqRef::unwrap_array on non-arrayref"))
442 }
443}
444
445unsafe impl WasmTy for Rooted<EqRef> {
446 #[inline]
447 fn valtype() -> ValType {
448 ValType::Ref(RefType::new(false, HeapType::Eq))
449 }
450
451 #[inline]
452 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
453 self.comes_from_same_store(store)
454 }
455
456 #[inline]
457 fn dynamic_concrete_type_check(
458 &self,
459 store: &StoreOpaque,
460 _nullable: bool,
461 ty: &HeapType,
462 ) -> Result<()> {
463 self.ensure_matches_ty(store, ty)
464 }
465
466 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
467 self.wasm_ty_store(store, ptr, ValRaw::anyref)
468 }
469
470 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
471 Self::wasm_ty_load(store, ptr.get_anyref(), EqRef::from_cloned_gc_ref)
472 }
473}
474
475unsafe impl WasmTy for Option<Rooted<EqRef>> {
476 #[inline]
477 fn valtype() -> ValType {
478 ValType::EQREF
479 }
480
481 #[inline]
482 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
483 self.map_or(true, |x| x.comes_from_same_store(store))
484 }
485
486 #[inline]
487 fn dynamic_concrete_type_check(
488 &self,
489 store: &StoreOpaque,
490 nullable: bool,
491 ty: &HeapType,
492 ) -> Result<()> {
493 match self {
494 Some(s) => Rooted::<EqRef>::dynamic_concrete_type_check(s, store, nullable, ty),
495 None => {
496 ensure!(
497 nullable,
498 "expected a non-null reference, but found a null reference"
499 );
500 Ok(())
501 }
502 }
503 }
504
505 #[inline]
506 fn is_vmgcref_and_points_to_object(&self) -> bool {
507 self.is_some()
508 }
509
510 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
511 <Rooted<EqRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref)
512 }
513
514 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
515 <Rooted<EqRef>>::wasm_ty_option_load(store, ptr.get_anyref(), EqRef::from_cloned_gc_ref)
516 }
517}
518
519unsafe impl WasmTy for ManuallyRooted<EqRef> {
520 #[inline]
521 fn valtype() -> ValType {
522 ValType::Ref(RefType::new(false, HeapType::Eq))
523 }
524
525 #[inline]
526 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
527 self.comes_from_same_store(store)
528 }
529
530 #[inline]
531 fn dynamic_concrete_type_check(
532 &self,
533 store: &StoreOpaque,
534 _: bool,
535 ty: &HeapType,
536 ) -> Result<()> {
537 self.ensure_matches_ty(store, ty)
538 }
539
540 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
541 self.wasm_ty_store(store, ptr, ValRaw::anyref)
542 }
543
544 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
545 Self::wasm_ty_load(store, ptr.get_anyref(), EqRef::from_cloned_gc_ref)
546 }
547}
548
549unsafe impl WasmTy for Option<ManuallyRooted<EqRef>> {
550 #[inline]
551 fn valtype() -> ValType {
552 ValType::EQREF
553 }
554
555 #[inline]
556 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
557 self.as_ref()
558 .map_or(true, |x| x.comes_from_same_store(store))
559 }
560
561 #[inline]
562 fn dynamic_concrete_type_check(
563 &self,
564 store: &StoreOpaque,
565 nullable: bool,
566 ty: &HeapType,
567 ) -> Result<()> {
568 match self {
569 Some(s) => ManuallyRooted::<EqRef>::dynamic_concrete_type_check(s, store, nullable, ty),
570 None => {
571 ensure!(
572 nullable,
573 "expected a non-null reference, but found a null reference"
574 );
575 Ok(())
576 }
577 }
578 }
579
580 #[inline]
581 fn is_vmgcref_and_points_to_object(&self) -> bool {
582 self.is_some()
583 }
584
585 fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
586 <ManuallyRooted<EqRef>>::wasm_ty_option_store(self, store, ptr, ValRaw::anyref)
587 }
588
589 unsafe fn load(store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
590 <ManuallyRooted<EqRef>>::wasm_ty_option_load(
591 store,
592 ptr.get_anyref(),
593 EqRef::from_cloned_gc_ref,
594 )
595 }
596}