1 use crate::runtime::vm::TableElement; 2 use crate::store::{AutoAssertNoGc, StoreOpaque}; 3 use crate::{ 4 AnyRef, ArrayRef, AsContext, AsContextMut, ExternRef, Func, HeapType, RefType, Rooted, 5 RootedGcRefImpl, StructRef, V128, ValType, prelude::*, 6 }; 7 use core::ptr; 8 9 pub use crate::runtime::vm::ValRaw; 10 11 /// Possible runtime values that a WebAssembly module can either consume or 12 /// produce. 13 /// 14 /// Note that we inline the `enum Ref { ... }` variants into `enum Val { ... }` 15 /// here as a size optimization. 16 #[derive(Debug, Clone, Copy)] 17 pub enum Val { 18 // NB: the ordering here is intended to match the ordering in 19 // `ValType` to improve codegen when learning the type of a value. 20 // 21 /// A 32-bit integer. 22 I32(i32), 23 24 /// A 64-bit integer. 25 I64(i64), 26 27 /// A 32-bit float. 28 /// 29 /// Note that the raw bits of the float are stored here, and you can use 30 /// `f32::from_bits` to create an `f32` value. 31 F32(u32), 32 33 /// A 64-bit float. 34 /// 35 /// Note that the raw bits of the float are stored here, and you can use 36 /// `f64::from_bits` to create an `f64` value. 37 F64(u64), 38 39 /// A 128-bit number. 40 V128(V128), 41 42 /// A function reference. 43 FuncRef(Option<Func>), 44 45 /// An external reference. 46 ExternRef(Option<Rooted<ExternRef>>), 47 48 /// An internal reference. 49 AnyRef(Option<Rooted<AnyRef>>), 50 } 51 52 macro_rules! accessors { 53 ($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($( 54 /// Attempt to access the underlying value of this `Val`, returning 55 /// `None` if it is not the correct type. 56 #[inline] 57 pub fn $get(&self) -> Option<$ty> { 58 if let Val::$variant($bind) = self { 59 Some($cvt) 60 } else { 61 None 62 } 63 } 64 65 /// Returns the underlying value of this `Val`, panicking if it's the 66 /// wrong type. 67 /// 68 /// # Panics 69 /// 70 /// Panics if `self` is not of the right type. 71 #[inline] 72 pub fn $unwrap(&self) -> $ty { 73 self.$get().expect(concat!("expected ", stringify!($ty))) 74 } 75 )*) 76 } 77 78 impl Val { 79 /// Returns the null reference for the given heap type. 80 #[inline] 81 pub fn null_ref(heap_type: &HeapType) -> Val { 82 Ref::null(&heap_type).into() 83 } 84 85 /// Returns the null function reference value. 86 /// 87 /// The return value has type `(ref null nofunc)` aka `nullfuncref` and is a 88 /// subtype of all function references. 89 #[inline] 90 pub const fn null_func_ref() -> Val { 91 Val::FuncRef(None) 92 } 93 94 /// Returns the null function reference value. 95 /// 96 /// The return value has type `(ref null extern)` aka `nullexternref` and is 97 /// a subtype of all external references. 98 #[inline] 99 pub const fn null_extern_ref() -> Val { 100 Val::ExternRef(None) 101 } 102 103 /// Returns the null function reference value. 104 /// 105 /// The return value has type `(ref null any)` aka `nullref` and is a 106 /// subtype of all internal references. 107 #[inline] 108 pub const fn null_any_ref() -> Val { 109 Val::AnyRef(None) 110 } 111 112 /// Returns the default value for the given type, if any exists. 113 /// 114 /// Returns `None` if there is no default value for the given type (for 115 /// example, non-nullable reference types do not have a default value). 116 pub fn default_for_ty(ty: &ValType) -> Option<Val> { 117 match ty { 118 ValType::I32 => Some(Val::I32(0)), 119 ValType::I64 => Some(Val::I64(0)), 120 ValType::F32 => Some(Val::F32(0)), 121 ValType::F64 => Some(Val::F64(0)), 122 ValType::V128 => Some(Val::V128(V128::from(0))), 123 ValType::Ref(ref_ty) => { 124 if ref_ty.is_nullable() { 125 Some(Val::null_ref(ref_ty.heap_type())) 126 } else { 127 None 128 } 129 } 130 } 131 } 132 133 /// Returns the corresponding [`ValType`] for this `Val`. 134 /// 135 /// # Errors 136 /// 137 /// Returns an error if this value is a GC reference that has since been 138 /// unrooted. 139 /// 140 /// # Panics 141 /// 142 /// Panics if this value is associated with a different store. 143 #[inline] 144 pub fn ty(&self, store: impl AsContext) -> Result<ValType> { 145 self.load_ty(&store.as_context().0) 146 } 147 148 #[inline] 149 pub(crate) fn load_ty(&self, store: &StoreOpaque) -> Result<ValType> { 150 Ok(match self { 151 Val::I32(_) => ValType::I32, 152 Val::I64(_) => ValType::I64, 153 Val::F32(_) => ValType::F32, 154 Val::F64(_) => ValType::F64, 155 Val::V128(_) => ValType::V128, 156 Val::ExternRef(Some(_)) => ValType::EXTERNREF, 157 Val::ExternRef(None) => ValType::NULLFUNCREF, 158 Val::FuncRef(None) => ValType::NULLFUNCREF, 159 Val::FuncRef(Some(f)) => ValType::Ref(RefType::new( 160 false, 161 HeapType::ConcreteFunc(f.load_ty(store)), 162 )), 163 Val::AnyRef(None) => ValType::NULLREF, 164 Val::AnyRef(Some(a)) => ValType::Ref(RefType::new(false, a._ty(store)?)), 165 }) 166 } 167 168 /// Does this value match the given type? 169 /// 170 /// Returns an error is an underlying `Rooted` has been unrooted. 171 /// 172 /// # Panics 173 /// 174 /// Panics if this value is not associated with the given store. 175 pub fn matches_ty(&self, store: impl AsContext, ty: &ValType) -> Result<bool> { 176 self._matches_ty(&store.as_context().0, ty) 177 } 178 179 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &ValType) -> Result<bool> { 180 assert!(self.comes_from_same_store(store)); 181 assert!(ty.comes_from_same_engine(store.engine())); 182 Ok(match (self, ty) { 183 (Val::I32(_), ValType::I32) 184 | (Val::I64(_), ValType::I64) 185 | (Val::F32(_), ValType::F32) 186 | (Val::F64(_), ValType::F64) 187 | (Val::V128(_), ValType::V128) => true, 188 189 (Val::FuncRef(f), ValType::Ref(ref_ty)) => Ref::from(*f)._matches_ty(store, ref_ty)?, 190 (Val::ExternRef(e), ValType::Ref(ref_ty)) => { 191 Ref::from(*e)._matches_ty(store, ref_ty)? 192 } 193 (Val::AnyRef(a), ValType::Ref(ref_ty)) => Ref::from(*a)._matches_ty(store, ref_ty)?, 194 195 (Val::I32(_), _) 196 | (Val::I64(_), _) 197 | (Val::F32(_), _) 198 | (Val::F64(_), _) 199 | (Val::V128(_), _) 200 | (Val::FuncRef(_), _) 201 | (Val::ExternRef(_), _) 202 | (Val::AnyRef(_), _) => false, 203 }) 204 } 205 206 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &ValType) -> Result<()> { 207 if !self.comes_from_same_store(store) { 208 bail!("value used with wrong store") 209 } 210 if !ty.comes_from_same_engine(store.engine()) { 211 bail!("type used with wrong engine") 212 } 213 if self._matches_ty(store, ty)? { 214 Ok(()) 215 } else { 216 let actual_ty = self.load_ty(store)?; 217 bail!("type mismatch: expected {ty}, found {actual_ty}") 218 } 219 } 220 221 /// Convenience method to convert this [`Val`] into a [`ValRaw`]. 222 /// 223 /// Returns an error if this value is a GC reference and the GC reference 224 /// has been unrooted. 225 /// 226 /// # Unsafety 227 /// 228 /// This method is unsafe for the reasons that [`ExternRef::to_raw`] and 229 /// [`Func::to_raw`] are unsafe. 230 pub unsafe fn to_raw(&self, store: impl AsContextMut) -> Result<ValRaw> { 231 match self { 232 Val::I32(i) => Ok(ValRaw::i32(*i)), 233 Val::I64(i) => Ok(ValRaw::i64(*i)), 234 Val::F32(u) => Ok(ValRaw::f32(*u)), 235 Val::F64(u) => Ok(ValRaw::f64(*u)), 236 Val::V128(b) => Ok(ValRaw::v128(b.as_u128())), 237 Val::ExternRef(e) => Ok(ValRaw::externref(match e { 238 None => 0, 239 Some(e) => e.to_raw(store)?, 240 })), 241 Val::AnyRef(e) => Ok(ValRaw::anyref(match e { 242 None => 0, 243 Some(e) => e.to_raw(store)?, 244 })), 245 Val::FuncRef(f) => Ok(ValRaw::funcref(match f { 246 Some(f) => f.to_raw(store), 247 None => ptr::null_mut(), 248 })), 249 } 250 } 251 252 /// Convenience method to convert a [`ValRaw`] into a [`Val`]. 253 /// 254 /// # Unsafety 255 /// 256 /// This method is unsafe for the reasons that [`ExternRef::from_raw`] and 257 /// [`Func::from_raw`] are unsafe. Additionally there's no guarantee 258 /// otherwise that `raw` should have the type `ty` specified. 259 pub unsafe fn from_raw(mut store: impl AsContextMut, raw: ValRaw, ty: ValType) -> Val { 260 let mut store = AutoAssertNoGc::new(store.as_context_mut().0); 261 Self::_from_raw(&mut store, raw, &ty) 262 } 263 264 pub(crate) unsafe fn _from_raw( 265 store: &mut AutoAssertNoGc<'_>, 266 raw: ValRaw, 267 ty: &ValType, 268 ) -> Val { 269 match ty { 270 ValType::I32 => Val::I32(raw.get_i32()), 271 ValType::I64 => Val::I64(raw.get_i64()), 272 ValType::F32 => Val::F32(raw.get_f32()), 273 ValType::F64 => Val::F64(raw.get_f64()), 274 ValType::V128 => Val::V128(raw.get_v128().into()), 275 ValType::Ref(ref_ty) => { 276 let ref_ = match ref_ty.heap_type() { 277 HeapType::Func | HeapType::ConcreteFunc(_) => { 278 Func::_from_raw(store, raw.get_funcref()).into() 279 } 280 281 HeapType::NoFunc => Ref::Func(None), 282 283 HeapType::NoCont | HeapType::ConcreteCont(_) | HeapType::Cont => { 284 // TODO(#10248): Required to support stack switching in the embedder API. 285 unimplemented!() 286 } 287 288 HeapType::Extern => ExternRef::_from_raw(store, raw.get_externref()).into(), 289 290 HeapType::NoExtern => Ref::Extern(None), 291 292 HeapType::Any 293 | HeapType::Eq 294 | HeapType::I31 295 | HeapType::Array 296 | HeapType::ConcreteArray(_) 297 | HeapType::Struct 298 | HeapType::ConcreteStruct(_) => { 299 AnyRef::_from_raw(store, raw.get_anyref()).into() 300 } 301 302 HeapType::None => Ref::Any(None), 303 }; 304 assert!( 305 ref_ty.is_nullable() || !ref_.is_null(), 306 "if the type is not nullable, we shouldn't get null; got \ 307 type = {ref_ty}, ref = {ref_:?}" 308 ); 309 ref_.into() 310 } 311 } 312 } 313 314 accessors! { 315 e 316 (I32(i32) i32 unwrap_i32 *e) 317 (I64(i64) i64 unwrap_i64 *e) 318 (F32(f32) f32 unwrap_f32 f32::from_bits(*e)) 319 (F64(f64) f64 unwrap_f64 f64::from_bits(*e)) 320 (FuncRef(Option<&Func>) func_ref unwrap_func_ref e.as_ref()) 321 (ExternRef(Option<&Rooted<ExternRef>>) extern_ref unwrap_extern_ref e.as_ref()) 322 (AnyRef(Option<&Rooted<AnyRef>>) any_ref unwrap_any_ref e.as_ref()) 323 (V128(V128) v128 unwrap_v128 *e) 324 } 325 326 /// Get this value's underlying reference, if any. 327 #[inline] 328 pub fn ref_(self) -> Option<Ref> { 329 match self { 330 Val::FuncRef(f) => Some(Ref::Func(f)), 331 Val::ExternRef(e) => Some(Ref::Extern(e)), 332 Val::AnyRef(a) => Some(Ref::Any(a)), 333 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => None, 334 } 335 } 336 337 /// Attempt to access the underlying `externref` value of this `Val`. 338 /// 339 /// If this is not an `externref`, then `None` is returned. 340 /// 341 /// If this is a null `externref`, then `Some(None)` is returned. 342 /// 343 /// If this is a non-null `externref`, then `Some(Some(..))` is returned. 344 #[inline] 345 pub fn externref(&self) -> Option<Option<&Rooted<ExternRef>>> { 346 match self { 347 Val::ExternRef(None) => Some(None), 348 Val::ExternRef(Some(e)) => Some(Some(e)), 349 _ => None, 350 } 351 } 352 353 /// Returns the underlying `externref` value of this `Val`, panicking if it's the 354 /// wrong type. 355 /// 356 /// If this is a null `externref`, then `None` is returned. 357 /// 358 /// If this is a non-null `externref`, then `Some(..)` is returned. 359 /// 360 /// # Panics 361 /// 362 /// Panics if `self` is not a (nullable) `externref`. 363 #[inline] 364 pub fn unwrap_externref(&self) -> Option<&Rooted<ExternRef>> { 365 self.externref().expect("expected externref") 366 } 367 368 /// Attempt to access the underlying `anyref` value of this `Val`. 369 /// 370 /// If this is not an `anyref`, then `None` is returned. 371 /// 372 /// If this is a null `anyref`, then `Some(None)` is returned. 373 /// 374 /// If this is a non-null `anyref`, then `Some(Some(..))` is returned. 375 #[inline] 376 pub fn anyref(&self) -> Option<Option<&Rooted<AnyRef>>> { 377 match self { 378 Val::AnyRef(None) => Some(None), 379 Val::AnyRef(Some(e)) => Some(Some(e)), 380 _ => None, 381 } 382 } 383 384 /// Returns the underlying `anyref` value of this `Val`, panicking if it's the 385 /// wrong type. 386 /// 387 /// If this is a null `anyref`, then `None` is returned. 388 /// 389 /// If this is a non-null `anyref`, then `Some(..)` is returned. 390 /// 391 /// # Panics 392 /// 393 /// Panics if `self` is not a (nullable) `anyref`. 394 #[inline] 395 pub fn unwrap_anyref(&self) -> Option<&Rooted<AnyRef>> { 396 self.anyref().expect("expected anyref") 397 } 398 399 /// Attempt to access the underlying `funcref` value of this `Val`. 400 /// 401 /// If this is not an `funcref`, then `None` is returned. 402 /// 403 /// If this is a null `funcref`, then `Some(None)` is returned. 404 /// 405 /// If this is a non-null `funcref`, then `Some(Some(..))` is returned. 406 #[inline] 407 pub fn funcref(&self) -> Option<Option<&Func>> { 408 match self { 409 Val::FuncRef(None) => Some(None), 410 Val::FuncRef(Some(f)) => Some(Some(f)), 411 _ => None, 412 } 413 } 414 415 /// Returns the underlying `funcref` value of this `Val`, panicking if it's the 416 /// wrong type. 417 /// 418 /// If this is a null `funcref`, then `None` is returned. 419 /// 420 /// If this is a non-null `funcref`, then `Some(..)` is returned. 421 /// 422 /// # Panics 423 /// 424 /// Panics if `self` is not a (nullable) `funcref`. 425 #[inline] 426 pub fn unwrap_funcref(&self) -> Option<&Func> { 427 self.funcref().expect("expected funcref") 428 } 429 430 #[inline] 431 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool { 432 match self { 433 Val::FuncRef(Some(f)) => f.comes_from_same_store(store), 434 Val::FuncRef(None) => true, 435 436 Val::ExternRef(Some(x)) => x.comes_from_same_store(store), 437 Val::ExternRef(None) => true, 438 439 Val::AnyRef(Some(a)) => a.comes_from_same_store(store), 440 Val::AnyRef(None) => true, 441 442 // Integers, floats, and vectors have no association with any 443 // particular store, so they're always considered as "yes I came 444 // from that store", 445 Val::I32(_) | Val::I64(_) | Val::F32(_) | Val::F64(_) | Val::V128(_) => true, 446 } 447 } 448 } 449 450 impl From<i32> for Val { 451 #[inline] 452 fn from(val: i32) -> Val { 453 Val::I32(val) 454 } 455 } 456 457 impl From<i64> for Val { 458 #[inline] 459 fn from(val: i64) -> Val { 460 Val::I64(val) 461 } 462 } 463 464 impl From<f32> for Val { 465 #[inline] 466 fn from(val: f32) -> Val { 467 Val::F32(val.to_bits()) 468 } 469 } 470 471 impl From<f64> for Val { 472 #[inline] 473 fn from(val: f64) -> Val { 474 Val::F64(val.to_bits()) 475 } 476 } 477 478 impl From<Ref> for Val { 479 #[inline] 480 fn from(val: Ref) -> Val { 481 match val { 482 Ref::Extern(e) => Val::ExternRef(e), 483 Ref::Func(f) => Val::FuncRef(f), 484 Ref::Any(a) => Val::AnyRef(a), 485 } 486 } 487 } 488 489 impl From<Rooted<ExternRef>> for Val { 490 #[inline] 491 fn from(val: Rooted<ExternRef>) -> Val { 492 Val::ExternRef(Some(val)) 493 } 494 } 495 496 impl From<Option<Rooted<ExternRef>>> for Val { 497 #[inline] 498 fn from(val: Option<Rooted<ExternRef>>) -> Val { 499 Val::ExternRef(val) 500 } 501 } 502 503 impl From<Rooted<AnyRef>> for Val { 504 #[inline] 505 fn from(val: Rooted<AnyRef>) -> Val { 506 Val::AnyRef(Some(val)) 507 } 508 } 509 510 impl From<Option<Rooted<AnyRef>>> for Val { 511 #[inline] 512 fn from(val: Option<Rooted<AnyRef>>) -> Val { 513 Val::AnyRef(val) 514 } 515 } 516 517 impl From<Rooted<StructRef>> for Val { 518 #[inline] 519 fn from(val: Rooted<StructRef>) -> Val { 520 Val::AnyRef(Some(val.into())) 521 } 522 } 523 524 impl From<Option<Rooted<StructRef>>> for Val { 525 #[inline] 526 fn from(val: Option<Rooted<StructRef>>) -> Val { 527 Val::AnyRef(val.map(Into::into)) 528 } 529 } 530 531 impl From<Rooted<ArrayRef>> for Val { 532 #[inline] 533 fn from(val: Rooted<ArrayRef>) -> Val { 534 Val::AnyRef(Some(val.into())) 535 } 536 } 537 538 impl From<Option<Rooted<ArrayRef>>> for Val { 539 #[inline] 540 fn from(val: Option<Rooted<ArrayRef>>) -> Val { 541 Val::AnyRef(val.map(Into::into)) 542 } 543 } 544 545 impl From<Func> for Val { 546 #[inline] 547 fn from(val: Func) -> Val { 548 Val::FuncRef(Some(val)) 549 } 550 } 551 552 impl From<Option<Func>> for Val { 553 #[inline] 554 fn from(val: Option<Func>) -> Val { 555 Val::FuncRef(val) 556 } 557 } 558 559 impl From<u128> for Val { 560 #[inline] 561 fn from(val: u128) -> Val { 562 Val::V128(val.into()) 563 } 564 } 565 566 impl From<V128> for Val { 567 #[inline] 568 fn from(val: V128) -> Val { 569 Val::V128(val) 570 } 571 } 572 573 /// A reference. 574 /// 575 /// References come in three broad flavors: 576 /// 577 /// 1. Function references. These are references to a function that can be 578 /// invoked. 579 /// 580 /// 2. External references. These are references to data that is external 581 /// and opaque to the Wasm guest, provided by the host. 582 /// 583 /// 3. Internal references. These are references to allocations inside the 584 /// Wasm's heap, such as structs and arrays. These are part of the GC 585 /// proposal, and not yet implemented in Wasmtime. 586 /// 587 /// At the Wasm level, there are nullable and non-nullable variants of each type 588 /// of reference. Both variants are represented with `Ref` at the Wasmtime API 589 /// level. For example, values of both `(ref extern)` and `(ref null extern)` 590 /// types will be represented as `Ref::Extern(Option<ExternRef>)` in the 591 /// Wasmtime API. Nullable references are represented as `Option<Ref>` where 592 /// null references are represented as `None`. Wasm can construct null 593 /// references via the `ref.null <heap-type>` instruction. 594 /// 595 /// References are non-forgable: Wasm cannot create invalid references, for 596 /// example, by claiming that the integer `0xbad1bad2` is actually a reference. 597 #[derive(Debug, Clone)] 598 pub enum Ref { 599 // NB: We have a variant for each of the type hierarchies defined in Wasm, 600 // and push the `Option` that provides nullability into each variant. This 601 // allows us to get the most-precise type of any reference value, whether it 602 // is null or not, without any additional metadata. 603 // 604 // Consider if we instead had the nullability inside `Val::Ref` and each of 605 // the `Ref` variants did not have an `Option`: 606 // 607 // enum Val { 608 // Ref(Option<Ref>), 609 // // Etc... 610 // } 611 // enum Ref { 612 // Func(Func), 613 // External(ExternRef), 614 // // Etc... 615 // } 616 // 617 // In this scenario, what type would we return from `Val::ty` for 618 // `Val::Ref(None)`? Because Wasm has multiple separate type hierarchies, 619 // there is no single common bottom type for all the different kinds of 620 // references. So in this scenario, `Val::Ref(None)` doesn't have enough 621 // information to reconstruct the value's type. That's a problem for us 622 // because we need to get a value's type at various times all over the code 623 // base. 624 // 625 /// A first-class reference to a WebAssembly function. 626 /// 627 /// The host, or the Wasm guest, can invoke this function. 628 /// 629 /// The host can create function references via [`Func::new`] or 630 /// [`Func::wrap`]. 631 /// 632 /// The Wasm guest can create non-null function references via the 633 /// `ref.func` instruction, or null references via the `ref.null func` 634 /// instruction. 635 Func(Option<Func>), 636 637 /// A reference to an value outside of the Wasm heap. 638 /// 639 /// These references are opaque to the Wasm itself. Wasm can't create 640 /// non-null external references, nor do anything with them accept pass them 641 /// around as function arguments and returns and place them into globals and 642 /// tables. 643 /// 644 /// Wasm can create null external references via the `ref.null extern` 645 /// instruction. 646 Extern(Option<Rooted<ExternRef>>), 647 648 /// An internal reference. 649 /// 650 /// The `AnyRef` type represents WebAssembly `anyref` values. These can be 651 /// references to `struct`s and `array`s or inline/unboxed 31-bit 652 /// integers. 653 /// 654 /// Unlike `externref`, Wasm guests can directly allocate `anyref`s, and 655 /// does not need to rely on the host to do that. 656 Any(Option<Rooted<AnyRef>>), 657 } 658 659 impl From<Func> for Ref { 660 #[inline] 661 fn from(f: Func) -> Ref { 662 Ref::Func(Some(f)) 663 } 664 } 665 666 impl From<Option<Func>> for Ref { 667 #[inline] 668 fn from(f: Option<Func>) -> Ref { 669 Ref::Func(f) 670 } 671 } 672 673 impl From<Rooted<ExternRef>> for Ref { 674 #[inline] 675 fn from(e: Rooted<ExternRef>) -> Ref { 676 Ref::Extern(Some(e)) 677 } 678 } 679 680 impl From<Option<Rooted<ExternRef>>> for Ref { 681 #[inline] 682 fn from(e: Option<Rooted<ExternRef>>) -> Ref { 683 Ref::Extern(e) 684 } 685 } 686 687 impl From<Rooted<AnyRef>> for Ref { 688 #[inline] 689 fn from(e: Rooted<AnyRef>) -> Ref { 690 Ref::Any(Some(e)) 691 } 692 } 693 694 impl From<Option<Rooted<AnyRef>>> for Ref { 695 #[inline] 696 fn from(e: Option<Rooted<AnyRef>>) -> Ref { 697 Ref::Any(e) 698 } 699 } 700 701 impl From<Rooted<StructRef>> for Ref { 702 #[inline] 703 fn from(e: Rooted<StructRef>) -> Ref { 704 Ref::Any(Some(e.into())) 705 } 706 } 707 708 impl From<Option<Rooted<StructRef>>> for Ref { 709 #[inline] 710 fn from(e: Option<Rooted<StructRef>>) -> Ref { 711 Ref::Any(e.map(Into::into)) 712 } 713 } 714 715 impl From<Rooted<ArrayRef>> for Ref { 716 #[inline] 717 fn from(e: Rooted<ArrayRef>) -> Ref { 718 Ref::Any(Some(e.into())) 719 } 720 } 721 722 impl From<Option<Rooted<ArrayRef>>> for Ref { 723 #[inline] 724 fn from(e: Option<Rooted<ArrayRef>>) -> Ref { 725 Ref::Any(e.map(Into::into)) 726 } 727 } 728 729 impl Ref { 730 /// Create a null reference to the given heap type. 731 #[inline] 732 pub fn null(heap_type: &HeapType) -> Self { 733 match heap_type.top() { 734 HeapType::Any => Ref::Any(None), 735 HeapType::Extern => Ref::Extern(None), 736 HeapType::Func => Ref::Func(None), 737 ty => unreachable!("not a heap type: {ty:?}"), 738 } 739 } 740 741 /// Is this a null reference? 742 #[inline] 743 pub fn is_null(&self) -> bool { 744 match self { 745 Ref::Any(None) | Ref::Extern(None) | Ref::Func(None) => true, 746 Ref::Any(Some(_)) | Ref::Extern(Some(_)) | Ref::Func(Some(_)) => false, 747 } 748 } 749 750 /// Is this a non-null reference? 751 #[inline] 752 pub fn is_non_null(&self) -> bool { 753 !self.is_null() 754 } 755 756 /// Is this an `extern` reference? 757 #[inline] 758 pub fn is_extern(&self) -> bool { 759 matches!(self, Ref::Extern(_)) 760 } 761 762 /// Get the underlying `extern` reference, if any. 763 /// 764 /// Returns `None` if this `Ref` is not an `extern` reference, eg it is a 765 /// `func` reference. 766 /// 767 /// Returns `Some(None)` if this `Ref` is a null `extern` reference. 768 /// 769 /// Returns `Some(Some(_))` if this `Ref` is a non-null `extern` reference. 770 #[inline] 771 pub fn as_extern(&self) -> Option<Option<&Rooted<ExternRef>>> { 772 match self { 773 Ref::Extern(e) => Some(e.as_ref()), 774 _ => None, 775 } 776 } 777 778 /// Get the underlying `extern` reference, panicking if this is a different 779 /// kind of reference. 780 /// 781 /// Returns `None` if this `Ref` is a null `extern` reference. 782 /// 783 /// Returns `Some(_)` if this `Ref` is a non-null `extern` reference. 784 #[inline] 785 pub fn unwrap_extern(&self) -> Option<&Rooted<ExternRef>> { 786 self.as_extern() 787 .expect("Ref::unwrap_extern on non-extern reference") 788 } 789 790 /// Is this an `any` reference? 791 #[inline] 792 pub fn is_any(&self) -> bool { 793 matches!(self, Ref::Any(_)) 794 } 795 796 /// Get the underlying `any` reference, if any. 797 /// 798 /// Returns `None` if this `Ref` is not an `any` reference, eg it is a 799 /// `func` reference. 800 /// 801 /// Returns `Some(None)` if this `Ref` is a null `any` reference. 802 /// 803 /// Returns `Some(Some(_))` if this `Ref` is a non-null `any` reference. 804 #[inline] 805 pub fn as_any(&self) -> Option<Option<&Rooted<AnyRef>>> { 806 match self { 807 Ref::Any(e) => Some(e.as_ref()), 808 _ => None, 809 } 810 } 811 812 /// Get the underlying `any` reference, panicking if this is a different 813 /// kind of reference. 814 /// 815 /// Returns `None` if this `Ref` is a null `any` reference. 816 /// 817 /// Returns `Some(_)` if this `Ref` is a non-null `any` reference. 818 #[inline] 819 pub fn unwrap_any(&self) -> Option<&Rooted<AnyRef>> { 820 self.as_any().expect("Ref::unwrap_any on non-any reference") 821 } 822 823 /// Is this a `func` reference? 824 #[inline] 825 pub fn is_func(&self) -> bool { 826 matches!(self, Ref::Func(_)) 827 } 828 829 /// Get the underlying `func` reference, if any. 830 /// 831 /// Returns `None` if this `Ref` is not an `func` reference, eg it is an 832 /// `extern` reference. 833 /// 834 /// Returns `Some(None)` if this `Ref` is a null `func` reference. 835 /// 836 /// Returns `Some(Some(_))` if this `Ref` is a non-null `func` reference. 837 #[inline] 838 pub fn as_func(&self) -> Option<Option<&Func>> { 839 match self { 840 Ref::Func(f) => Some(f.as_ref()), 841 _ => None, 842 } 843 } 844 845 /// Get the underlying `func` reference, panicking if this is a different 846 /// kind of reference. 847 /// 848 /// Returns `None` if this `Ref` is a null `func` reference. 849 /// 850 /// Returns `Some(_)` if this `Ref` is a non-null `func` reference. 851 #[inline] 852 pub fn unwrap_func(&self) -> Option<&Func> { 853 self.as_func() 854 .expect("Ref::unwrap_func on non-func reference") 855 } 856 857 /// Get the type of this reference. 858 /// 859 /// # Errors 860 /// 861 /// Return an error if this reference has been unrooted. 862 /// 863 /// # Panics 864 /// 865 /// Panics if this reference is associated with a different store. 866 pub fn ty(&self, store: impl AsContext) -> Result<RefType> { 867 self.load_ty(&store.as_context().0) 868 } 869 870 pub(crate) fn load_ty(&self, store: &StoreOpaque) -> Result<RefType> { 871 assert!(self.comes_from_same_store(store)); 872 Ok(RefType::new( 873 self.is_null(), 874 // NB: We choose the most-specific heap type we can here and let 875 // subtyping do its thing if callers are matching against a 876 // `HeapType::Func`. 877 match self { 878 Ref::Extern(None) => HeapType::NoExtern, 879 Ref::Extern(Some(_)) => HeapType::Extern, 880 881 Ref::Func(None) => HeapType::NoFunc, 882 Ref::Func(Some(f)) => HeapType::ConcreteFunc(f.load_ty(store)), 883 884 Ref::Any(None) => HeapType::None, 885 Ref::Any(Some(a)) => a._ty(store)?, 886 }, 887 )) 888 } 889 890 /// Does this reference value match the given type? 891 /// 892 /// Returns an error if the underlying `Rooted` has been unrooted. 893 /// 894 /// # Panics 895 /// 896 /// Panics if this reference is not associated with the given store. 897 pub fn matches_ty(&self, store: impl AsContext, ty: &RefType) -> Result<bool> { 898 self._matches_ty(&store.as_context().0, ty) 899 } 900 901 pub(crate) fn _matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<bool> { 902 assert!(self.comes_from_same_store(store)); 903 assert!(ty.comes_from_same_engine(store.engine())); 904 if self.is_null() && !ty.is_nullable() { 905 return Ok(false); 906 } 907 Ok(match (self, ty.heap_type()) { 908 (Ref::Extern(_), HeapType::Extern) => true, 909 (Ref::Extern(None), HeapType::NoExtern) => true, 910 (Ref::Extern(_), _) => false, 911 912 (Ref::Func(_), HeapType::Func) => true, 913 (Ref::Func(None), HeapType::NoFunc | HeapType::ConcreteFunc(_)) => true, 914 (Ref::Func(Some(f)), HeapType::ConcreteFunc(func_ty)) => f._matches_ty(store, func_ty), 915 (Ref::Func(_), _) => false, 916 917 (Ref::Any(_), HeapType::Any) => true, 918 (Ref::Any(Some(a)), HeapType::I31) => a._is_i31(store)?, 919 (Ref::Any(Some(a)), HeapType::Struct) => a._is_struct(store)?, 920 (Ref::Any(Some(a)), HeapType::ConcreteStruct(_ty)) => match a._as_struct(store)? { 921 None => false, 922 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))] 923 Some(s) => s._matches_ty(store, _ty)?, 924 }, 925 (Ref::Any(Some(a)), HeapType::Eq) => a._is_eqref(store)?, 926 (Ref::Any(Some(a)), HeapType::Array) => a._is_array(store)?, 927 (Ref::Any(Some(a)), HeapType::ConcreteArray(_ty)) => match a._as_array(store)? { 928 None => false, 929 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))] 930 Some(a) => a._matches_ty(store, _ty)?, 931 }, 932 ( 933 Ref::Any(None), 934 HeapType::None 935 | HeapType::I31 936 | HeapType::ConcreteStruct(_) 937 | HeapType::Struct 938 | HeapType::ConcreteArray(_) 939 | HeapType::Array 940 | HeapType::Eq, 941 ) => true, 942 (Ref::Any(_), _) => false, 943 }) 944 } 945 946 pub(crate) fn ensure_matches_ty(&self, store: &StoreOpaque, ty: &RefType) -> Result<()> { 947 if !self.comes_from_same_store(store) { 948 bail!("reference used with wrong store") 949 } 950 if !ty.comes_from_same_engine(store.engine()) { 951 bail!("type used with wrong engine") 952 } 953 if self._matches_ty(store, ty)? { 954 Ok(()) 955 } else { 956 let actual_ty = self.load_ty(store)?; 957 bail!("type mismatch: expected {ty}, found {actual_ty}") 958 } 959 } 960 961 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool { 962 match self { 963 Ref::Func(Some(f)) => f.comes_from_same_store(store), 964 Ref::Func(None) => true, 965 Ref::Extern(Some(x)) => x.comes_from_same_store(store), 966 Ref::Extern(None) => true, 967 Ref::Any(Some(a)) => a.comes_from_same_store(store), 968 Ref::Any(None) => true, 969 } 970 } 971 972 pub(crate) fn into_table_element( 973 self, 974 store: &mut StoreOpaque, 975 ty: &RefType, 976 ) -> Result<TableElement> { 977 let mut store = AutoAssertNoGc::new(store); 978 self.ensure_matches_ty(&store, &ty) 979 .context("type mismatch: value does not match table element type")?; 980 981 match (self, ty.heap_type().top()) { 982 (Ref::Func(None), HeapType::Func) => { 983 assert!(ty.is_nullable()); 984 Ok(TableElement::FuncRef(None)) 985 } 986 (Ref::Func(Some(f)), HeapType::Func) => { 987 debug_assert!( 988 f.comes_from_same_store(&store), 989 "checked in `ensure_matches_ty`" 990 ); 991 Ok(TableElement::FuncRef(Some(f.vm_func_ref(&store)))) 992 } 993 994 (Ref::Extern(e), HeapType::Extern) => match e { 995 None => { 996 assert!(ty.is_nullable()); 997 Ok(TableElement::GcRef(None)) 998 } 999 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))] 1000 Some(e) => { 1001 let gc_ref = e.try_clone_gc_ref(&mut store)?; 1002 Ok(TableElement::GcRef(Some(gc_ref))) 1003 } 1004 }, 1005 1006 (Ref::Any(a), HeapType::Any) => match a { 1007 None => { 1008 assert!(ty.is_nullable()); 1009 Ok(TableElement::GcRef(None)) 1010 } 1011 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))] 1012 Some(a) => { 1013 let gc_ref = a.try_clone_gc_ref(&mut store)?; 1014 Ok(TableElement::GcRef(Some(gc_ref))) 1015 } 1016 }, 1017 1018 _ => unreachable!("checked that the value matches the type above"), 1019 } 1020 } 1021 } 1022 1023 #[cfg(test)] 1024 mod tests { 1025 use crate::*; 1026 1027 #[test] 1028 fn size_of_val() { 1029 // Try to keep tabs on the size of `Val` and make sure we don't grow its 1030 // size. 1031 let expected = if cfg!(target_arch = "x86_64") 1032 || cfg!(target_arch = "aarch64") 1033 || cfg!(target_arch = "s390x") 1034 || cfg!(target_arch = "riscv64") 1035 || cfg!(target_arch = "arm") 1036 { 1037 24 1038 } else if cfg!(target_arch = "x86") { 1039 20 1040 } else { 1041 panic!("unsupported architecture") 1042 }; 1043 assert_eq!(std::mem::size_of::<Val>(), expected); 1044 } 1045 1046 #[test] 1047 fn size_of_ref() { 1048 // Try to keep tabs on the size of `Ref` and make sure we don't grow its 1049 // size. 1050 let expected = if cfg!(target_arch = "x86_64") 1051 || cfg!(target_arch = "aarch64") 1052 || cfg!(target_arch = "s390x") 1053 || cfg!(target_arch = "riscv64") 1054 || cfg!(target_arch = "arm") 1055 { 1056 24 1057 } else if cfg!(target_arch = "x86") { 1058 20 1059 } else { 1060 panic!("unsupported architecture") 1061 }; 1062 assert_eq!(std::mem::size_of::<Ref>(), expected); 1063 } 1064 1065 #[test] 1066 #[should_panic] 1067 fn val_matches_ty_wrong_engine() { 1068 let e1 = Engine::default(); 1069 let e2 = Engine::default(); 1070 1071 let t1 = FuncType::new(&e1, None, None); 1072 let t2 = FuncType::new(&e2, None, None); 1073 1074 let mut s1 = Store::new(&e1, ()); 1075 let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(())); 1076 1077 // Should panic. 1078 let _ = Val::FuncRef(Some(f)).matches_ty( 1079 &s1, 1080 &ValType::Ref(RefType::new(true, HeapType::ConcreteFunc(t2))), 1081 ); 1082 } 1083 1084 #[test] 1085 #[should_panic] 1086 fn ref_matches_ty_wrong_engine() { 1087 let e1 = Engine::default(); 1088 let e2 = Engine::default(); 1089 1090 let t1 = FuncType::new(&e1, None, None); 1091 let t2 = FuncType::new(&e2, None, None); 1092 1093 let mut s1 = Store::new(&e1, ()); 1094 let f = Func::new(&mut s1, t1.clone(), |_caller, _args, _results| Ok(())); 1095 1096 // Should panic. 1097 let _ = Ref::Func(Some(f)).matches_ty(&s1, &RefType::new(true, HeapType::ConcreteFunc(t2))); 1098 } 1099 } 1100