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