dusk_wasmtime/runtime/gc/enabled/
anyref.rs1use crate::{
4 store::{AutoAssertNoGc, StoreOpaque},
5 AsContext, AsContextMut, FuncType, GcRefImpl, GcRootIndex, HeapType, ManuallyRooted, RefType,
6 Result, RootSet, Rooted, ValRaw, ValType, WasmTy, I31,
7};
8use std::num::NonZeroU64;
9use wasmtime_runtime::VMGcRef;
10
11#[derive(Debug)]
90#[repr(transparent)]
91pub struct AnyRef {
92 inner: GcRootIndex,
93}
94
95unsafe impl GcRefImpl for AnyRef {
96 #[allow(private_interfaces)]
97 fn transmute_ref(index: &GcRootIndex) -> &Self {
98 let me: &Self = unsafe { std::mem::transmute(index) };
100
101 assert!(matches!(
103 me,
104 Self {
105 inner: GcRootIndex { .. },
106 }
107 ));
108
109 me
110 }
111}
112
113impl AnyRef {
114 pub fn from_i31(mut store: impl AsContextMut, value: I31) -> Rooted<Self> {
132 let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
133 Self::_from_i31(&mut store, value)
134 }
135
136 pub(crate) fn _from_i31(store: &mut AutoAssertNoGc<'_>, value: I31) -> Rooted<Self> {
137 let gc_ref = VMGcRef::from_i31(value.runtime_i31());
138 Rooted::new(store, gc_ref)
139 }
140
141 pub unsafe fn from_raw(mut store: impl AsContextMut, raw: u32) -> Option<Rooted<Self>> {
170 let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
171 let gc_ref = VMGcRef::from_raw_u32(raw)?;
172 Some(Self::from_cloned_gc_ref(&mut store, gc_ref))
173 }
174
175 pub(crate) fn from_cloned_gc_ref(
181 store: &mut AutoAssertNoGc<'_>,
182 gc_ref: VMGcRef,
183 ) -> Rooted<Self> {
184 assert!(gc_ref.is_i31());
185 assert!(VMGcRef::ONLY_EXTERN_REF_AND_I31);
186 Rooted::new(store, gc_ref)
187 }
188
189 pub unsafe fn to_raw(&self, mut store: impl AsContextMut) -> Result<u32> {
202 let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
203 let gc_ref = self.inner.try_clone_gc_ref(&mut store)?;
204 let raw = gc_ref.as_raw_u32();
205 store.gc_store_mut()?.expose_gc_ref_to_wasm(gc_ref);
206 Ok(raw)
207 }
208
209 pub fn is_i31(&self, store: impl AsContext) -> Result<bool> {
213 self._is_i31(store.as_context().0)
214 }
215
216 pub(crate) fn _is_i31(&self, store: &StoreOpaque) -> Result<bool> {
217 let gc_ref = self.inner.unchecked_try_gc_ref(store)?;
220 Ok(gc_ref.is_i31())
221 }
222
223 pub fn as_i31(&self, store: impl AsContext) -> Result<Option<I31>> {
231 let gc_ref = self.inner.unchecked_try_gc_ref(store.as_context().0)?;
234 Ok(gc_ref.as_i31().map(Into::into))
235 }
236
237 pub fn unwrap_i31(&self, store: impl AsContext) -> Result<I31> {
242 Ok(self.as_i31(store)?.expect("AnyRef::unwrap_i31 on non-i31"))
243 }
244}
245
246unsafe impl WasmTy for Rooted<AnyRef> {
247 type Abi = NonZeroU64;
250
251 #[inline]
252 fn valtype() -> ValType {
253 ValType::Ref(RefType::new(false, HeapType::Any))
254 }
255
256 #[inline]
257 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
258 self.comes_from_same_store(store)
259 }
260
261 #[inline]
262 fn dynamic_concrete_type_check(&self, _: &StoreOpaque, _: bool, _: &FuncType) -> Result<()> {
263 unreachable!()
264 }
265
266 #[inline]
267 fn is_non_i31_gc_ref(&self) -> bool {
268 true
269 }
270
271 #[inline]
272 unsafe fn abi_from_raw(raw: *mut ValRaw) -> Self::Abi {
273 let raw = (*raw).get_externref();
274 debug_assert_ne!(raw, 0);
275 NonZeroU64::new_unchecked(u64::from(raw))
276 }
277
278 #[inline]
279 unsafe fn abi_into_raw(abi: Self::Abi, raw: *mut ValRaw) {
280 let externref = u32::try_from(abi.get()).unwrap();
281 *raw = ValRaw::externref(externref);
282 }
283
284 #[inline]
285 fn into_abi(self, store: &mut AutoAssertNoGc<'_>) -> Result<Self::Abi> {
286 let gc_ref = self.inner.try_clone_gc_ref(store)?;
287 let r64 = gc_ref.as_r64();
288 store.gc_store_mut()?.expose_gc_ref_to_wasm(gc_ref);
289 debug_assert_ne!(r64, 0);
290 Ok(unsafe { NonZeroU64::new_unchecked(r64) })
291 }
292
293 #[inline]
294 unsafe fn from_abi(abi: Self::Abi, store: &mut AutoAssertNoGc<'_>) -> Self {
295 let gc_ref = VMGcRef::from_r64(abi.get())
296 .expect("valid r64")
297 .expect("non-null");
298 let gc_ref = store.unwrap_gc_store_mut().clone_gc_ref(&gc_ref);
299 AnyRef::from_cloned_gc_ref(store, gc_ref)
300 }
301}
302
303unsafe impl WasmTy for Option<Rooted<AnyRef>> {
304 type Abi = u64;
305
306 #[inline]
307 fn valtype() -> ValType {
308 ValType::ANYREF
309 }
310
311 #[inline]
312 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
313 self.map_or(true, |x| x.comes_from_same_store(store))
314 }
315
316 #[inline]
317 fn dynamic_concrete_type_check(&self, _: &StoreOpaque, _: bool, _: &FuncType) -> Result<()> {
318 unreachable!()
319 }
320
321 #[inline]
322 fn is_non_i31_gc_ref(&self) -> bool {
323 true
324 }
325
326 #[inline]
327 unsafe fn abi_from_raw(raw: *mut ValRaw) -> Self::Abi {
328 let externref = (*raw).get_externref();
329 u64::from(externref)
330 }
331
332 #[inline]
333 unsafe fn abi_into_raw(abi: Self::Abi, raw: *mut ValRaw) {
334 let externref = u32::try_from(abi).unwrap();
335 *raw = ValRaw::externref(externref);
336 }
337
338 #[inline]
339 fn into_abi(self, store: &mut AutoAssertNoGc<'_>) -> Result<Self::Abi> {
340 Ok(if let Some(x) = self {
341 <Rooted<AnyRef> as WasmTy>::into_abi(x, store)?.get()
342 } else {
343 0
344 })
345 }
346
347 #[inline]
348 unsafe fn from_abi(abi: Self::Abi, store: &mut AutoAssertNoGc<'_>) -> Self {
349 let gc_ref = VMGcRef::from_r64(abi).expect("valid r64")?;
350 let gc_ref = store.unwrap_gc_store_mut().clone_gc_ref(&gc_ref);
351 Some(AnyRef::from_cloned_gc_ref(store, gc_ref))
352 }
353}
354
355unsafe impl WasmTy for ManuallyRooted<AnyRef> {
356 type Abi = NonZeroU64;
357
358 #[inline]
359 fn valtype() -> ValType {
360 ValType::Ref(RefType::new(false, HeapType::Any))
361 }
362
363 #[inline]
364 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
365 self.comes_from_same_store(store)
366 }
367
368 #[inline]
369 fn dynamic_concrete_type_check(&self, _: &StoreOpaque, _: bool, _: &FuncType) -> Result<()> {
370 unreachable!()
371 }
372
373 #[inline]
374 fn is_non_i31_gc_ref(&self) -> bool {
375 true
376 }
377
378 #[inline]
379 unsafe fn abi_from_raw(raw: *mut ValRaw) -> Self::Abi {
380 let externref = (*raw).get_externref();
381 debug_assert_ne!(externref, 0);
382 NonZeroU64::new_unchecked(u64::from(externref))
383 }
384
385 #[inline]
386 unsafe fn abi_into_raw(abi: Self::Abi, raw: *mut ValRaw) {
387 let externref = u32::try_from(abi.get()).unwrap();
388 *raw = ValRaw::externref(externref);
389 }
390
391 #[inline]
392 fn into_abi(self, store: &mut AutoAssertNoGc<'_>) -> Result<Self::Abi> {
393 let gc_ref = self.inner.try_clone_gc_ref(store)?;
394 let r64 = gc_ref.as_r64();
395 store.gc_store_mut()?.expose_gc_ref_to_wasm(gc_ref);
396 Ok(unsafe { NonZeroU64::new_unchecked(r64) })
397 }
398
399 #[inline]
400 unsafe fn from_abi(abi: Self::Abi, store: &mut AutoAssertNoGc<'_>) -> Self {
401 let gc_ref = VMGcRef::from_r64(abi.get())
402 .expect("valid r64")
403 .expect("non-null");
404 let gc_ref = store.unwrap_gc_store_mut().clone_gc_ref(&gc_ref);
405 RootSet::with_lifo_scope(store, |store| {
406 let rooted = AnyRef::from_cloned_gc_ref(store, gc_ref);
407 rooted
408 ._to_manually_rooted(store)
409 .expect("rooted is in scope")
410 })
411 }
412}
413
414unsafe impl WasmTy for Option<ManuallyRooted<AnyRef>> {
415 type Abi = u64;
416
417 #[inline]
418 fn valtype() -> ValType {
419 ValType::ANYREF
420 }
421
422 #[inline]
423 fn compatible_with_store(&self, store: &StoreOpaque) -> bool {
424 self.as_ref()
425 .map_or(true, |x| x.comes_from_same_store(store))
426 }
427
428 #[inline]
429 fn dynamic_concrete_type_check(&self, _: &StoreOpaque, _: bool, _: &FuncType) -> Result<()> {
430 unreachable!()
431 }
432
433 #[inline]
434 fn is_non_i31_gc_ref(&self) -> bool {
435 true
436 }
437
438 #[inline]
439 unsafe fn abi_from_raw(raw: *mut ValRaw) -> Self::Abi {
440 let externref = (*raw).get_externref();
441 u64::from(externref)
442 }
443
444 #[inline]
445 unsafe fn abi_into_raw(abi: Self::Abi, raw: *mut ValRaw) {
446 let externref = u32::try_from(abi).unwrap();
447 *raw = ValRaw::externref(externref);
448 }
449
450 #[inline]
451 fn into_abi(self, store: &mut AutoAssertNoGc<'_>) -> Result<Self::Abi> {
452 Ok(if let Some(x) = self {
453 <ManuallyRooted<AnyRef> as WasmTy>::into_abi(x, store)?.get()
454 } else {
455 0
456 })
457 }
458
459 #[inline]
460 unsafe fn from_abi(abi: Self::Abi, store: &mut AutoAssertNoGc<'_>) -> Self {
461 let gc_ref = VMGcRef::from_r64(abi).expect("valid r64")?;
462 let gc_ref = store.unwrap_gc_store_mut().clone_gc_ref(&gc_ref);
463 RootSet::with_lifo_scope(store, |store| {
464 let rooted = AnyRef::from_cloned_gc_ref(store, gc_ref);
465 Some(
466 rooted
467 ._to_manually_rooted(store)
468 .expect("rooted is in scope"),
469 )
470 })
471 }
472}