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