1 use crate::error::OutOfMemory; 2 use crate::prelude::*; 3 use crate::runtime::externals::Global as RuntimeGlobal; 4 use crate::runtime::externals::Table as RuntimeTable; 5 use crate::runtime::externals::Tag as RuntimeTag; 6 use crate::{AsContextMut, Extern, Func, Val}; 7 use crate::{Engine, type_registry::RegisteredType}; 8 use core::fmt::{self, Display, Write}; 9 use wasmtime_environ::WasmExnType; 10 use wasmtime_environ::{ 11 EngineOrModuleTypeIndex, EntityType, Global, IndexType, Limits, Memory, ModuleTypes, 12 PanicOnOom as _, Table, Tag, TypeTrace, VMSharedTypeIndex, WasmArrayType, 13 WasmCompositeInnerType, WasmCompositeType, WasmFieldType, WasmFuncType, WasmHeapType, 14 WasmRefType, WasmStorageType, WasmStructType, WasmSubType, WasmValType, 15 }; 16 17 pub(crate) mod matching; 18 19 // Type Representations 20 21 // Type attributes 22 23 /// Indicator of whether a global value, struct's field, or array type's 24 /// elements are mutable or not. 25 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] 26 pub enum Mutability { 27 /// The global value, struct field, or array elements are constant and the 28 /// value does not change. 29 Const, 30 /// The value of the global, struct field, or array elements can change over 31 /// time. 32 Var, 33 } 34 35 impl Mutability { 36 /// Is this constant? 37 #[inline] is_const(&self) -> bool38 pub fn is_const(&self) -> bool { 39 *self == Self::Const 40 } 41 42 /// Is this variable? 43 #[inline] is_var(&self) -> bool44 pub fn is_var(&self) -> bool { 45 *self == Self::Var 46 } 47 } 48 49 /// Indicator of whether a type is final or not. 50 /// 51 /// Final types may not be the supertype of other types. 52 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] 53 pub enum Finality { 54 /// The associated type is final. 55 Final, 56 /// The associated type is not final. 57 NonFinal, 58 } 59 60 impl Finality { 61 /// Is this final? 62 #[inline] is_final(&self) -> bool63 pub fn is_final(&self) -> bool { 64 *self == Self::Final 65 } 66 67 /// Is this non-final? 68 #[inline] is_non_final(&self) -> bool69 pub fn is_non_final(&self) -> bool { 70 *self == Self::NonFinal 71 } 72 } 73 74 // Value Types 75 76 /// A list of all possible value types in WebAssembly. 77 /// 78 /// # Subtyping and Equality 79 /// 80 /// `ValType` does not implement `Eq`, because reference types have a subtyping 81 /// relationship, and so 99.99% of the time you actually want to check whether 82 /// one type matches (i.e. is a subtype of) another type. You can use the 83 /// [`ValType::matches`] and [`Val::matches_ty`][crate::Val::matches_ty] methods 84 /// to perform these types of checks. If, however, you are in that 0.01% 85 /// scenario where you need to check precise equality between types, you can use 86 /// the [`ValType::eq`] method. 87 #[derive(Clone, Hash)] 88 pub enum ValType { 89 // NB: the ordering of variants here is intended to match the ordering in 90 // `wasmtime_environ::WasmType` to help improve codegen when converting. 91 // 92 /// Signed 32 bit integer. 93 I32, 94 /// Signed 64 bit integer. 95 I64, 96 /// Floating point 32 bit integer. 97 F32, 98 /// Floating point 64 bit integer. 99 F64, 100 /// A 128 bit number. 101 V128, 102 /// An opaque reference to some type on the heap. 103 Ref(RefType), 104 } 105 106 impl fmt::Debug for ValType { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 108 fmt::Display::fmt(self, f) 109 } 110 } 111 112 impl Display for ValType { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result113 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 114 match self { 115 ValType::I32 => write!(f, "i32"), 116 ValType::I64 => write!(f, "i64"), 117 ValType::F32 => write!(f, "f32"), 118 ValType::F64 => write!(f, "f64"), 119 ValType::V128 => write!(f, "v128"), 120 ValType::Ref(r) => Display::fmt(r, f), 121 } 122 } 123 } 124 125 impl From<RefType> for ValType { 126 #[inline] from(r: RefType) -> Self127 fn from(r: RefType) -> Self { 128 ValType::Ref(r) 129 } 130 } 131 132 impl ValType { 133 /// The `externref` type, aka `(ref null extern)`. 134 pub const EXTERNREF: Self = ValType::Ref(RefType::EXTERNREF); 135 136 /// The `nullexternref` type, aka `(ref null noextern)`. 137 pub const NULLEXTERNREF: Self = ValType::Ref(RefType::NULLEXTERNREF); 138 139 /// The `funcref` type, aka `(ref null func)`. 140 pub const FUNCREF: Self = ValType::Ref(RefType::FUNCREF); 141 142 /// The `nullfuncref` type, aka `(ref null nofunc)`. 143 pub const NULLFUNCREF: Self = ValType::Ref(RefType::NULLFUNCREF); 144 145 /// The `anyref` type, aka `(ref null any)`. 146 pub const ANYREF: Self = ValType::Ref(RefType::ANYREF); 147 148 /// The `eqref` type, aka `(ref null eq)`. 149 pub const EQREF: Self = ValType::Ref(RefType::EQREF); 150 151 /// The `i31ref` type, aka `(ref null i31)`. 152 pub const I31REF: Self = ValType::Ref(RefType::I31REF); 153 154 /// The `arrayref` type, aka `(ref null array)`. 155 pub const ARRAYREF: Self = ValType::Ref(RefType::ARRAYREF); 156 157 /// The `structref` type, aka `(ref null struct)`. 158 pub const STRUCTREF: Self = ValType::Ref(RefType::STRUCTREF); 159 160 /// The `nullref` type, aka `(ref null none)`. 161 pub const NULLREF: Self = ValType::Ref(RefType::NULLREF); 162 163 /// The `contref` type, aka `(ref null cont)`. 164 pub const CONTREF: Self = ValType::Ref(RefType::CONTREF); 165 166 /// The `nullcontref` type, aka. `(ref null nocont)`. 167 pub const NULLCONTREF: Self = ValType::Ref(RefType::NULLCONTREF); 168 169 /// The `exnref` type, aka `(ref null exn)`. 170 pub const EXNREF: Self = ValType::Ref(RefType::EXNREF); 171 172 /// The `nullexnref` type, aka `(ref null noexn)`. 173 pub const NULLEXNREF: Self = ValType::Ref(RefType::NULLEXNREF); 174 175 /// Returns true if `ValType` matches any of the numeric types. (e.g. `I32`, 176 /// `I64`, `F32`, `F64`). 177 #[inline] is_num(&self) -> bool178 pub fn is_num(&self) -> bool { 179 match self { 180 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => true, 181 _ => false, 182 } 183 } 184 185 /// Is this the `i32` type? 186 #[inline] is_i32(&self) -> bool187 pub fn is_i32(&self) -> bool { 188 matches!(self, ValType::I32) 189 } 190 191 /// Is this the `i64` type? 192 #[inline] is_i64(&self) -> bool193 pub fn is_i64(&self) -> bool { 194 matches!(self, ValType::I64) 195 } 196 197 /// Is this the `f32` type? 198 #[inline] is_f32(&self) -> bool199 pub fn is_f32(&self) -> bool { 200 matches!(self, ValType::F32) 201 } 202 203 /// Is this the `f64` type? 204 #[inline] is_f64(&self) -> bool205 pub fn is_f64(&self) -> bool { 206 matches!(self, ValType::F64) 207 } 208 209 /// Is this the `v128` type? 210 #[inline] is_v128(&self) -> bool211 pub fn is_v128(&self) -> bool { 212 matches!(self, ValType::V128) 213 } 214 215 /// Returns true if `ValType` is any kind of reference type. 216 #[inline] is_ref(&self) -> bool217 pub fn is_ref(&self) -> bool { 218 matches!(self, ValType::Ref(_)) 219 } 220 221 /// Is this the `funcref` (aka `(ref null func)`) type? 222 #[inline] is_funcref(&self) -> bool223 pub fn is_funcref(&self) -> bool { 224 matches!( 225 self, 226 ValType::Ref(RefType { 227 is_nullable: true, 228 heap_type: HeapType::Func 229 }) 230 ) 231 } 232 233 /// Is this the `externref` (aka `(ref null extern)`) type? 234 #[inline] is_externref(&self) -> bool235 pub fn is_externref(&self) -> bool { 236 matches!( 237 self, 238 ValType::Ref(RefType { 239 is_nullable: true, 240 heap_type: HeapType::Extern 241 }) 242 ) 243 } 244 245 /// Is this the `anyref` (aka `(ref null any)`) type? 246 #[inline] is_anyref(&self) -> bool247 pub fn is_anyref(&self) -> bool { 248 matches!( 249 self, 250 ValType::Ref(RefType { 251 is_nullable: true, 252 heap_type: HeapType::Any 253 }) 254 ) 255 } 256 257 /// Is this the `contref` (aka `(ref null cont)`) type? 258 #[inline] is_contref(&self) -> bool259 pub fn is_contref(&self) -> bool { 260 matches!( 261 self, 262 ValType::Ref(RefType { 263 is_nullable: true, 264 heap_type: HeapType::Cont 265 }) 266 ) 267 } 268 269 /// Get the underlying reference type, if this value type is a reference 270 /// type. 271 #[inline] as_ref(&self) -> Option<&RefType>272 pub fn as_ref(&self) -> Option<&RefType> { 273 match self { 274 ValType::Ref(r) => Some(r), 275 _ => None, 276 } 277 } 278 279 /// Get the underlying reference type, panicking if this value type is not a 280 /// reference type. 281 #[inline] unwrap_ref(&self) -> &RefType282 pub fn unwrap_ref(&self) -> &RefType { 283 self.as_ref() 284 .expect("ValType::unwrap_ref on a non-reference type") 285 } 286 287 /// Does this value type match the other type? 288 /// 289 /// That is, is this value type a subtype of the other? 290 /// 291 /// # Panics 292 /// 293 /// Panics if either type is associated with a different engine from the 294 /// other. matches(&self, other: &ValType) -> bool295 pub fn matches(&self, other: &ValType) -> bool { 296 match (self, other) { 297 (Self::I32, Self::I32) => true, 298 (Self::I64, Self::I64) => true, 299 (Self::F32, Self::F32) => true, 300 (Self::F64, Self::F64) => true, 301 (Self::V128, Self::V128) => true, 302 (Self::Ref(a), Self::Ref(b)) => a.matches(b), 303 (Self::I32, _) 304 | (Self::I64, _) 305 | (Self::F32, _) 306 | (Self::F64, _) 307 | (Self::V128, _) 308 | (Self::Ref(_), _) => false, 309 } 310 } 311 312 /// Is value type `a` precisely equal to value type `b`? 313 /// 314 /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they 315 /// are not exactly the same value type. 316 /// 317 /// # Panics 318 /// 319 /// Panics if either type is associated with a different engine. eq(a: &Self, b: &Self) -> bool320 pub fn eq(a: &Self, b: &Self) -> bool { 321 a.matches(b) && b.matches(a) 322 } 323 324 /// Is this a `VMGcRef` type that is not i31 and is not an uninhabited 325 /// bottom type? 326 #[inline] is_vmgcref_type_and_points_to_object(&self) -> bool327 pub(crate) fn is_vmgcref_type_and_points_to_object(&self) -> bool { 328 match self { 329 ValType::Ref(r) => r.is_vmgcref_type_and_points_to_object(), 330 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => false, 331 } 332 } 333 ensure_matches(&self, engine: &Engine, other: &ValType) -> Result<()>334 pub(crate) fn ensure_matches(&self, engine: &Engine, other: &ValType) -> Result<()> { 335 if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) { 336 bail!("type used with wrong engine"); 337 } 338 if self.matches(other) { 339 Ok(()) 340 } else { 341 bail!("type mismatch: expected {other}, found {self}") 342 } 343 } 344 comes_from_same_engine(&self, engine: &Engine) -> bool345 pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool { 346 match self { 347 Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128 => true, 348 Self::Ref(r) => r.comes_from_same_engine(engine), 349 } 350 } 351 to_wasm_type(&self) -> WasmValType352 pub(crate) fn to_wasm_type(&self) -> WasmValType { 353 match self { 354 Self::I32 => WasmValType::I32, 355 Self::I64 => WasmValType::I64, 356 Self::F32 => WasmValType::F32, 357 Self::F64 => WasmValType::F64, 358 Self::V128 => WasmValType::V128, 359 Self::Ref(r) => WasmValType::Ref(r.to_wasm_type()), 360 } 361 } 362 363 #[inline] from_wasm_type(engine: &Engine, ty: &WasmValType) -> Self364 pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmValType) -> Self { 365 match ty { 366 WasmValType::I32 => Self::I32, 367 WasmValType::I64 => Self::I64, 368 WasmValType::F32 => Self::F32, 369 WasmValType::F64 => Self::F64, 370 WasmValType::V128 => Self::V128, 371 WasmValType::Ref(r) => Self::Ref(RefType::from_wasm_type(engine, r)), 372 } 373 } 374 /// Construct a default value. Returns None for non-nullable Ref types, which have no default. default_value(&self) -> Option<Val>375 pub fn default_value(&self) -> Option<Val> { 376 match self { 377 ValType::I32 => Some(Val::I32(0)), 378 ValType::I64 => Some(Val::I64(0)), 379 ValType::F32 => Some(Val::F32(0)), 380 ValType::F64 => Some(Val::F64(0)), 381 ValType::V128 => Some(Val::V128(0.into())), 382 ValType::Ref(r) => { 383 if r.is_nullable() { 384 Some(Val::null_ref(r.heap_type())) 385 } else { 386 None 387 } 388 } 389 } 390 } 391 into_registered_type(self) -> Option<RegisteredType>392 pub(crate) fn into_registered_type(self) -> Option<RegisteredType> { 393 match self { 394 ValType::Ref(ty) => ty.into_registered_type(), 395 _ => None, 396 } 397 } 398 } 399 400 /// Opaque references to data in the Wasm heap or to host data. 401 /// 402 /// # Subtyping and Equality 403 /// 404 /// `RefType` does not implement `Eq`, because reference types have a subtyping 405 /// relationship, and so 99.99% of the time you actually want to check whether 406 /// one type matches (i.e. is a subtype of) another type. You can use the 407 /// [`RefType::matches`] and [`Ref::matches_ty`][crate::Ref::matches_ty] methods 408 /// to perform these types of checks. If, however, you are in that 0.01% 409 /// scenario where you need to check precise equality between types, you can use 410 /// the [`RefType::eq`] method. 411 #[derive(Clone, Hash)] 412 pub struct RefType { 413 is_nullable: bool, 414 heap_type: HeapType, 415 } 416 417 impl fmt::Debug for RefType { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result418 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 419 Display::fmt(self, f) 420 } 421 } 422 423 impl fmt::Display for RefType { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result424 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 425 write!(f, "(ref ")?; 426 if self.is_nullable() { 427 write!(f, "null ")?; 428 } 429 write!(f, "{})", self.heap_type()) 430 } 431 } 432 433 impl RefType { 434 /// The `externref` type, aka `(ref null extern)`. 435 pub const EXTERNREF: Self = RefType { 436 is_nullable: true, 437 heap_type: HeapType::Extern, 438 }; 439 440 /// The `nullexternref` type, aka `(ref null noextern)`. 441 pub const NULLEXTERNREF: Self = RefType { 442 is_nullable: true, 443 heap_type: HeapType::NoExtern, 444 }; 445 446 /// The `funcref` type, aka `(ref null func)`. 447 pub const FUNCREF: Self = RefType { 448 is_nullable: true, 449 heap_type: HeapType::Func, 450 }; 451 452 /// The `nullfuncref` type, aka `(ref null nofunc)`. 453 pub const NULLFUNCREF: Self = RefType { 454 is_nullable: true, 455 heap_type: HeapType::NoFunc, 456 }; 457 458 /// The `anyref` type, aka `(ref null any)`. 459 pub const ANYREF: Self = RefType { 460 is_nullable: true, 461 heap_type: HeapType::Any, 462 }; 463 464 /// The `eqref` type, aka `(ref null eq)`. 465 pub const EQREF: Self = RefType { 466 is_nullable: true, 467 heap_type: HeapType::Eq, 468 }; 469 470 /// The `i31ref` type, aka `(ref null i31)`. 471 pub const I31REF: Self = RefType { 472 is_nullable: true, 473 heap_type: HeapType::I31, 474 }; 475 476 /// The `arrayref` type, aka `(ref null array)`. 477 pub const ARRAYREF: Self = RefType { 478 is_nullable: true, 479 heap_type: HeapType::Array, 480 }; 481 482 /// The `structref` type, aka `(ref null struct)`. 483 pub const STRUCTREF: Self = RefType { 484 is_nullable: true, 485 heap_type: HeapType::Struct, 486 }; 487 488 /// The `nullref` type, aka `(ref null none)`. 489 pub const NULLREF: Self = RefType { 490 is_nullable: true, 491 heap_type: HeapType::None, 492 }; 493 494 /// The `contref` type, aka `(ref null cont)`. 495 pub const CONTREF: Self = RefType { 496 is_nullable: true, 497 heap_type: HeapType::Cont, 498 }; 499 500 /// The `nullcontref` type, aka `(ref null nocont)`. 501 pub const NULLCONTREF: Self = RefType { 502 is_nullable: true, 503 heap_type: HeapType::NoCont, 504 }; 505 506 /// The `exnref` type, aka `(ref null exn)`. 507 pub const EXNREF: Self = RefType { 508 is_nullable: true, 509 heap_type: HeapType::Exn, 510 }; 511 512 /// The `nullexnref` type, aka `(ref null noexn)`. 513 pub const NULLEXNREF: Self = RefType { 514 is_nullable: true, 515 heap_type: HeapType::NoExn, 516 }; 517 518 /// Construct a new reference type. new(is_nullable: bool, heap_type: HeapType) -> RefType519 pub fn new(is_nullable: bool, heap_type: HeapType) -> RefType { 520 RefType { 521 is_nullable, 522 heap_type, 523 } 524 } 525 526 /// Can this type of reference be null? is_nullable(&self) -> bool527 pub fn is_nullable(&self) -> bool { 528 self.is_nullable 529 } 530 531 /// The heap type that this is a reference to. 532 #[inline] heap_type(&self) -> &HeapType533 pub fn heap_type(&self) -> &HeapType { 534 &self.heap_type 535 } 536 537 /// Does this reference type match the other? 538 /// 539 /// That is, is this reference type a subtype of the other? 540 /// 541 /// # Panics 542 /// 543 /// Panics if either type is associated with a different engine from the 544 /// other. matches(&self, other: &RefType) -> bool545 pub fn matches(&self, other: &RefType) -> bool { 546 if self.is_nullable() && !other.is_nullable() { 547 return false; 548 } 549 self.heap_type().matches(other.heap_type()) 550 } 551 552 /// Is reference type `a` precisely equal to reference type `b`? 553 /// 554 /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they 555 /// are not exactly the same reference type. 556 /// 557 /// # Panics 558 /// 559 /// Panics if either type is associated with a different engine. eq(a: &RefType, b: &RefType) -> bool560 pub fn eq(a: &RefType, b: &RefType) -> bool { 561 a.matches(b) && b.matches(a) 562 } 563 ensure_matches(&self, engine: &Engine, other: &RefType) -> Result<()>564 pub(crate) fn ensure_matches(&self, engine: &Engine, other: &RefType) -> Result<()> { 565 if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) { 566 bail!("type used with wrong engine"); 567 } 568 if self.matches(other) { 569 Ok(()) 570 } else { 571 bail!("type mismatch: expected {other}, found {self}") 572 } 573 } 574 comes_from_same_engine(&self, engine: &Engine) -> bool575 pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool { 576 self.heap_type().comes_from_same_engine(engine) 577 } 578 to_wasm_type(&self) -> WasmRefType579 pub(crate) fn to_wasm_type(&self) -> WasmRefType { 580 WasmRefType { 581 nullable: self.is_nullable(), 582 heap_type: self.heap_type().to_wasm_type(), 583 } 584 } 585 from_wasm_type(engine: &Engine, ty: &WasmRefType) -> RefType586 pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmRefType) -> RefType { 587 RefType { 588 is_nullable: ty.nullable, 589 heap_type: HeapType::from_wasm_type(engine, &ty.heap_type), 590 } 591 } 592 is_vmgcref_type_and_points_to_object(&self) -> bool593 pub(crate) fn is_vmgcref_type_and_points_to_object(&self) -> bool { 594 self.heap_type().is_vmgcref_type_and_points_to_object() 595 } 596 into_registered_type(self) -> Option<RegisteredType>597 pub(crate) fn into_registered_type(self) -> Option<RegisteredType> { 598 self.heap_type.into_registered_type() 599 } 600 } 601 602 /// The heap types that can Wasm can have references to. 603 /// 604 /// # Subtyping Hierarchy 605 /// 606 /// Wasm has three different heap type hierarchies: 607 /// 608 /// 1. Function types 609 /// 2. External types 610 /// 3. Internal (struct and array) types 611 /// 4. Exception types 612 /// 613 /// Each hierarchy has a top type (the common supertype of which everything else 614 /// in its hierarchy is a subtype of) and a bottom type (the common subtype of 615 /// which everything else in its hierarchy is supertype of). 616 /// 617 /// ## Function Types Hierarchy 618 /// 619 /// The top of the function types hierarchy is `func`; the bottom is 620 /// `nofunc`. In between are all the concrete function types. 621 /// 622 /// ```text 623 /// func 624 /// / / \ \ 625 /// ,---------------- / \ -------------------------. 626 /// / / \ \ 627 /// | ,---- -----------. | 628 /// | | | | 629 /// | | | | 630 /// (func) (func (param i32)) (func (param i32 i32)) ... 631 /// | | | | 632 /// | | | | 633 /// | `---. ,----------' | 634 /// \ \ / / 635 /// `---------------. \ / ,------------------------' 636 /// \ \ / / 637 /// nofunc 638 /// ``` 639 /// 640 /// Additionally, some concrete function types are sub- or supertypes of other 641 /// concrete function types, if that was declared in their definition. For 642 /// simplicity, this isn't depicted in the diagram above. 643 /// 644 /// ## External 645 /// 646 /// The top of the external types hierarchy is `extern`; the bottom is 647 /// `noextern`. There are no concrete types in this hierarchy. 648 /// 649 /// ```text 650 /// extern 651 /// | 652 /// noextern 653 /// ``` 654 /// 655 /// ## Internal 656 /// 657 /// The top of the internal types hierarchy is `any`; the bottom is `none`. The 658 /// `eq` type is the common supertype of all types that can be compared for 659 /// equality. The `struct` and `array` types are the common supertypes of all 660 /// concrete struct and array types respectively. The `i31` type represents 661 /// unboxed 31-bit integers. 662 /// 663 /// ```text 664 /// any 665 /// / | \ 666 /// ,----------------------------' | `--------------------------. 667 /// / | \ 668 /// | .--------' | 669 /// | | | 670 /// | struct array 671 /// | / | \ / | \ 672 /// i31 ,-----' | '-----. ,-----' | `-----. 673 /// | / | \ / | \ 674 /// | | | | | | | 675 /// | (struct) (struct i32) ... (array i32) (array i64) ... 676 /// | | | | | | | 677 /// | \ | / \ | / 678 /// \ `-----. | ,-----' `-----. | ,-----' 679 /// \ \ | / \ | / 680 /// \ \ | / \ | / 681 /// \ \| / \| / 682 /// \ |/ |/ 683 /// \ | | 684 /// \ | / 685 /// \ '--------. / 686 /// \ | / 687 /// `--------------------. | ,-----------------------' 688 /// \ | / 689 /// none 690 /// ``` 691 /// 692 /// Additionally, concrete struct and array types can be subtypes of other 693 /// concrete struct and array types respectively, if that was declared in their 694 /// definitions. Once again, this is omitted from the above diagram for 695 /// simplicity. 696 /// 697 /// ## Exceptions 698 /// 699 /// The top of the exception types hierarchy is `exn`; the bottom is 700 /// `noexn`. At the WebAssembly level, there are no concrete types in 701 /// this hierarchy. However, internally we do reify a heap type for 702 /// each tag, similar to how continuation objects work. 703 /// 704 /// ```text 705 /// exn 706 /// / | \ 707 /// (exn $t) ... 708 /// \ | / 709 /// noexn 710 /// ``` 711 /// 712 /// # Subtyping and Equality 713 /// 714 /// `HeapType` does not implement `Eq`, because heap types have a subtyping 715 /// relationship, and so 99.99% of the time you actually want to check whether 716 /// one type matches (i.e. is a subtype of) another type. You can use the 717 /// [`HeapType::matches`] method to perform these types of checks. If, however, 718 /// you are in that 0.01% scenario where you need to check precise equality 719 /// between types, you can use the [`HeapType::eq`] method. 720 #[derive(Debug, Clone, Hash)] 721 pub enum HeapType { 722 /// The abstract `extern` heap type represents external host data. 723 /// 724 /// This is the top type for the external type hierarchy, and therefore is 725 /// the common supertype of all external reference types. 726 Extern, 727 728 /// The abstract `noextern` heap type represents the null external 729 /// reference. 730 /// 731 /// This is the bottom type for the external type hierarchy, and therefore 732 /// is the common subtype of all external reference types. 733 NoExtern, 734 735 /// The abstract `func` heap type represents a reference to any kind of 736 /// function. 737 /// 738 /// This is the top type for the function references type hierarchy, and is 739 /// therefore a supertype of every function reference. 740 Func, 741 742 /// A reference to a function of a specific, concrete type. 743 /// 744 /// These are subtypes of `func` and supertypes of `nofunc`. 745 ConcreteFunc(FuncType), 746 747 /// The abstract `nofunc` heap type represents the null function reference. 748 /// 749 /// This is the bottom type for the function references type hierarchy, and 750 /// therefore `nofunc` is a subtype of all function reference types. 751 NoFunc, 752 753 /// The abstract `any` heap type represents all internal Wasm data. 754 /// 755 /// This is the top type of the internal type hierarchy, and is therefore a 756 /// supertype of all internal types (such as `eq`, `i31`, `struct`s, and 757 /// `array`s). 758 Any, 759 760 /// The abstract `eq` heap type represenets all internal Wasm references 761 /// that can be compared for equality. 762 /// 763 /// This is a subtype of `any` and a supertype of `i31`, `array`, `struct`, 764 /// and `none` heap types. 765 Eq, 766 767 /// The `i31` heap type represents unboxed 31-bit integers. 768 /// 769 /// This is a subtype of `any` and `eq`, and a supertype of `none`. 770 I31, 771 772 /// The abstract `array` heap type represents a reference to any kind of 773 /// array. 774 /// 775 /// This is a subtype of `any` and `eq`, and a supertype of all concrete 776 /// array types, as well as a supertype of the abstract `none` heap type. 777 Array, 778 779 /// A reference to an array of a specific, concrete type. 780 /// 781 /// These are subtypes of the `array` heap type (therefore also a subtype of 782 /// `any` and `eq`) and supertypes of the `none` heap type. 783 ConcreteArray(ArrayType), 784 785 /// The abstract `struct` heap type represents a reference to any kind of 786 /// struct. 787 /// 788 /// This is a subtype of `any` and `eq`, and a supertype of all concrete 789 /// struct types, as well as a supertype of the abstract `none` heap type. 790 Struct, 791 792 /// A reference to an struct of a specific, concrete type. 793 /// 794 /// These are subtypes of the `struct` heap type (therefore also a subtype 795 /// of `any` and `eq`) and supertypes of the `none` heap type. 796 ConcreteStruct(StructType), 797 798 /// The abstract `exn` heap type represents a reference to any 799 /// kind of exception. 800 /// 801 /// This is a supertype of the internal concrete exception heap 802 /// types and the `noexn` heap type. 803 Exn, 804 805 /// A concrete exception object with a specific tag. 806 /// 807 /// These are internal, not exposed at the Wasm level, but useful 808 /// in our implementation and host API. These are subtypes of 809 /// `exn` and supertypes of `noexn`. 810 ConcreteExn(ExnType), 811 812 /// A reference to a continuation of a specific, concrete type. 813 /// 814 /// These are subtypes of `cont` and supertypes of `nocont`. 815 ConcreteCont(ContType), 816 817 /// The `cont` heap type represents a reference to any kind of continuation. 818 /// 819 /// This is the top type for the continuation objects type hierarchy, and is 820 /// therefore a supertype of every continuation object. 821 Cont, 822 823 /// The `nocont` heap type represents the null continuation object. 824 /// 825 /// This is the bottom type for the continuation objects type hierarchy, and 826 /// therefore `nocont` is a subtype of all continuation object types. 827 NoCont, 828 829 /// The abstract `none` heap type represents the null internal reference. 830 /// 831 /// This is the bottom type for the internal type hierarchy, and therefore 832 /// `none` is a subtype of internal types. 833 None, 834 835 /// The `noexn` heap type represents the null exception object. 836 /// 837 /// This is the bottom type for the exception objects type hierarchy. 838 NoExn, 839 } 840 841 impl Display for HeapType { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result842 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 843 match self { 844 HeapType::Extern => write!(f, "extern"), 845 HeapType::NoExtern => write!(f, "noextern"), 846 HeapType::Func => write!(f, "func"), 847 HeapType::NoFunc => write!(f, "nofunc"), 848 HeapType::Any => write!(f, "any"), 849 HeapType::Eq => write!(f, "eq"), 850 HeapType::I31 => write!(f, "i31"), 851 HeapType::Array => write!(f, "array"), 852 HeapType::Struct => write!(f, "struct"), 853 HeapType::None => write!(f, "none"), 854 HeapType::ConcreteFunc(ty) => write!(f, "(concrete func {:?})", ty.type_index()), 855 HeapType::ConcreteArray(ty) => write!(f, "(concrete array {:?})", ty.type_index()), 856 HeapType::ConcreteStruct(ty) => write!(f, "(concrete struct {:?})", ty.type_index()), 857 HeapType::ConcreteCont(ty) => write!(f, "(concrete cont {:?})", ty.type_index()), 858 HeapType::ConcreteExn(ty) => write!(f, "(concrete exn {:?})", ty.type_index()), 859 HeapType::Cont => write!(f, "cont"), 860 HeapType::NoCont => write!(f, "nocont"), 861 HeapType::Exn => write!(f, "exn"), 862 HeapType::NoExn => write!(f, "noexn"), 863 } 864 } 865 } 866 867 impl From<FuncType> for HeapType { 868 #[inline] from(f: FuncType) -> Self869 fn from(f: FuncType) -> Self { 870 HeapType::ConcreteFunc(f) 871 } 872 } 873 874 impl From<ArrayType> for HeapType { 875 #[inline] from(a: ArrayType) -> Self876 fn from(a: ArrayType) -> Self { 877 HeapType::ConcreteArray(a) 878 } 879 } 880 881 impl From<StructType> for HeapType { 882 #[inline] from(s: StructType) -> Self883 fn from(s: StructType) -> Self { 884 HeapType::ConcreteStruct(s) 885 } 886 } 887 888 impl From<ContType> for HeapType { 889 #[inline] from(f: ContType) -> Self890 fn from(f: ContType) -> Self { 891 HeapType::ConcreteCont(f) 892 } 893 } 894 895 impl From<ExnType> for HeapType { 896 #[inline] from(e: ExnType) -> Self897 fn from(e: ExnType) -> Self { 898 HeapType::ConcreteExn(e) 899 } 900 } 901 902 impl HeapType { 903 /// Is this the abstract `extern` heap type? is_extern(&self) -> bool904 pub fn is_extern(&self) -> bool { 905 matches!(self, HeapType::Extern) 906 } 907 908 /// Is this the abstract `func` heap type? is_func(&self) -> bool909 pub fn is_func(&self) -> bool { 910 matches!(self, HeapType::Func) 911 } 912 913 /// Is this the abstract `nofunc` heap type? is_no_func(&self) -> bool914 pub fn is_no_func(&self) -> bool { 915 matches!(self, HeapType::NoFunc) 916 } 917 918 /// Is this the abstract `any` heap type? is_any(&self) -> bool919 pub fn is_any(&self) -> bool { 920 matches!(self, HeapType::Any) 921 } 922 923 /// Is this the abstract `i31` heap type? is_i31(&self) -> bool924 pub fn is_i31(&self) -> bool { 925 matches!(self, HeapType::I31) 926 } 927 928 /// Is this the abstract `none` heap type? is_none(&self) -> bool929 pub fn is_none(&self) -> bool { 930 matches!(self, HeapType::None) 931 } 932 933 /// Is this the abstract `cont` heap type? is_cont(&self) -> bool934 pub fn is_cont(&self) -> bool { 935 matches!(self, HeapType::Cont) 936 } 937 938 /// Is this the abstract `exn` heap type? is_exn(&self) -> bool939 pub fn is_exn(&self) -> bool { 940 matches!(self, HeapType::Exn) 941 } 942 943 /// Is this the abstract `noexn` heap type? is_no_exn(&self) -> bool944 pub fn is_no_exn(&self) -> bool { 945 matches!(self, HeapType::NoExn) 946 } 947 948 /// Is this an abstract type? 949 /// 950 /// Types that are not abstract are concrete, user-defined types. is_abstract(&self) -> bool951 pub fn is_abstract(&self) -> bool { 952 !self.is_concrete() 953 } 954 955 /// Is this a concrete, user-defined heap type? 956 /// 957 /// Types that are not concrete, user-defined types are abstract types. 958 #[inline] is_concrete(&self) -> bool959 pub fn is_concrete(&self) -> bool { 960 matches!( 961 self, 962 HeapType::ConcreteFunc(_) 963 | HeapType::ConcreteArray(_) 964 | HeapType::ConcreteStruct(_) 965 | HeapType::ConcreteCont(_) 966 | HeapType::ConcreteExn(_) 967 ) 968 } 969 970 /// Is this a concrete, user-defined function type? is_concrete_func(&self) -> bool971 pub fn is_concrete_func(&self) -> bool { 972 matches!(self, HeapType::ConcreteFunc(_)) 973 } 974 975 /// Get the underlying concrete, user-defined function type, if any. 976 /// 977 /// Returns `None` if this is not a concrete function type. as_concrete_func(&self) -> Option<&FuncType>978 pub fn as_concrete_func(&self) -> Option<&FuncType> { 979 match self { 980 HeapType::ConcreteFunc(f) => Some(f), 981 _ => None, 982 } 983 } 984 985 /// Get the underlying concrete, user-defined type, panicking if this is not 986 /// a concrete function type. unwrap_concrete_func(&self) -> &FuncType987 pub fn unwrap_concrete_func(&self) -> &FuncType { 988 self.as_concrete_func().unwrap() 989 } 990 991 /// Is this a concrete, user-defined array type? is_concrete_array(&self) -> bool992 pub fn is_concrete_array(&self) -> bool { 993 matches!(self, HeapType::ConcreteArray(_)) 994 } 995 996 /// Get the underlying concrete, user-defined array type, if any. 997 /// 998 /// Returns `None` for if this is not a concrete array type. as_concrete_array(&self) -> Option<&ArrayType>999 pub fn as_concrete_array(&self) -> Option<&ArrayType> { 1000 match self { 1001 HeapType::ConcreteArray(f) => Some(f), 1002 _ => None, 1003 } 1004 } 1005 1006 /// Get the underlying concrete, user-defined type, panicking if this is not 1007 /// a concrete array type. unwrap_concrete_array(&self) -> &ArrayType1008 pub fn unwrap_concrete_array(&self) -> &ArrayType { 1009 self.as_concrete_array().unwrap() 1010 } 1011 1012 /// Is this a concrete, user-defined continuation type? is_concrete_cont(&self) -> bool1013 pub fn is_concrete_cont(&self) -> bool { 1014 matches!(self, HeapType::ConcreteCont(_)) 1015 } 1016 1017 /// Get the underlying concrete, user-defined continuation type, if any. 1018 /// 1019 /// Returns `None` if this is not a concrete continuation type. as_concrete_cont(&self) -> Option<&ContType>1020 pub fn as_concrete_cont(&self) -> Option<&ContType> { 1021 match self { 1022 HeapType::ConcreteCont(f) => Some(f), 1023 _ => None, 1024 } 1025 } 1026 1027 /// Is this a concrete, user-defined struct type? is_concrete_struct(&self) -> bool1028 pub fn is_concrete_struct(&self) -> bool { 1029 matches!(self, HeapType::ConcreteStruct(_)) 1030 } 1031 1032 /// Get the underlying concrete, user-defined struct type, if any. 1033 /// 1034 /// Returns `None` for if this is not a concrete struct type. as_concrete_struct(&self) -> Option<&StructType>1035 pub fn as_concrete_struct(&self) -> Option<&StructType> { 1036 match self { 1037 HeapType::ConcreteStruct(f) => Some(f), 1038 _ => None, 1039 } 1040 } 1041 1042 /// Get the underlying concrete, user-defined type, panicking if this is not 1043 /// a concrete continuation type. unwrap_concrete_cont(&self) -> &ContType1044 pub fn unwrap_concrete_cont(&self) -> &ContType { 1045 self.as_concrete_cont().unwrap() 1046 } 1047 1048 /// Get the underlying concrete, user-defined type, panicking if this is not 1049 /// a concrete struct type. unwrap_concrete_struct(&self) -> &StructType1050 pub fn unwrap_concrete_struct(&self) -> &StructType { 1051 self.as_concrete_struct().unwrap() 1052 } 1053 1054 /// Is this a concrete, user-defined exception type? is_concrete_exn(&self) -> bool1055 pub fn is_concrete_exn(&self) -> bool { 1056 matches!(self, HeapType::ConcreteExn(_)) 1057 } 1058 1059 /// Get the underlying concrete, user-defined exception type, if any. 1060 /// 1061 /// Returns `None` if this is not a concrete exception type. as_concrete_exn(&self) -> Option<&ExnType>1062 pub fn as_concrete_exn(&self) -> Option<&ExnType> { 1063 match self { 1064 HeapType::ConcreteExn(e) => Some(e), 1065 _ => None, 1066 } 1067 } 1068 1069 /// Get the top type of this heap type's type hierarchy. 1070 /// 1071 /// The returned heap type is a supertype of all types in this heap type's 1072 /// type hierarchy. 1073 #[inline] top(&self) -> HeapType1074 pub fn top(&self) -> HeapType { 1075 match self { 1076 HeapType::Func | HeapType::ConcreteFunc(_) | HeapType::NoFunc => HeapType::Func, 1077 1078 HeapType::Extern | HeapType::NoExtern => HeapType::Extern, 1079 1080 HeapType::Any 1081 | HeapType::Eq 1082 | HeapType::I31 1083 | HeapType::Array 1084 | HeapType::ConcreteArray(_) 1085 | HeapType::Struct 1086 | HeapType::ConcreteStruct(_) 1087 | HeapType::None => HeapType::Any, 1088 1089 HeapType::Cont | HeapType::ConcreteCont(_) | HeapType::NoCont => HeapType::Cont, 1090 1091 HeapType::Exn | HeapType::ConcreteExn(_) | HeapType::NoExn => HeapType::Exn, 1092 } 1093 } 1094 1095 /// Is this the top type within its type hierarchy? 1096 #[inline] is_top(&self) -> bool1097 pub fn is_top(&self) -> bool { 1098 match self { 1099 HeapType::Any | HeapType::Extern | HeapType::Func | HeapType::Cont | HeapType::Exn => { 1100 true 1101 } 1102 _ => false, 1103 } 1104 } 1105 1106 /// Get the bottom type of this heap type's type hierarchy. 1107 /// 1108 /// The returned heap type is a subtype of all types in this heap type's 1109 /// type hierarchy. 1110 #[inline] bottom(&self) -> HeapType1111 pub fn bottom(&self) -> HeapType { 1112 match self { 1113 HeapType::Extern | HeapType::NoExtern => HeapType::NoExtern, 1114 1115 HeapType::Func | HeapType::ConcreteFunc(_) | HeapType::NoFunc => HeapType::NoFunc, 1116 1117 HeapType::Any 1118 | HeapType::Eq 1119 | HeapType::I31 1120 | HeapType::Array 1121 | HeapType::ConcreteArray(_) 1122 | HeapType::Struct 1123 | HeapType::ConcreteStruct(_) 1124 | HeapType::None => HeapType::None, 1125 1126 HeapType::Cont | HeapType::ConcreteCont(_) | HeapType::NoCont => HeapType::NoCont, 1127 1128 HeapType::Exn | HeapType::ConcreteExn(_) | HeapType::NoExn => HeapType::NoExn, 1129 } 1130 } 1131 1132 /// Is this the bottom type within its type hierarchy? 1133 #[inline] is_bottom(&self) -> bool1134 pub fn is_bottom(&self) -> bool { 1135 match self { 1136 HeapType::None 1137 | HeapType::NoExtern 1138 | HeapType::NoFunc 1139 | HeapType::NoCont 1140 | HeapType::NoExn => true, 1141 _ => false, 1142 } 1143 } 1144 1145 /// Does this heap type match the other heap type? 1146 /// 1147 /// That is, is this heap type a subtype of the other? 1148 /// 1149 /// # Panics 1150 /// 1151 /// Panics if either type is associated with a different engine from the 1152 /// other. matches(&self, other: &HeapType) -> bool1153 pub fn matches(&self, other: &HeapType) -> bool { 1154 match (self, other) { 1155 (HeapType::Extern, HeapType::Extern) => true, 1156 (HeapType::Extern, _) => false, 1157 1158 (HeapType::NoExtern, HeapType::NoExtern | HeapType::Extern) => true, 1159 (HeapType::NoExtern, _) => false, 1160 1161 (HeapType::NoFunc, HeapType::NoFunc | HeapType::ConcreteFunc(_) | HeapType::Func) => { 1162 true 1163 } 1164 (HeapType::NoFunc, _) => false, 1165 1166 (HeapType::ConcreteFunc(_), HeapType::Func) => true, 1167 (HeapType::ConcreteFunc(a), HeapType::ConcreteFunc(b)) => { 1168 assert!(a.comes_from_same_engine(b.engine())); 1169 a.engine() 1170 .signatures() 1171 .is_subtype(a.type_index(), b.type_index()) 1172 } 1173 (HeapType::ConcreteFunc(_), _) => false, 1174 1175 (HeapType::Func, HeapType::Func) => true, 1176 (HeapType::Func, _) => false, 1177 1178 (HeapType::Cont, HeapType::Cont) => true, 1179 (HeapType::Cont, _) => false, 1180 1181 (HeapType::NoCont, HeapType::NoCont | HeapType::ConcreteCont(_) | HeapType::Cont) => { 1182 true 1183 } 1184 (HeapType::NoCont, _) => false, 1185 1186 (HeapType::ConcreteCont(_), HeapType::Cont) => true, 1187 (HeapType::ConcreteCont(a), HeapType::ConcreteCont(b)) => a.matches(b), 1188 (HeapType::ConcreteCont(_), _) => false, 1189 1190 ( 1191 HeapType::None, 1192 HeapType::None 1193 | HeapType::ConcreteArray(_) 1194 | HeapType::Array 1195 | HeapType::ConcreteStruct(_) 1196 | HeapType::Struct 1197 | HeapType::I31 1198 | HeapType::Eq 1199 | HeapType::Any, 1200 ) => true, 1201 (HeapType::None, _) => false, 1202 1203 (HeapType::ConcreteArray(_), HeapType::Array | HeapType::Eq | HeapType::Any) => true, 1204 (HeapType::ConcreteArray(a), HeapType::ConcreteArray(b)) => { 1205 assert!(a.comes_from_same_engine(b.engine())); 1206 a.engine() 1207 .signatures() 1208 .is_subtype(a.type_index(), b.type_index()) 1209 } 1210 (HeapType::ConcreteArray(_), _) => false, 1211 1212 (HeapType::Array, HeapType::Array | HeapType::Eq | HeapType::Any) => true, 1213 (HeapType::Array, _) => false, 1214 1215 (HeapType::ConcreteStruct(_), HeapType::Struct | HeapType::Eq | HeapType::Any) => true, 1216 (HeapType::ConcreteStruct(a), HeapType::ConcreteStruct(b)) => { 1217 assert!(a.comes_from_same_engine(b.engine())); 1218 a.engine() 1219 .signatures() 1220 .is_subtype(a.type_index(), b.type_index()) 1221 } 1222 (HeapType::ConcreteStruct(_), _) => false, 1223 1224 (HeapType::Struct, HeapType::Struct | HeapType::Eq | HeapType::Any) => true, 1225 (HeapType::Struct, _) => false, 1226 1227 (HeapType::I31, HeapType::I31 | HeapType::Eq | HeapType::Any) => true, 1228 (HeapType::I31, _) => false, 1229 1230 (HeapType::Eq, HeapType::Eq | HeapType::Any) => true, 1231 (HeapType::Eq, _) => false, 1232 1233 (HeapType::Any, HeapType::Any) => true, 1234 (HeapType::Any, _) => false, 1235 1236 (HeapType::NoExn, HeapType::Exn | HeapType::ConcreteExn(_) | HeapType::NoExn) => true, 1237 (HeapType::NoExn, _) => false, 1238 1239 (HeapType::ConcreteExn(_), HeapType::Exn) => true, 1240 (HeapType::ConcreteExn(a), HeapType::ConcreteExn(b)) => a.matches(b), 1241 (HeapType::ConcreteExn(_), _) => false, 1242 1243 (HeapType::Exn, HeapType::Exn) => true, 1244 (HeapType::Exn, _) => false, 1245 } 1246 } 1247 1248 /// Is heap type `a` precisely equal to heap type `b`? 1249 /// 1250 /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they 1251 /// are not exactly the same heap type. 1252 /// 1253 /// # Panics 1254 /// 1255 /// Panics if either type is associated with a different engine from the 1256 /// other. eq(a: &HeapType, b: &HeapType) -> bool1257 pub fn eq(a: &HeapType, b: &HeapType) -> bool { 1258 a.matches(b) && b.matches(a) 1259 } 1260 ensure_matches(&self, engine: &Engine, other: &HeapType) -> Result<()>1261 pub(crate) fn ensure_matches(&self, engine: &Engine, other: &HeapType) -> Result<()> { 1262 if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) { 1263 bail!("type used with wrong engine"); 1264 } 1265 if self.matches(other) { 1266 Ok(()) 1267 } else { 1268 bail!("type mismatch: expected {other}, found {self}"); 1269 } 1270 } 1271 comes_from_same_engine(&self, engine: &Engine) -> bool1272 pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool { 1273 match self { 1274 HeapType::Extern 1275 | HeapType::NoExtern 1276 | HeapType::Func 1277 | HeapType::NoFunc 1278 | HeapType::Any 1279 | HeapType::Eq 1280 | HeapType::I31 1281 | HeapType::Array 1282 | HeapType::Struct 1283 | HeapType::Cont 1284 | HeapType::NoCont 1285 | HeapType::Exn 1286 | HeapType::NoExn 1287 | HeapType::None => true, 1288 HeapType::ConcreteFunc(ty) => ty.comes_from_same_engine(engine), 1289 HeapType::ConcreteArray(ty) => ty.comes_from_same_engine(engine), 1290 HeapType::ConcreteStruct(ty) => ty.comes_from_same_engine(engine), 1291 HeapType::ConcreteCont(ty) => ty.comes_from_same_engine(engine), 1292 HeapType::ConcreteExn(ty) => ty.comes_from_same_engine(engine), 1293 } 1294 } 1295 to_wasm_type(&self) -> WasmHeapType1296 pub(crate) fn to_wasm_type(&self) -> WasmHeapType { 1297 match self { 1298 HeapType::Extern => WasmHeapType::Extern, 1299 HeapType::NoExtern => WasmHeapType::NoExtern, 1300 HeapType::Func => WasmHeapType::Func, 1301 HeapType::NoFunc => WasmHeapType::NoFunc, 1302 HeapType::Any => WasmHeapType::Any, 1303 HeapType::Eq => WasmHeapType::Eq, 1304 HeapType::I31 => WasmHeapType::I31, 1305 HeapType::Array => WasmHeapType::Array, 1306 HeapType::Struct => WasmHeapType::Struct, 1307 HeapType::None => WasmHeapType::None, 1308 HeapType::ConcreteFunc(f) => { 1309 WasmHeapType::ConcreteFunc(EngineOrModuleTypeIndex::Engine(f.type_index())) 1310 } 1311 HeapType::ConcreteArray(a) => { 1312 WasmHeapType::ConcreteArray(EngineOrModuleTypeIndex::Engine(a.type_index())) 1313 } 1314 HeapType::ConcreteStruct(a) => { 1315 WasmHeapType::ConcreteStruct(EngineOrModuleTypeIndex::Engine(a.type_index())) 1316 } 1317 HeapType::Cont => WasmHeapType::Cont, 1318 HeapType::NoCont => WasmHeapType::NoCont, 1319 HeapType::ConcreteCont(c) => { 1320 WasmHeapType::ConcreteCont(EngineOrModuleTypeIndex::Engine(c.type_index())) 1321 } 1322 HeapType::Exn => WasmHeapType::Exn, 1323 HeapType::NoExn => WasmHeapType::NoExn, 1324 HeapType::ConcreteExn(e) => { 1325 WasmHeapType::ConcreteExn(EngineOrModuleTypeIndex::Engine(e.type_index())) 1326 } 1327 } 1328 } 1329 from_wasm_type(engine: &Engine, ty: &WasmHeapType) -> HeapType1330 pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmHeapType) -> HeapType { 1331 match ty { 1332 WasmHeapType::Extern => HeapType::Extern, 1333 WasmHeapType::NoExtern => HeapType::NoExtern, 1334 WasmHeapType::Func => HeapType::Func, 1335 WasmHeapType::NoFunc => HeapType::NoFunc, 1336 WasmHeapType::Any => HeapType::Any, 1337 WasmHeapType::Eq => HeapType::Eq, 1338 WasmHeapType::I31 => HeapType::I31, 1339 WasmHeapType::Array => HeapType::Array, 1340 WasmHeapType::Struct => HeapType::Struct, 1341 WasmHeapType::None => HeapType::None, 1342 WasmHeapType::ConcreteFunc(EngineOrModuleTypeIndex::Engine(idx)) => { 1343 HeapType::ConcreteFunc(FuncType::from_shared_type_index(engine, *idx)) 1344 } 1345 WasmHeapType::ConcreteArray(EngineOrModuleTypeIndex::Engine(idx)) => { 1346 HeapType::ConcreteArray(ArrayType::from_shared_type_index(engine, *idx)) 1347 } 1348 WasmHeapType::ConcreteStruct(EngineOrModuleTypeIndex::Engine(idx)) => { 1349 HeapType::ConcreteStruct(StructType::from_shared_type_index(engine, *idx)) 1350 } 1351 1352 WasmHeapType::ConcreteFunc(EngineOrModuleTypeIndex::Module(_)) 1353 | WasmHeapType::ConcreteFunc(EngineOrModuleTypeIndex::RecGroup(_)) 1354 | WasmHeapType::ConcreteArray(EngineOrModuleTypeIndex::Module(_)) 1355 | WasmHeapType::ConcreteArray(EngineOrModuleTypeIndex::RecGroup(_)) 1356 | WasmHeapType::ConcreteStruct(EngineOrModuleTypeIndex::Module(_)) 1357 | WasmHeapType::ConcreteStruct(EngineOrModuleTypeIndex::RecGroup(_)) 1358 | WasmHeapType::ConcreteCont(EngineOrModuleTypeIndex::Module(_)) 1359 | WasmHeapType::ConcreteCont(EngineOrModuleTypeIndex::RecGroup(_)) 1360 | WasmHeapType::ConcreteExn(EngineOrModuleTypeIndex::Module(_)) 1361 | WasmHeapType::ConcreteExn(EngineOrModuleTypeIndex::RecGroup(_)) => { 1362 panic!("HeapType::from_wasm_type on non-canonicalized-for-runtime-usage heap type") 1363 } 1364 WasmHeapType::Cont => HeapType::Cont, 1365 WasmHeapType::NoCont => HeapType::NoCont, 1366 WasmHeapType::ConcreteCont(EngineOrModuleTypeIndex::Engine(idx)) => { 1367 HeapType::ConcreteCont(ContType::from_shared_type_index(engine, *idx)) 1368 } 1369 WasmHeapType::Exn => HeapType::Exn, 1370 WasmHeapType::NoExn => HeapType::NoExn, 1371 WasmHeapType::ConcreteExn(EngineOrModuleTypeIndex::Engine(idx)) => { 1372 HeapType::ConcreteExn(ExnType::from_shared_type_index(engine, *idx)) 1373 } 1374 } 1375 } 1376 as_registered_type(&self) -> Option<&RegisteredType>1377 pub(crate) fn as_registered_type(&self) -> Option<&RegisteredType> { 1378 match self { 1379 HeapType::ConcreteCont(c) => Some(&c.registered_type), 1380 HeapType::ConcreteFunc(f) => Some(&f.registered_type), 1381 HeapType::ConcreteArray(a) => Some(&a.registered_type), 1382 HeapType::ConcreteStruct(a) => Some(&a.registered_type), 1383 HeapType::ConcreteExn(e) => Some(&e.registered_type), 1384 1385 HeapType::Extern 1386 | HeapType::NoExtern 1387 | HeapType::Func 1388 | HeapType::NoFunc 1389 | HeapType::Any 1390 | HeapType::Eq 1391 | HeapType::I31 1392 | HeapType::Array 1393 | HeapType::Struct 1394 | HeapType::Cont 1395 | HeapType::NoCont 1396 | HeapType::Exn 1397 | HeapType::NoExn 1398 | HeapType::None => None, 1399 } 1400 } 1401 1402 #[inline] is_vmgcref_type(&self) -> bool1403 pub(crate) fn is_vmgcref_type(&self) -> bool { 1404 match self.top() { 1405 Self::Any | Self::Extern | Self::Exn => true, 1406 Self::Func => false, 1407 Self::Cont => false, 1408 ty => unreachable!("not a top type: {ty:?}"), 1409 } 1410 } 1411 1412 /// Is this a `VMGcRef` type that is not i31 and is not an uninhabited 1413 /// bottom type? 1414 #[inline] is_vmgcref_type_and_points_to_object(&self) -> bool1415 pub(crate) fn is_vmgcref_type_and_points_to_object(&self) -> bool { 1416 self.is_vmgcref_type() 1417 && !matches!( 1418 self, 1419 HeapType::I31 | HeapType::NoExtern | HeapType::NoFunc | HeapType::None 1420 ) 1421 } 1422 into_registered_type(self) -> Option<RegisteredType>1423 pub(crate) fn into_registered_type(self) -> Option<RegisteredType> { 1424 use HeapType::*; 1425 match self { 1426 ConcreteFunc(ty) => Some(ty.registered_type), 1427 ConcreteArray(ty) => Some(ty.registered_type), 1428 ConcreteStruct(ty) => Some(ty.registered_type), 1429 ConcreteCont(ty) => Some(ty.registered_type), 1430 ConcreteExn(ty) => Some(ty.registered_type), 1431 Extern | NoExtern | Func | NoFunc | Any | Eq | I31 | Array | Struct | Cont | NoCont 1432 | Exn | NoExn | None => Option::None, 1433 } 1434 } 1435 } 1436 1437 // External Types 1438 1439 /// A list of all possible types which can be externally referenced from a 1440 /// WebAssembly module. 1441 /// 1442 /// This list can be found in [`ImportType`] or [`ExportType`], so these types 1443 /// can either be imported or exported. 1444 #[derive(Debug, Clone)] 1445 pub enum ExternType { 1446 /// This external type is the type of a WebAssembly function. 1447 Func(FuncType), 1448 /// This external type is the type of a WebAssembly global. 1449 Global(GlobalType), 1450 /// This external type is the type of a WebAssembly table. 1451 Table(TableType), 1452 /// This external type is the type of a WebAssembly memory. 1453 Memory(MemoryType), 1454 /// This external type is the type of a WebAssembly tag. 1455 Tag(TagType), 1456 } 1457 1458 macro_rules! extern_type_accessors { 1459 ($(($variant:ident($ty:ty) $get:ident $unwrap:ident))*) => ($( 1460 /// Attempt to return the underlying type of this external type, 1461 /// returning `None` if it is a different type. 1462 pub fn $get(&self) -> Option<&$ty> { 1463 if let ExternType::$variant(e) = self { 1464 Some(e) 1465 } else { 1466 None 1467 } 1468 } 1469 1470 /// Returns the underlying descriptor of this [`ExternType`], panicking 1471 /// if it is a different type. 1472 /// 1473 /// # Panics 1474 /// 1475 /// Panics if `self` is not of the right type. 1476 pub fn $unwrap(&self) -> &$ty { 1477 self.$get().expect(concat!("expected ", stringify!($ty))) 1478 } 1479 )*) 1480 } 1481 1482 impl ExternType { 1483 extern_type_accessors! { 1484 (Func(FuncType) func unwrap_func) 1485 (Global(GlobalType) global unwrap_global) 1486 (Table(TableType) table unwrap_table) 1487 (Memory(MemoryType) memory unwrap_memory) 1488 (Tag(TagType) tag unwrap_tag) 1489 } 1490 from_wasmtime( engine: &Engine, types: &ModuleTypes, ty: &EntityType, ) -> ExternType1491 pub(crate) fn from_wasmtime( 1492 engine: &Engine, 1493 types: &ModuleTypes, 1494 ty: &EntityType, 1495 ) -> ExternType { 1496 match ty { 1497 EntityType::Function(idx) => match idx { 1498 EngineOrModuleTypeIndex::Engine(e) => { 1499 FuncType::from_shared_type_index(engine, *e).into() 1500 } 1501 EngineOrModuleTypeIndex::Module(m) => { 1502 let subty = &types[*m]; 1503 debug_assert!(subty.is_canonicalized_for_runtime_usage()); 1504 // subty.canonicalize_for_runtime_usage(&mut |idx| { 1505 // signatures.shared_type(idx).unwrap() 1506 // }); 1507 FuncType::from_wasm_func_type( 1508 engine, 1509 subty.is_final, 1510 subty.supertype, 1511 subty.unwrap_func().clone_panic_on_oom(), 1512 ) 1513 .panic_on_oom() 1514 .into() 1515 } 1516 EngineOrModuleTypeIndex::RecGroup(_) => unreachable!(), 1517 }, 1518 EntityType::Global(ty) => GlobalType::from_wasmtime_global(engine, ty).into(), 1519 EntityType::Memory(ty) => MemoryType::from_wasmtime_memory(ty).into(), 1520 EntityType::Table(ty) => TableType::from_wasmtime_table(engine, ty).into(), 1521 EntityType::Tag(ty) => TagType::from_wasmtime_tag(engine, ty).into(), 1522 } 1523 } 1524 /// Construct a default value, if possible, for the underlying type. default_value(&self, store: impl AsContextMut) -> Result<Extern>1525 pub fn default_value(&self, store: impl AsContextMut) -> Result<Extern> { 1526 match self { 1527 ExternType::Func(func_ty) => func_ty.default_value(store).map(Extern::Func), 1528 ExternType::Global(global_ty) => global_ty.default_value(store).map(Extern::Global), 1529 ExternType::Table(table_ty) => table_ty.default_value(store).map(Extern::Table), 1530 ExternType::Memory(mem_ty) => mem_ty.default_value(store), 1531 ExternType::Tag(tag_ty) => tag_ty.default_value(store).map(Extern::Tag), 1532 } 1533 } 1534 } 1535 1536 impl From<FuncType> for ExternType { from(ty: FuncType) -> ExternType1537 fn from(ty: FuncType) -> ExternType { 1538 ExternType::Func(ty) 1539 } 1540 } 1541 1542 impl From<GlobalType> for ExternType { from(ty: GlobalType) -> ExternType1543 fn from(ty: GlobalType) -> ExternType { 1544 ExternType::Global(ty) 1545 } 1546 } 1547 1548 impl From<MemoryType> for ExternType { from(ty: MemoryType) -> ExternType1549 fn from(ty: MemoryType) -> ExternType { 1550 ExternType::Memory(ty) 1551 } 1552 } 1553 1554 impl From<TableType> for ExternType { from(ty: TableType) -> ExternType1555 fn from(ty: TableType) -> ExternType { 1556 ExternType::Table(ty) 1557 } 1558 } 1559 1560 impl From<TagType> for ExternType { from(ty: TagType) -> ExternType1561 fn from(ty: TagType) -> ExternType { 1562 ExternType::Tag(ty) 1563 } 1564 } 1565 1566 /// The storage type of a `struct` field or `array` element. 1567 /// 1568 /// This is either a packed 8- or -16 bit integer, or else it is some unpacked 1569 /// Wasm value type. 1570 #[derive(Clone, Hash)] 1571 pub enum StorageType { 1572 /// `i8`, an 8-bit integer. 1573 I8, 1574 /// `i16`, a 16-bit integer. 1575 I16, 1576 /// A value type. 1577 ValType(ValType), 1578 } 1579 1580 impl fmt::Display for StorageType { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1581 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1582 match self { 1583 StorageType::I8 => write!(f, "i8"), 1584 StorageType::I16 => write!(f, "i16"), 1585 StorageType::ValType(ty) => fmt::Display::fmt(ty, f), 1586 } 1587 } 1588 } 1589 1590 impl From<ValType> for StorageType { 1591 #[inline] from(v: ValType) -> Self1592 fn from(v: ValType) -> Self { 1593 StorageType::ValType(v) 1594 } 1595 } 1596 1597 impl From<RefType> for StorageType { 1598 #[inline] from(r: RefType) -> Self1599 fn from(r: RefType) -> Self { 1600 StorageType::ValType(r.into()) 1601 } 1602 } 1603 1604 impl StorageType { 1605 /// Is this an `i8`? 1606 #[inline] is_i8(&self) -> bool1607 pub fn is_i8(&self) -> bool { 1608 matches!(self, Self::I8) 1609 } 1610 1611 /// Is this an `i16`? 1612 #[inline] is_i16(&self) -> bool1613 pub fn is_i16(&self) -> bool { 1614 matches!(self, Self::I16) 1615 } 1616 1617 /// Is this a Wasm value type? 1618 #[inline] is_val_type(&self) -> bool1619 pub fn is_val_type(&self) -> bool { 1620 matches!(self, Self::I16) 1621 } 1622 1623 /// Get this storage type's underlying value type, if any. 1624 /// 1625 /// Returns `None` if this storage type is not a value type. 1626 #[inline] as_val_type(&self) -> Option<&ValType>1627 pub fn as_val_type(&self) -> Option<&ValType> { 1628 match self { 1629 Self::ValType(v) => Some(v), 1630 _ => None, 1631 } 1632 } 1633 1634 /// Get this storage type's underlying value type, panicking if it is not a 1635 /// value type. unwrap_val_type(&self) -> &ValType1636 pub fn unwrap_val_type(&self) -> &ValType { 1637 self.as_val_type().unwrap() 1638 } 1639 1640 /// Unpack this (possibly packed) storage type into a full `ValType`. 1641 /// 1642 /// If this is a `StorageType::ValType`, then the inner `ValType` is 1643 /// returned as-is. 1644 /// 1645 /// If this is a packed `StorageType::I8` or `StorageType::I16, then a 1646 /// `ValType::I32` is returned. unpack(&self) -> &ValType1647 pub fn unpack(&self) -> &ValType { 1648 match self { 1649 StorageType::I8 | StorageType::I16 => &ValType::I32, 1650 StorageType::ValType(ty) => ty, 1651 } 1652 } 1653 1654 /// Does this field type match the other field type? 1655 /// 1656 /// That is, is this field type a subtype of the other field type? 1657 /// 1658 /// # Panics 1659 /// 1660 /// Panics if either type is associated with a different engine from the 1661 /// other. matches(&self, other: &Self) -> bool1662 pub fn matches(&self, other: &Self) -> bool { 1663 match (self, other) { 1664 (StorageType::I8, StorageType::I8) => true, 1665 (StorageType::I8, _) => false, 1666 (StorageType::I16, StorageType::I16) => true, 1667 (StorageType::I16, _) => false, 1668 (StorageType::ValType(a), StorageType::ValType(b)) => a.matches(b), 1669 (StorageType::ValType(_), _) => false, 1670 } 1671 } 1672 1673 /// Is field type `a` precisely equal to field type `b`? 1674 /// 1675 /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they 1676 /// are not exactly the same field type. 1677 /// 1678 /// # Panics 1679 /// 1680 /// Panics if either type is associated with a different engine from the 1681 /// other. eq(a: &Self, b: &Self) -> bool1682 pub fn eq(a: &Self, b: &Self) -> bool { 1683 match (a, b) { 1684 (StorageType::I8, StorageType::I8) => true, 1685 (StorageType::I8, _) => false, 1686 (StorageType::I16, StorageType::I16) => true, 1687 (StorageType::I16, _) => false, 1688 (StorageType::ValType(a), StorageType::ValType(b)) => ValType::eq(a, b), 1689 (StorageType::ValType(_), _) => false, 1690 } 1691 } 1692 comes_from_same_engine(&self, engine: &Engine) -> bool1693 pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool { 1694 match self { 1695 StorageType::I8 | StorageType::I16 => true, 1696 StorageType::ValType(v) => v.comes_from_same_engine(engine), 1697 } 1698 } 1699 from_wasm_storage_type(engine: &Engine, ty: &WasmStorageType) -> Self1700 pub(crate) fn from_wasm_storage_type(engine: &Engine, ty: &WasmStorageType) -> Self { 1701 match ty { 1702 WasmStorageType::I8 => Self::I8, 1703 WasmStorageType::I16 => Self::I16, 1704 WasmStorageType::Val(v) => ValType::from_wasm_type(engine, &v).into(), 1705 } 1706 } 1707 to_wasm_storage_type(&self) -> WasmStorageType1708 pub(crate) fn to_wasm_storage_type(&self) -> WasmStorageType { 1709 match self { 1710 Self::I8 => WasmStorageType::I8, 1711 Self::I16 => WasmStorageType::I16, 1712 Self::ValType(v) => WasmStorageType::Val(v.to_wasm_type()), 1713 } 1714 } 1715 1716 /// The byte size of this type, if it has a defined size in the spec. 1717 /// 1718 /// See 1719 /// https://webassembly.github.io/gc/core/syntax/types.html#bitwidth-fieldtype 1720 /// and 1721 /// https://webassembly.github.io/gc/core/syntax/types.html#bitwidth-valtype 1722 #[cfg(feature = "gc")] data_byte_size(&self) -> Option<u32>1723 pub(crate) fn data_byte_size(&self) -> Option<u32> { 1724 match self { 1725 StorageType::I8 => Some(1), 1726 StorageType::I16 => Some(2), 1727 StorageType::ValType(ValType::I32 | ValType::F32) => Some(4), 1728 StorageType::ValType(ValType::I64 | ValType::F64) => Some(8), 1729 StorageType::ValType(ValType::V128) => Some(16), 1730 StorageType::ValType(ValType::Ref(_)) => None, 1731 } 1732 } 1733 } 1734 1735 /// The type of a `struct` field or an `array`'s elements. 1736 /// 1737 /// This is a pair of both the field's storage type and its mutability 1738 /// (i.e. whether the field can be updated or not). 1739 #[derive(Clone, Hash)] 1740 pub struct FieldType { 1741 mutability: Mutability, 1742 element_type: StorageType, 1743 } 1744 1745 impl fmt::Display for FieldType { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1746 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1747 if self.mutability.is_var() { 1748 write!(f, "(mut {})", self.element_type) 1749 } else { 1750 fmt::Display::fmt(&self.element_type, f) 1751 } 1752 } 1753 } 1754 1755 impl FieldType { 1756 /// Construct a new field type from the given parts. 1757 #[inline] new(mutability: Mutability, element_type: StorageType) -> Self1758 pub fn new(mutability: Mutability, element_type: StorageType) -> Self { 1759 Self { 1760 mutability, 1761 element_type, 1762 } 1763 } 1764 1765 /// Get whether or not this field type is mutable. 1766 #[inline] mutability(&self) -> Mutability1767 pub fn mutability(&self) -> Mutability { 1768 self.mutability 1769 } 1770 1771 /// Get this field type's storage type. 1772 #[inline] element_type(&self) -> &StorageType1773 pub fn element_type(&self) -> &StorageType { 1774 &self.element_type 1775 } 1776 1777 /// Does this field type match the other field type? 1778 /// 1779 /// That is, is this field type a subtype of the other field type? 1780 /// 1781 /// # Panics 1782 /// 1783 /// Panics if either type is associated with a different engine from the 1784 /// other. matches(&self, other: &Self) -> bool1785 pub fn matches(&self, other: &Self) -> bool { 1786 // Our storage type must match `other`'s storage type and either 1787 // 1788 // 1. Both field types are immutable, or 1789 // 1790 // 2. Both field types are mutable and `other`'s storage type must match 1791 // ours, i.e. the storage types are exactly the same. 1792 use Mutability as M; 1793 match (self.mutability, other.mutability) { 1794 // Case 1 1795 (M::Const, M::Const) => self.element_type.matches(&other.element_type), 1796 // Case 2 1797 (M::Var, M::Var) => StorageType::eq(&self.element_type, &other.element_type), 1798 // Does not match. 1799 _ => false, 1800 } 1801 } 1802 1803 /// Is field type `a` precisely equal to field type `b`? 1804 /// 1805 /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they 1806 /// are not exactly the same field type. 1807 /// 1808 /// # Panics 1809 /// 1810 /// Panics if either type is associated with a different engine from the 1811 /// other. eq(a: &Self, b: &Self) -> bool1812 pub fn eq(a: &Self, b: &Self) -> bool { 1813 a.matches(b) && b.matches(a) 1814 } 1815 comes_from_same_engine(&self, engine: &Engine) -> bool1816 pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool { 1817 self.element_type.comes_from_same_engine(engine) 1818 } 1819 from_wasm_field_type(engine: &Engine, ty: &WasmFieldType) -> Self1820 pub(crate) fn from_wasm_field_type(engine: &Engine, ty: &WasmFieldType) -> Self { 1821 Self { 1822 mutability: if ty.mutable { 1823 Mutability::Var 1824 } else { 1825 Mutability::Const 1826 }, 1827 element_type: StorageType::from_wasm_storage_type(engine, &ty.element_type), 1828 } 1829 } 1830 to_wasm_field_type(&self) -> WasmFieldType1831 pub(crate) fn to_wasm_field_type(&self) -> WasmFieldType { 1832 WasmFieldType { 1833 element_type: self.element_type.to_wasm_storage_type(), 1834 mutable: matches!(self.mutability, Mutability::Var), 1835 } 1836 } 1837 } 1838 1839 /// The type of a WebAssembly struct. 1840 /// 1841 /// WebAssembly structs are a static, fixed-length, ordered sequence of 1842 /// fields. Fields are named by index, not an identifier. Each field is mutable 1843 /// or constant and stores unpacked [`Val`][crate::Val]s or packed 8-/16-bit 1844 /// integers. 1845 /// 1846 /// # Subtyping and Equality 1847 /// 1848 /// `StructType` does not implement `Eq`, because reference types have a 1849 /// subtyping relationship, and so 99.99% of the time you actually want to check 1850 /// whether one type matches (i.e. is a subtype of) another type. You can use 1851 /// the [`StructType::matches`] method to perform these types of checks. If, 1852 /// however, you are in that 0.01% scenario where you need to check precise 1853 /// equality between types, you can use the [`StructType::eq`] method. 1854 // 1855 // TODO: Once we have struct values, update above docs with a reference to the 1856 // future `Struct::matches_ty` method 1857 #[derive(Debug, Clone, Hash)] 1858 pub struct StructType { 1859 registered_type: RegisteredType, 1860 } 1861 1862 impl fmt::Display for StructType { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1863 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1864 write!(f, "(struct")?; 1865 for field in self.fields() { 1866 write!(f, " (field {field})")?; 1867 } 1868 write!(f, ")")?; 1869 Ok(()) 1870 } 1871 } 1872 1873 impl StructType { 1874 /// Construct a new `StructType` with the given field types. 1875 /// 1876 /// This `StructType` will be final and without a supertype. 1877 /// 1878 /// The result will be associated with the given engine, and attempts to use 1879 /// it with other engines will panic (for example, checking whether it is a 1880 /// subtype of another struct type that is associated with a different 1881 /// engine). 1882 /// 1883 /// Returns an error if the number of fields exceeds the implementation 1884 /// limit. 1885 /// 1886 /// # Panics 1887 /// 1888 /// Panics if any given field type is not associated with the given engine. new(engine: &Engine, fields: impl IntoIterator<Item = FieldType>) -> Result<Self>1889 pub fn new(engine: &Engine, fields: impl IntoIterator<Item = FieldType>) -> Result<Self> { 1890 Self::with_finality_and_supertype(engine, Finality::Final, None, fields) 1891 } 1892 1893 /// Construct a new `StructType` with the given finality, supertype, and 1894 /// fields. 1895 /// 1896 /// The result will be associated with the given engine, and attempts to use 1897 /// it with other engines will panic (for example, checking whether it is a 1898 /// subtype of another struct type that is associated with a different 1899 /// engine). 1900 /// 1901 /// Returns an error if the number of fields exceeds the implementation 1902 /// limit, if the supertype is final, or if this type does not match the 1903 /// supertype. 1904 /// 1905 /// # Panics 1906 /// 1907 /// Panics if any given field type is not associated with the given engine. with_finality_and_supertype( engine: &Engine, finality: Finality, supertype: Option<&Self>, fields: impl IntoIterator<Item = FieldType>, ) -> Result<Self>1908 pub fn with_finality_and_supertype( 1909 engine: &Engine, 1910 finality: Finality, 1911 supertype: Option<&Self>, 1912 fields: impl IntoIterator<Item = FieldType>, 1913 ) -> Result<Self> { 1914 let fields = fields.into_iter(); 1915 1916 let mut wasmtime_fields = Vec::with_capacity({ 1917 let size_hint = fields.size_hint(); 1918 let cap = size_hint.1.unwrap_or(size_hint.0); 1919 // Only reserve space if we have a supertype, as that is the only time 1920 // that this vec is used. 1921 supertype.is_some() as usize * cap 1922 }); 1923 1924 // Same as in `FuncType::new`: we must prevent any `RegisteredType`s 1925 // from being reclaimed while constructing this struct type. 1926 let mut registrations = smallvec::SmallVec::<[_; 4]>::new(); 1927 1928 let fields: Box<[WasmFieldType]> = fields 1929 .map(|ty: FieldType| -> Result<_, Error> { 1930 assert!(ty.comes_from_same_engine(engine)); 1931 1932 if supertype.is_some() { 1933 wasmtime_fields.push(ty.clone()); 1934 } 1935 1936 if let Some(r) = ty.element_type.as_val_type().and_then(|v| v.as_ref()) { 1937 if let Some(r) = r.heap_type().as_registered_type() { 1938 registrations.push(r.clone()); 1939 } 1940 } 1941 1942 Ok(ty.to_wasm_field_type()) 1943 }) 1944 .try_collect()?; 1945 1946 if let Some(supertype) = supertype { 1947 ensure!( 1948 supertype.finality().is_non_final(), 1949 "cannot create a subtype of a final supertype" 1950 ); 1951 ensure!( 1952 Self::fields_match(wasmtime_fields.into_iter(), supertype.fields()), 1953 "struct fields must match their supertype's fields" 1954 ); 1955 } 1956 1957 Self::from_wasm_struct_type( 1958 engine, 1959 finality.is_final(), 1960 false, 1961 supertype.map(|ty| ty.type_index().into()), 1962 WasmStructType { fields }, 1963 ) 1964 } 1965 1966 /// Get the engine that this struct type is associated with. engine(&self) -> &Engine1967 pub fn engine(&self) -> &Engine { 1968 self.registered_type.engine() 1969 } 1970 1971 /// Get the finality of this struct type. finality(&self) -> Finality1972 pub fn finality(&self) -> Finality { 1973 match self.registered_type.is_final { 1974 true => Finality::Final, 1975 false => Finality::NonFinal, 1976 } 1977 } 1978 1979 /// Get the supertype of this struct type, if any. supertype(&self) -> Option<Self>1980 pub fn supertype(&self) -> Option<Self> { 1981 self.registered_type 1982 .supertype 1983 .map(|ty| Self::from_shared_type_index(self.engine(), ty.unwrap_engine_type_index())) 1984 } 1985 1986 /// Get the `i`th field type. 1987 /// 1988 /// Returns `None` if `i` is out of bounds. field(&self, i: usize) -> Option<FieldType>1989 pub fn field(&self, i: usize) -> Option<FieldType> { 1990 let engine = self.engine(); 1991 self.as_wasm_struct_type() 1992 .fields 1993 .get(i) 1994 .map(|ty| FieldType::from_wasm_field_type(engine, ty)) 1995 } 1996 1997 /// Returns the list of field types for this function. 1998 #[inline] fields(&self) -> impl ExactSizeIterator<Item = FieldType> + '_1999 pub fn fields(&self) -> impl ExactSizeIterator<Item = FieldType> + '_ { 2000 let engine = self.engine(); 2001 self.as_wasm_struct_type() 2002 .fields 2003 .iter() 2004 .map(|ty| FieldType::from_wasm_field_type(engine, ty)) 2005 } 2006 2007 /// Does this struct type match the other struct type? 2008 /// 2009 /// That is, is this function type a subtype of the other struct type? 2010 /// 2011 /// # Panics 2012 /// 2013 /// Panics if either type is associated with a different engine from the 2014 /// other. matches(&self, other: &StructType) -> bool2015 pub fn matches(&self, other: &StructType) -> bool { 2016 assert!(self.comes_from_same_engine(other.engine())); 2017 2018 self.engine() 2019 .signatures() 2020 .is_subtype(self.type_index(), other.type_index()) 2021 } 2022 fields_match( a: impl ExactSizeIterator<Item = FieldType>, b: impl ExactSizeIterator<Item = FieldType>, ) -> bool2023 fn fields_match( 2024 a: impl ExactSizeIterator<Item = FieldType>, 2025 b: impl ExactSizeIterator<Item = FieldType>, 2026 ) -> bool { 2027 a.len() >= b.len() && a.zip(b).all(|(a, b)| a.matches(&b)) 2028 } 2029 2030 /// Is struct type `a` precisely equal to struct type `b`? 2031 /// 2032 /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they 2033 /// are not exactly the same struct type. 2034 /// 2035 /// # Panics 2036 /// 2037 /// Panics if either type is associated with a different engine from the 2038 /// other. eq(a: &StructType, b: &StructType) -> bool2039 pub fn eq(a: &StructType, b: &StructType) -> bool { 2040 assert!(a.comes_from_same_engine(b.engine())); 2041 a.type_index() == b.type_index() 2042 } 2043 comes_from_same_engine(&self, engine: &Engine) -> bool2044 pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool { 2045 Engine::same(self.registered_type().engine(), engine) 2046 } 2047 type_index(&self) -> VMSharedTypeIndex2048 pub(crate) fn type_index(&self) -> VMSharedTypeIndex { 2049 self.registered_type().index() 2050 } 2051 as_wasm_struct_type(&self) -> &WasmStructType2052 pub(crate) fn as_wasm_struct_type(&self) -> &WasmStructType { 2053 self.registered_type().unwrap_struct() 2054 } 2055 registered_type(&self) -> &RegisteredType2056 pub(crate) fn registered_type(&self) -> &RegisteredType { 2057 &self.registered_type 2058 } 2059 2060 /// Construct a `StructType` from a `WasmStructType`. 2061 /// 2062 /// This method should only be used when something has already registered -- 2063 /// and is *keeping registered* -- any other concrete Wasm types referenced 2064 /// by the given `WasmStructType`. 2065 /// 2066 /// For example, this method may be called to convert an struct type from 2067 /// within a Wasm module's `ModuleTypes` since the Wasm module itself is 2068 /// holding a strong reference to all of its types, including any `(ref null 2069 /// <index>)` types used as the element type for this struct type. from_wasm_struct_type( engine: &Engine, is_final: bool, is_shared: bool, supertype: Option<EngineOrModuleTypeIndex>, ty: WasmStructType, ) -> Result<StructType>2070 pub(crate) fn from_wasm_struct_type( 2071 engine: &Engine, 2072 is_final: bool, 2073 is_shared: bool, 2074 supertype: Option<EngineOrModuleTypeIndex>, 2075 ty: WasmStructType, 2076 ) -> Result<StructType> { 2077 const MAX_FIELDS: usize = 10_000; 2078 let fields_len = ty.fields.len(); 2079 ensure!( 2080 fields_len <= MAX_FIELDS, 2081 "attempted to define a struct type with {fields_len} fields, but \ 2082 that is more than the maximum supported number of fields \ 2083 ({MAX_FIELDS})", 2084 ); 2085 2086 let ty = RegisteredType::new( 2087 engine, 2088 WasmSubType { 2089 is_final, 2090 supertype, 2091 composite_type: WasmCompositeType { 2092 shared: is_shared, 2093 inner: WasmCompositeInnerType::Struct(ty), 2094 }, 2095 }, 2096 )?; 2097 Ok(Self { 2098 registered_type: ty, 2099 }) 2100 } 2101 from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> StructType2102 pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> StructType { 2103 let ty = RegisteredType::root(engine, index); 2104 Self::from_registered_type(ty) 2105 } 2106 from_registered_type(registered_type: RegisteredType) -> Self2107 pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self { 2108 debug_assert!(registered_type.is_struct()); 2109 Self { registered_type } 2110 } 2111 } 2112 2113 /// The type of a WebAssembly array. 2114 /// 2115 /// WebAssembly arrays are dynamically-sized, but not resizable. They contain 2116 /// either unpacked [`Val`][crate::Val]s or packed 8-/16-bit integers. 2117 /// 2118 /// # Subtyping and Equality 2119 /// 2120 /// `ArrayType` does not implement `Eq`, because reference types have a 2121 /// subtyping relationship, and so 99.99% of the time you actually want to check 2122 /// whether one type matches (i.e. is a subtype of) another type. You can use 2123 /// the [`ArrayType::matches`] method to perform these types of checks. If, 2124 /// however, you are in that 0.01% scenario where you need to check precise 2125 /// equality between types, you can use the [`ArrayType::eq`] method. 2126 // 2127 // TODO: Once we have array values, update above docs with a reference to the 2128 // future `Array::matches_ty` method 2129 #[derive(Debug, Clone, Hash)] 2130 pub struct ArrayType { 2131 registered_type: RegisteredType, 2132 } 2133 2134 impl fmt::Display for ArrayType { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result2135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 2136 let field_ty = self.field_type(); 2137 write!(f, "(array (field {field_ty}))")?; 2138 Ok(()) 2139 } 2140 } 2141 2142 impl ArrayType { 2143 /// Construct a new `ArrayType` with the given field type's mutability and 2144 /// storage type. 2145 /// 2146 /// The new `ArrayType` will be final and without a supertype. 2147 /// 2148 /// The result will be associated with the given engine, and attempts to use 2149 /// it with other engines will panic (for example, checking whether it is a 2150 /// subtype of another array type that is associated with a different 2151 /// engine). 2152 /// 2153 /// # Panics 2154 /// 2155 /// Panics if the given field type is not associated with the given engine. new(engine: &Engine, field_type: FieldType) -> Self2156 pub fn new(engine: &Engine, field_type: FieldType) -> Self { 2157 Self::with_finality_and_supertype(engine, Finality::Final, None, field_type) 2158 .expect("cannot fail without a supertype") 2159 } 2160 2161 /// Construct a new `StructType` with the given finality, supertype, and 2162 /// fields. 2163 /// 2164 /// The result will be associated with the given engine, and attempts to use 2165 /// it with other engines will panic (for example, checking whether it is a 2166 /// subtype of another struct type that is associated with a different 2167 /// engine). 2168 /// 2169 /// Returns an error if the supertype is final, or if this type does not 2170 /// match the supertype. 2171 /// 2172 /// # Panics 2173 /// 2174 /// Panics if the given field type is not associated with the given engine. with_finality_and_supertype( engine: &Engine, finality: Finality, supertype: Option<&Self>, field_type: FieldType, ) -> Result<Self>2175 pub fn with_finality_and_supertype( 2176 engine: &Engine, 2177 finality: Finality, 2178 supertype: Option<&Self>, 2179 field_type: FieldType, 2180 ) -> Result<Self> { 2181 if let Some(supertype) = supertype { 2182 assert!(supertype.comes_from_same_engine(engine)); 2183 ensure!( 2184 supertype.finality().is_non_final(), 2185 "cannot create a subtype of a final supertype" 2186 ); 2187 ensure!( 2188 field_type.matches(&supertype.field_type()), 2189 "array field type must match its supertype's field type" 2190 ); 2191 } 2192 2193 // Same as in `FuncType::new`: we must prevent any `RegisteredType` in 2194 // `field_type` from being reclaimed while constructing this array type. 2195 let _registration = field_type 2196 .element_type 2197 .as_val_type() 2198 .and_then(|v| v.as_ref()) 2199 .and_then(|r| r.heap_type().as_registered_type()); 2200 2201 assert!(field_type.comes_from_same_engine(engine)); 2202 let wasm_ty = WasmArrayType(field_type.to_wasm_field_type()); 2203 2204 Ok(Self::from_wasm_array_type( 2205 engine, 2206 finality.is_final(), 2207 supertype.map(|ty| ty.type_index().into()), 2208 wasm_ty, 2209 )?) 2210 } 2211 2212 /// Get the engine that this array type is associated with. engine(&self) -> &Engine2213 pub fn engine(&self) -> &Engine { 2214 self.registered_type.engine() 2215 } 2216 2217 /// Get the finality of this array type. finality(&self) -> Finality2218 pub fn finality(&self) -> Finality { 2219 match self.registered_type.is_final { 2220 true => Finality::Final, 2221 false => Finality::NonFinal, 2222 } 2223 } 2224 2225 /// Get the supertype of this array type, if any. supertype(&self) -> Option<Self>2226 pub fn supertype(&self) -> Option<Self> { 2227 self.registered_type 2228 .supertype 2229 .map(|ty| Self::from_shared_type_index(self.engine(), ty.unwrap_engine_type_index())) 2230 } 2231 2232 /// Get this array's underlying field type. 2233 /// 2234 /// The field type contains information about both this array type's 2235 /// mutability and the storage type used for its elements. field_type(&self) -> FieldType2236 pub fn field_type(&self) -> FieldType { 2237 FieldType::from_wasm_field_type(self.engine(), &self.as_wasm_array_type().0) 2238 } 2239 2240 /// Get this array type's mutability and whether its instances' elements can 2241 /// be updated or not. 2242 /// 2243 /// This is a convenience method providing a short-hand for 2244 /// `my_array_type.field_type().mutability()`. mutability(&self) -> Mutability2245 pub fn mutability(&self) -> Mutability { 2246 if self.as_wasm_array_type().0.mutable { 2247 Mutability::Var 2248 } else { 2249 Mutability::Const 2250 } 2251 } 2252 2253 /// Get the storage type used for this array type's elements. 2254 /// 2255 /// This is a convenience method providing a short-hand for 2256 /// `my_array_type.field_type().element_type()`. element_type(&self) -> StorageType2257 pub fn element_type(&self) -> StorageType { 2258 StorageType::from_wasm_storage_type( 2259 self.engine(), 2260 &self.registered_type.unwrap_array().0.element_type, 2261 ) 2262 } 2263 2264 /// Does this array type match the other array type? 2265 /// 2266 /// That is, is this function type a subtype of the other array type? 2267 /// 2268 /// # Panics 2269 /// 2270 /// Panics if either type is associated with a different engine from the 2271 /// other. matches(&self, other: &ArrayType) -> bool2272 pub fn matches(&self, other: &ArrayType) -> bool { 2273 assert!(self.comes_from_same_engine(other.engine())); 2274 2275 self.engine() 2276 .signatures() 2277 .is_subtype(self.type_index(), other.type_index()) 2278 } 2279 2280 /// Is array type `a` precisely equal to array type `b`? 2281 /// 2282 /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they 2283 /// are not exactly the same array type. 2284 /// 2285 /// # Panics 2286 /// 2287 /// Panics if either type is associated with a different engine from the 2288 /// other. eq(a: &ArrayType, b: &ArrayType) -> bool2289 pub fn eq(a: &ArrayType, b: &ArrayType) -> bool { 2290 assert!(a.comes_from_same_engine(b.engine())); 2291 a.type_index() == b.type_index() 2292 } 2293 comes_from_same_engine(&self, engine: &Engine) -> bool2294 pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool { 2295 Engine::same(self.registered_type.engine(), engine) 2296 } 2297 2298 #[cfg(feature = "gc")] registered_type(&self) -> &RegisteredType2299 pub(crate) fn registered_type(&self) -> &RegisteredType { 2300 &self.registered_type 2301 } 2302 type_index(&self) -> VMSharedTypeIndex2303 pub(crate) fn type_index(&self) -> VMSharedTypeIndex { 2304 self.registered_type.index() 2305 } 2306 as_wasm_array_type(&self) -> &WasmArrayType2307 pub(crate) fn as_wasm_array_type(&self) -> &WasmArrayType { 2308 self.registered_type.unwrap_array() 2309 } 2310 2311 /// Construct a `ArrayType` from a `WasmArrayType`. 2312 /// 2313 /// This method should only be used when something has already registered -- 2314 /// and is *keeping registered* -- any other concrete Wasm types referenced 2315 /// by the given `WasmArrayType`. 2316 /// 2317 /// For example, this method may be called to convert an array type from 2318 /// within a Wasm module's `ModuleTypes` since the Wasm module itself is 2319 /// holding a strong reference to all of its types, including any `(ref null 2320 /// <index>)` types used as the element type for this array type. from_wasm_array_type( engine: &Engine, is_final: bool, supertype: Option<EngineOrModuleTypeIndex>, ty: WasmArrayType, ) -> Result<ArrayType>2321 pub(crate) fn from_wasm_array_type( 2322 engine: &Engine, 2323 is_final: bool, 2324 supertype: Option<EngineOrModuleTypeIndex>, 2325 ty: WasmArrayType, 2326 ) -> Result<ArrayType> { 2327 let ty = RegisteredType::new( 2328 engine, 2329 WasmSubType { 2330 is_final, 2331 supertype, 2332 composite_type: WasmCompositeType { 2333 shared: false, 2334 inner: WasmCompositeInnerType::Array(ty), 2335 }, 2336 }, 2337 )?; 2338 Ok(Self { 2339 registered_type: ty, 2340 }) 2341 } 2342 from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> ArrayType2343 pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> ArrayType { 2344 let ty = RegisteredType::root(engine, index); 2345 Self::from_registered_type(ty) 2346 } 2347 from_registered_type(registered_type: RegisteredType) -> Self2348 pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self { 2349 debug_assert!(registered_type.is_array()); 2350 Self { registered_type } 2351 } 2352 } 2353 2354 /// The type of a WebAssembly function. 2355 /// 2356 /// WebAssembly functions can have 0 or more parameters and results. 2357 /// 2358 /// # Subtyping and Equality 2359 /// 2360 /// `FuncType` does not implement `Eq`, because reference types have a subtyping 2361 /// relationship, and so 99.99% of the time you actually want to check whether 2362 /// one type matches (i.e. is a subtype of) another type. You can use the 2363 /// [`FuncType::matches`] and [`Func::matches_ty`][crate::Func::matches_ty] 2364 /// methods to perform these types of checks. If, however, you are in that 0.01% 2365 /// scenario where you need to check precise equality between types, you can use 2366 /// the [`FuncType::eq`] method. 2367 #[derive(Debug, Clone, Hash)] 2368 pub struct FuncType { 2369 registered_type: RegisteredType, 2370 } 2371 2372 impl Display for FuncType { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result2373 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 2374 write!(f, "(type (func")?; 2375 if self.params().len() > 0 { 2376 write!(f, " (param")?; 2377 for p in self.params() { 2378 write!(f, " {p}")?; 2379 } 2380 write!(f, ")")?; 2381 } 2382 if self.results().len() > 0 { 2383 write!(f, " (result")?; 2384 for r in self.results() { 2385 write!(f, " {r}")?; 2386 } 2387 write!(f, ")")?; 2388 } 2389 write!(f, "))") 2390 } 2391 } 2392 2393 impl FuncType { 2394 /// Creates a new function type from the given parameters and results. 2395 /// 2396 /// The function type returned will represent a function which takes 2397 /// `params` as arguments and returns `results` when it is finished. 2398 /// 2399 /// The resulting function type will be final and without a supertype. 2400 /// 2401 /// # Panics 2402 /// 2403 /// Panics if any parameter or value type is not associated with the given 2404 /// engine. new( engine: &Engine, params: impl IntoIterator<Item = ValType>, results: impl IntoIterator<Item = ValType>, ) -> FuncType2405 pub fn new( 2406 engine: &Engine, 2407 params: impl IntoIterator<Item = ValType>, 2408 results: impl IntoIterator<Item = ValType>, 2409 ) -> FuncType { 2410 Self::with_finality_and_supertype(engine, Finality::Final, None, params, results) 2411 .expect("cannot fail without a supertype") 2412 } 2413 2414 /// Like [`FuncType::new`] but returns an 2415 /// [`OutOfMemory`][crate::error::OutOfMemory] error on allocation failure. try_new( engine: &Engine, params: impl IntoIterator<Item = ValType>, results: impl IntoIterator<Item = ValType>, ) -> Result<FuncType, OutOfMemory>2416 pub fn try_new( 2417 engine: &Engine, 2418 params: impl IntoIterator<Item = ValType>, 2419 results: impl IntoIterator<Item = ValType>, 2420 ) -> Result<FuncType, OutOfMemory> { 2421 Self::with_finality_and_supertype(engine, Finality::Final, None, params, results).map_err( 2422 |e| { 2423 e.downcast::<OutOfMemory>() 2424 .expect("cannot fail without a supertype, other than OOM") 2425 }, 2426 ) 2427 } 2428 2429 /// Create a new function type with the given finality, supertype, parameter 2430 /// types, and result types. 2431 /// 2432 /// Returns an error if the supertype is final, or if this function type 2433 /// does not match the supertype. 2434 /// 2435 /// # Panics 2436 /// 2437 /// Panics if any parameter or value type is not associated with the given 2438 /// engine. with_finality_and_supertype( engine: &Engine, finality: Finality, supertype: Option<&Self>, params: impl IntoIterator<Item = ValType>, results: impl IntoIterator<Item = ValType>, ) -> Result<Self>2439 pub fn with_finality_and_supertype( 2440 engine: &Engine, 2441 finality: Finality, 2442 supertype: Option<&Self>, 2443 params: impl IntoIterator<Item = ValType>, 2444 results: impl IntoIterator<Item = ValType>, 2445 ) -> Result<Self> { 2446 let params = params.into_iter(); 2447 let results = results.into_iter(); 2448 2449 let mut wasmtime_params = TryVec::with_capacity({ 2450 let size_hint = params.size_hint(); 2451 let cap = size_hint.1.unwrap_or(size_hint.0); 2452 // Only reserve space if we have a supertype, as that is the only time 2453 // that this vec is used. 2454 supertype.is_some() as usize * cap 2455 })?; 2456 2457 let mut wasmtime_results = TryVec::with_capacity({ 2458 let size_hint = results.size_hint(); 2459 let cap = size_hint.1.unwrap_or(size_hint.0); 2460 // Same as above. 2461 supertype.is_some() as usize * cap 2462 })?; 2463 2464 // Keep any of our parameters' and results' `RegisteredType`s alive 2465 // across `Self::from_wasm_func_type`. If one of our given `ValType`s is 2466 // the only thing keeping a type in the registry, we don't want to 2467 // unregister it when we convert the `ValType` into a `WasmValType` just 2468 // before we register our new `WasmFuncType` that will reference it. 2469 let mut registrations = TryVec::new(); 2470 2471 let mut to_wasm_type = 2472 |ty: ValType, vec: &mut TryVec<_>| -> Result<WasmValType, OutOfMemory> { 2473 assert!(ty.comes_from_same_engine(engine)); 2474 2475 if supertype.is_some() { 2476 vec.push(ty.clone())?; 2477 } 2478 2479 if let Some(r) = ty.as_ref() { 2480 if let Some(r) = r.heap_type().as_registered_type() { 2481 registrations.push(r.clone())?; 2482 } 2483 } 2484 2485 Ok(ty.to_wasm_type()) 2486 }; 2487 2488 let params: Box<[_]> = params 2489 .map(|p| to_wasm_type(p, &mut wasmtime_params)) 2490 .try_collect()?; 2491 let results: Box<[_]> = results 2492 .map(|p| to_wasm_type(p, &mut wasmtime_results)) 2493 .try_collect()?; 2494 let wasm_func_ty = WasmFuncType::new(params, results)?; 2495 2496 if let Some(supertype) = supertype { 2497 assert!(supertype.comes_from_same_engine(engine)); 2498 ensure!( 2499 supertype.finality().is_non_final(), 2500 "cannot create a subtype of a final supertype" 2501 ); 2502 ensure!( 2503 Self::matches_impl( 2504 wasmtime_params.iter().cloned(), 2505 supertype.params(), 2506 wasmtime_results.iter().cloned(), 2507 supertype.results() 2508 ), 2509 "function type must match its supertype: found (func{params}{results}), expected \ 2510 {supertype}", 2511 params = if wasmtime_params.is_empty() { 2512 String::new() 2513 } else { 2514 let mut s = format!(" (params"); 2515 for p in &wasmtime_params { 2516 write!(&mut s, " {p}").unwrap(); 2517 } 2518 s.push(')'); 2519 s 2520 }, 2521 results = if wasmtime_results.is_empty() { 2522 String::new() 2523 } else { 2524 let mut s = format!(" (results"); 2525 for r in &wasmtime_results { 2526 write!(&mut s, " {r}").unwrap(); 2527 } 2528 s.push(')'); 2529 s 2530 }, 2531 ); 2532 } 2533 2534 Ok(Self::from_wasm_func_type( 2535 engine, 2536 finality.is_final(), 2537 supertype.map(|ty| ty.type_index().into()), 2538 wasm_func_ty, 2539 )?) 2540 } 2541 2542 /// Get the engine that this function type is associated with. engine(&self) -> &Engine2543 pub fn engine(&self) -> &Engine { 2544 self.registered_type.engine() 2545 } 2546 2547 /// Get the finality of this function type. finality(&self) -> Finality2548 pub fn finality(&self) -> Finality { 2549 match self.registered_type.is_final { 2550 true => Finality::Final, 2551 false => Finality::NonFinal, 2552 } 2553 } 2554 2555 /// Get the supertype of this function type, if any. supertype(&self) -> Option<Self>2556 pub fn supertype(&self) -> Option<Self> { 2557 self.registered_type 2558 .supertype 2559 .map(|ty| Self::from_shared_type_index(self.engine(), ty.unwrap_engine_type_index())) 2560 } 2561 2562 /// Get the `i`th parameter type. 2563 /// 2564 /// Returns `None` if `i` is out of bounds. param(&self, i: usize) -> Option<ValType>2565 pub fn param(&self, i: usize) -> Option<ValType> { 2566 let engine = self.engine(); 2567 self.registered_type 2568 .unwrap_func() 2569 .params() 2570 .get(i) 2571 .map(|ty| ValType::from_wasm_type(engine, ty)) 2572 } 2573 2574 /// Returns the list of parameter types for this function. 2575 #[inline] params(&self) -> impl ExactSizeIterator<Item = ValType> + '_2576 pub fn params(&self) -> impl ExactSizeIterator<Item = ValType> + '_ { 2577 let engine = self.engine(); 2578 self.registered_type 2579 .unwrap_func() 2580 .params() 2581 .iter() 2582 .map(|ty| ValType::from_wasm_type(engine, ty)) 2583 } 2584 2585 /// Get the `i`th result type. 2586 /// 2587 /// Returns `None` if `i` is out of bounds. result(&self, i: usize) -> Option<ValType>2588 pub fn result(&self, i: usize) -> Option<ValType> { 2589 let engine = self.engine(); 2590 self.registered_type 2591 .unwrap_func() 2592 .results() 2593 .get(i) 2594 .map(|ty| ValType::from_wasm_type(engine, ty)) 2595 } 2596 2597 /// Returns the list of result types for this function. 2598 #[inline] results(&self) -> impl ExactSizeIterator<Item = ValType> + '_2599 pub fn results(&self) -> impl ExactSizeIterator<Item = ValType> + '_ { 2600 let engine = self.engine(); 2601 self.registered_type 2602 .unwrap_func() 2603 .results() 2604 .iter() 2605 .map(|ty| ValType::from_wasm_type(engine, ty)) 2606 } 2607 2608 /// Does this function type match the other function type? 2609 /// 2610 /// That is, is this function type a subtype of the other function type? 2611 /// 2612 /// # Panics 2613 /// 2614 /// Panics if either type is associated with a different engine from the 2615 /// other. matches(&self, other: &FuncType) -> bool2616 pub fn matches(&self, other: &FuncType) -> bool { 2617 assert!(self.comes_from_same_engine(other.engine())); 2618 2619 // Avoid matching on structure for subtyping checks when we have 2620 // precisely the same type. 2621 if self.type_index() == other.type_index() { 2622 return true; 2623 } 2624 2625 Self::matches_impl( 2626 self.params(), 2627 other.params(), 2628 self.results(), 2629 other.results(), 2630 ) 2631 } 2632 matches_impl( a_params: impl ExactSizeIterator<Item = ValType>, b_params: impl ExactSizeIterator<Item = ValType>, a_results: impl ExactSizeIterator<Item = ValType>, b_results: impl ExactSizeIterator<Item = ValType>, ) -> bool2633 fn matches_impl( 2634 a_params: impl ExactSizeIterator<Item = ValType>, 2635 b_params: impl ExactSizeIterator<Item = ValType>, 2636 a_results: impl ExactSizeIterator<Item = ValType>, 2637 b_results: impl ExactSizeIterator<Item = ValType>, 2638 ) -> bool { 2639 a_params.len() == b_params.len() 2640 && a_results.len() == b_results.len() 2641 // Params are contravariant and results are covariant. For more 2642 // details and a refresher on variance, read 2643 // https://github.com/bytecodealliance/wasm-tools/blob/f1d89a4/crates/wasmparser/src/readers/core/types/matches.rs#L137-L174 2644 && a_params 2645 .zip(b_params) 2646 .all(|(a, b)| b.matches(&a)) 2647 && a_results 2648 .zip(b_results) 2649 .all(|(a, b)| a.matches(&b)) 2650 } 2651 2652 /// Is function type `a` precisely equal to function type `b`? 2653 /// 2654 /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they 2655 /// are not exactly the same function type. 2656 /// 2657 /// # Panics 2658 /// 2659 /// Panics if either type is associated with a different engine from the 2660 /// other. eq(a: &FuncType, b: &FuncType) -> bool2661 pub fn eq(a: &FuncType, b: &FuncType) -> bool { 2662 assert!(a.comes_from_same_engine(b.engine())); 2663 a.type_index() == b.type_index() 2664 } 2665 comes_from_same_engine(&self, engine: &Engine) -> bool2666 pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool { 2667 Engine::same(self.registered_type.engine(), engine) 2668 } 2669 type_index(&self) -> VMSharedTypeIndex2670 pub(crate) fn type_index(&self) -> VMSharedTypeIndex { 2671 self.registered_type.index() 2672 } 2673 into_registered_type(self) -> RegisteredType2674 pub(crate) fn into_registered_type(self) -> RegisteredType { 2675 self.registered_type 2676 } 2677 2678 /// Construct a `FuncType` from a `WasmFuncType`. 2679 /// 2680 /// This method should only be used when something has already registered -- 2681 /// and is *keeping registered* -- any other concrete Wasm types referenced 2682 /// by the given `WasmFuncType`. 2683 /// 2684 /// For example, this method may be called to convert a function type from 2685 /// within a Wasm module's `ModuleTypes` since the Wasm module itself is 2686 /// holding a strong reference to all of its types, including any `(ref null 2687 /// <index>)` types used in the function's parameters and results. from_wasm_func_type( engine: &Engine, is_final: bool, supertype: Option<EngineOrModuleTypeIndex>, ty: WasmFuncType, ) -> Result<FuncType, OutOfMemory>2688 pub(crate) fn from_wasm_func_type( 2689 engine: &Engine, 2690 is_final: bool, 2691 supertype: Option<EngineOrModuleTypeIndex>, 2692 ty: WasmFuncType, 2693 ) -> Result<FuncType, OutOfMemory> { 2694 let ty = RegisteredType::new( 2695 engine, 2696 WasmSubType { 2697 is_final, 2698 supertype, 2699 composite_type: WasmCompositeType { 2700 shared: false, 2701 inner: WasmCompositeInnerType::Func(ty), 2702 }, 2703 }, 2704 )?; 2705 Ok(Self { 2706 registered_type: ty, 2707 }) 2708 } 2709 from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> FuncType2710 pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> FuncType { 2711 let ty = RegisteredType::root(engine, index); 2712 Self::from_registered_type(ty) 2713 } 2714 from_registered_type(registered_type: RegisteredType) -> Self2715 pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self { 2716 debug_assert!(registered_type.is_func()); 2717 Self { registered_type } 2718 } 2719 /// Construct a func which returns results of default value, if each result type has a default value. default_value(&self, mut store: impl AsContextMut) -> Result<Func>2720 pub fn default_value(&self, mut store: impl AsContextMut) -> Result<Func> { 2721 let dummy_results = self 2722 .results() 2723 .map(|ty| ty.default_value()) 2724 .collect::<Option<Vec<_>>>() 2725 .ok_or_else(|| format_err!("function results do not have a default value"))?; 2726 Ok(Func::new(&mut store, self.clone(), move |_, _, results| { 2727 for (slot, dummy) in results.iter_mut().zip(dummy_results.iter()) { 2728 *slot = *dummy; 2729 } 2730 Ok(()) 2731 })) 2732 } 2733 } 2734 2735 // Continuation types 2736 /// A WebAssembly continuation descriptor. 2737 #[derive(Debug, Clone, Hash)] 2738 pub struct ContType { 2739 registered_type: RegisteredType, 2740 } 2741 2742 impl ContType { 2743 /// Get the engine that this function type is associated with. engine(&self) -> &Engine2744 pub fn engine(&self) -> &Engine { 2745 self.registered_type.engine() 2746 } 2747 comes_from_same_engine(&self, engine: &Engine) -> bool2748 pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool { 2749 Engine::same(self.registered_type.engine(), engine) 2750 } 2751 type_index(&self) -> VMSharedTypeIndex2752 pub(crate) fn type_index(&self) -> VMSharedTypeIndex { 2753 self.registered_type.index() 2754 } 2755 2756 /// Does this continuation type match the other continuation type? 2757 /// 2758 /// That is, is this continuation type a subtype of the other continuation type? 2759 /// 2760 /// # Panics 2761 /// 2762 /// Panics if either type is associated with a different engine from the 2763 /// other. matches(&self, other: &ContType) -> bool2764 pub fn matches(&self, other: &ContType) -> bool { 2765 assert!(self.comes_from_same_engine(other.engine())); 2766 2767 // Avoid matching on structure for subtyping checks when we have 2768 // precisely the same type. 2769 // TODO(dhil): Implement subtype check later. 2770 self.type_index() == other.type_index() 2771 } 2772 from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> ContType2773 pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> ContType { 2774 let ty = RegisteredType::root(engine, index); 2775 assert!(ty.is_cont()); 2776 Self { 2777 registered_type: ty, 2778 } 2779 } 2780 } 2781 2782 // Exception types 2783 2784 /// A WebAssembly exception-object signature type. 2785 /// 2786 /// This type captures the *signature* of an exception object. Note 2787 /// that the WebAssembly standard does not define concrete types in 2788 /// the heap-type lattice between `exn` (any exception object -- the 2789 /// top type) and `noexn` (the uninhabited bottom type). Wasmtime 2790 /// defines concrete types based on the *signature* -- that is, the 2791 /// function type that describes the signature of the exception 2792 /// payload values -- rather than the tag. The tag is a per-instance 2793 /// nominal entity (similar to a memory or a table) and is associated 2794 /// only with particular exception *objects*. 2795 #[derive(Debug, Clone, Hash)] 2796 pub struct ExnType { 2797 func_ty: FuncType, 2798 registered_type: RegisteredType, 2799 } 2800 2801 impl fmt::Display for ExnType { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result2802 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 2803 write!(f, "(exn {}", self.func_ty)?; 2804 for field in self.fields() { 2805 write!(f, " (field {field})")?; 2806 } 2807 write!(f, ")")?; 2808 Ok(()) 2809 } 2810 } 2811 2812 impl ExnType { 2813 /// Create a new `ExnType`. 2814 /// 2815 /// This function creates a new exception object type with the 2816 /// given signature, i.e., list of payload value types. This 2817 /// signature implies a tag type, and when instantiated at 2818 /// runtime, it must be associated with a tag of that type. new(engine: &Engine, fields: impl IntoIterator<Item = ValType>) -> Result<ExnType>2819 pub fn new(engine: &Engine, fields: impl IntoIterator<Item = ValType>) -> Result<ExnType> { 2820 let fields: TryVec<_> = fields.into_iter().try_collect()?; 2821 2822 // First, construct/intern a FuncType: we need this to exist 2823 // so we can hand out a TagType, and it also roots any nested registrations. 2824 let func_ty = FuncType::try_new(engine, fields.iter().cloned(), [])?; 2825 2826 Self::_new(engine, fields, func_ty) 2827 } 2828 2829 /// Create a new `ExnType` from an existing `TagType`. 2830 /// 2831 /// This function creates a new exception object type with the 2832 /// signature represented by the tag. The signature must have no 2833 /// result values, i.e., must be of the form `(T1, T2, ...) -> 2834 /// ()`. from_tag_type(tag: &TagType) -> Result<ExnType>2835 pub fn from_tag_type(tag: &TagType) -> Result<ExnType> { 2836 let func_ty = tag.ty(); 2837 2838 // Check that the tag's signature type has no results. 2839 ensure!( 2840 func_ty.results().len() == 0, 2841 "Cannot create an exception type from a tag type with results in the signature" 2842 ); 2843 2844 Self::_new(tag.ty.engine(), func_ty.params(), func_ty.clone()) 2845 } 2846 _new( engine: &Engine, fields: impl IntoIterator<Item = ValType>, func_ty: FuncType, ) -> Result<ExnType>2847 fn _new( 2848 engine: &Engine, 2849 fields: impl IntoIterator<Item = ValType>, 2850 func_ty: FuncType, 2851 ) -> Result<ExnType> { 2852 let mut wasm_fields = TryVec::new(); 2853 for ty in fields.into_iter() { 2854 assert!(ty.comes_from_same_engine(engine)); 2855 wasm_fields.push(WasmFieldType { 2856 element_type: WasmStorageType::Val(ty.to_wasm_type()), 2857 mutable: false, 2858 })?; 2859 } 2860 2861 let ty = RegisteredType::new( 2862 engine, 2863 WasmSubType { 2864 is_final: true, 2865 supertype: None, 2866 composite_type: WasmCompositeType { 2867 shared: false, 2868 inner: WasmCompositeInnerType::Exn(WasmExnType { 2869 func_ty: EngineOrModuleTypeIndex::Engine(func_ty.type_index()), 2870 fields: wasm_fields.into_boxed_slice()?, 2871 }), 2872 }, 2873 }, 2874 )?; 2875 2876 Ok(ExnType { 2877 func_ty, 2878 registered_type: ty, 2879 }) 2880 } 2881 2882 /// Get the tag type that this exception type is associated with. tag_type(&self) -> TagType2883 pub fn tag_type(&self) -> TagType { 2884 TagType { 2885 ty: self.func_ty.clone(), 2886 } 2887 } 2888 2889 /// Get the `i`th field type. 2890 /// 2891 /// Returns `None` if `i` is out of bounds. field(&self, i: usize) -> Option<FieldType>2892 pub fn field(&self, i: usize) -> Option<FieldType> { 2893 let engine = self.engine(); 2894 self.as_wasm_exn_type() 2895 .fields 2896 .get(i) 2897 .map(|ty| FieldType::from_wasm_field_type(engine, ty)) 2898 } 2899 2900 /// Returns the list of field types for this function. 2901 #[inline] fields(&self) -> impl ExactSizeIterator<Item = FieldType> + '_2902 pub fn fields(&self) -> impl ExactSizeIterator<Item = FieldType> + '_ { 2903 let engine = self.engine(); 2904 self.as_wasm_exn_type() 2905 .fields 2906 .iter() 2907 .map(|ty| FieldType::from_wasm_field_type(engine, ty)) 2908 } 2909 2910 /// Get the engine that this exception type is associated with. engine(&self) -> &Engine2911 pub fn engine(&self) -> &Engine { 2912 self.registered_type.engine() 2913 } 2914 comes_from_same_engine(&self, engine: &Engine) -> bool2915 pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool { 2916 Engine::same(self.registered_type.engine(), engine) 2917 } 2918 as_wasm_exn_type(&self) -> &WasmExnType2919 pub(crate) fn as_wasm_exn_type(&self) -> &WasmExnType { 2920 self.registered_type().unwrap_exn() 2921 } 2922 type_index(&self) -> VMSharedTypeIndex2923 pub(crate) fn type_index(&self) -> VMSharedTypeIndex { 2924 self.registered_type.index() 2925 } 2926 2927 /// Does this exception type match the other exception type? 2928 /// 2929 /// That is, is this exception type a subtype of the other exception type? 2930 /// 2931 /// # Panics 2932 /// 2933 /// Panics if either type is associated with a different engine from the 2934 /// other. matches(&self, other: &ExnType) -> bool2935 pub fn matches(&self, other: &ExnType) -> bool { 2936 assert!(self.comes_from_same_engine(other.engine())); 2937 2938 // We have no concrete-exception-type subtyping; concrete 2939 // exception types are only (mutually, trivially) subtypes if 2940 // they are exactly equal. 2941 self.type_index() == other.type_index() 2942 } 2943 registered_type(&self) -> &RegisteredType2944 pub(crate) fn registered_type(&self) -> &RegisteredType { 2945 &self.registered_type 2946 } 2947 from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> ExnType2948 pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> ExnType { 2949 let ty = RegisteredType::root(engine, index); 2950 assert!(ty.is_exn()); 2951 let func_ty = FuncType::from_shared_type_index( 2952 engine, 2953 ty.unwrap_exn().func_ty.unwrap_engine_type_index(), 2954 ); 2955 Self { 2956 func_ty, 2957 registered_type: ty, 2958 } 2959 } 2960 } 2961 2962 // Global Types 2963 2964 /// A WebAssembly global descriptor. 2965 /// 2966 /// This type describes an instance of a global in a WebAssembly module. Globals 2967 /// are local to an [`Instance`](crate::Instance) and are either immutable or 2968 /// mutable. 2969 #[derive(Debug, Clone, Hash)] 2970 pub struct GlobalType { 2971 content: ValType, 2972 mutability: Mutability, 2973 } 2974 2975 impl GlobalType { 2976 /// Creates a new global descriptor of the specified `content` type and 2977 /// whether or not it's mutable. new(content: ValType, mutability: Mutability) -> GlobalType2978 pub fn new(content: ValType, mutability: Mutability) -> GlobalType { 2979 GlobalType { 2980 content, 2981 mutability, 2982 } 2983 } 2984 2985 /// Returns the value type of this global descriptor. content(&self) -> &ValType2986 pub fn content(&self) -> &ValType { 2987 &self.content 2988 } 2989 2990 /// Returns whether or not this global is mutable. mutability(&self) -> Mutability2991 pub fn mutability(&self) -> Mutability { 2992 self.mutability 2993 } 2994 2995 /// Returns `None` if the wasmtime global has a type that we can't 2996 /// represent, but that should only very rarely happen and indicate a bug. from_wasmtime_global(engine: &Engine, global: &Global) -> GlobalType2997 pub(crate) fn from_wasmtime_global(engine: &Engine, global: &Global) -> GlobalType { 2998 let ty = ValType::from_wasm_type(engine, &global.wasm_ty); 2999 let mutability = if global.mutability { 3000 Mutability::Var 3001 } else { 3002 Mutability::Const 3003 }; 3004 GlobalType::new(ty, mutability) 3005 } 3006 /// Construct a new global import with this type’s default value. 3007 /// 3008 /// This creates a host `Global` in the given store initialized to the 3009 /// type’s zero/null default (e.g. `0` for numeric globals, `null_ref` for refs). default_value(&self, store: impl AsContextMut) -> Result<RuntimeGlobal>3010 pub fn default_value(&self, store: impl AsContextMut) -> Result<RuntimeGlobal> { 3011 let val = self 3012 .content() 3013 .default_value() 3014 .ok_or_else(|| format_err!("global type has no default value"))?; 3015 RuntimeGlobal::new(store, self.clone(), val) 3016 } 3017 into_registered_type(self) -> Option<RegisteredType>3018 pub(crate) fn into_registered_type(self) -> Option<RegisteredType> { 3019 self.content.into_registered_type() 3020 } 3021 } 3022 3023 // Tag Types 3024 3025 /// A descriptor for a tag in a WebAssembly module. 3026 /// 3027 /// Note that tags are local to an [`Instance`](crate::Instance), 3028 /// i.e., are a runtime entity. However, a tag is associated with a 3029 /// function type, and so has a kind of static type. This descriptor 3030 /// is a thin wrapper around a `FuncType` representing the function 3031 /// type of a tag. 3032 #[derive(Debug, Clone, Hash)] 3033 pub struct TagType { 3034 ty: FuncType, 3035 } 3036 3037 impl TagType { 3038 /// Creates a new global descriptor of the specified type. new(ty: FuncType) -> TagType3039 pub fn new(ty: FuncType) -> TagType { 3040 TagType { ty } 3041 } 3042 3043 /// Returns the underlying function type of this tag descriptor. ty(&self) -> &FuncType3044 pub fn ty(&self) -> &FuncType { 3045 &self.ty 3046 } 3047 from_wasmtime_tag(engine: &Engine, tag: &Tag) -> TagType3048 pub(crate) fn from_wasmtime_tag(engine: &Engine, tag: &Tag) -> TagType { 3049 let ty = FuncType::from_shared_type_index(engine, tag.signature.unwrap_engine_type_index()); 3050 TagType { ty } 3051 } 3052 3053 /// Construct a new default tag with this type. 3054 /// 3055 /// This creates a host `Tag` in the given store. Tag instances 3056 /// have no content other than their type, so this "default" value 3057 /// is identical to ordinary host tag allocation. default_value(&self, store: impl AsContextMut) -> Result<RuntimeTag>3058 pub fn default_value(&self, store: impl AsContextMut) -> Result<RuntimeTag> { 3059 RuntimeTag::new(store, self) 3060 } 3061 } 3062 3063 // Table Types 3064 3065 /// A descriptor for a table in a WebAssembly module. 3066 /// 3067 /// Tables are contiguous chunks of a specific element, typically a `funcref` or 3068 /// an `externref`. The most common use for tables is a function table through 3069 /// which `call_indirect` can invoke other functions. 3070 #[derive(Debug, Clone, Hash)] 3071 pub struct TableType { 3072 // Keep a `wasmtime::RefType` so that `TableType::element` doesn't need to 3073 // take an `&Engine`. 3074 element: RefType, 3075 ty: Table, 3076 } 3077 3078 impl TableType { 3079 /// Creates a new table descriptor which will contain the specified 3080 /// `element` and have the `limits` applied to its length. new(element: RefType, min: u32, max: Option<u32>) -> TableType3081 pub fn new(element: RefType, min: u32, max: Option<u32>) -> TableType { 3082 let ref_type = element.to_wasm_type(); 3083 3084 debug_assert!( 3085 ref_type.is_canonicalized_for_runtime_usage(), 3086 "should be canonicalized for runtime usage: {ref_type:?}" 3087 ); 3088 3089 let limits = Limits { 3090 min: u64::from(min), 3091 max: max.map(|x| u64::from(x)), 3092 }; 3093 3094 TableType { 3095 element, 3096 ty: Table { 3097 idx_type: IndexType::I32, 3098 limits, 3099 ref_type, 3100 }, 3101 } 3102 } 3103 3104 /// Crates a new descriptor for a 64-bit table. 3105 /// 3106 /// Note that 64-bit tables are part of the memory64 proposal for 3107 /// WebAssembly which is not standardized yet. new64(element: RefType, min: u64, max: Option<u64>) -> TableType3108 pub fn new64(element: RefType, min: u64, max: Option<u64>) -> TableType { 3109 let ref_type = element.to_wasm_type(); 3110 3111 debug_assert!( 3112 ref_type.is_canonicalized_for_runtime_usage(), 3113 "should be canonicalized for runtime usage: {ref_type:?}" 3114 ); 3115 3116 TableType { 3117 element, 3118 ty: Table { 3119 ref_type, 3120 idx_type: IndexType::I64, 3121 limits: Limits { min, max }, 3122 }, 3123 } 3124 } 3125 3126 /// Returns whether or not this table is a 64-bit table. 3127 /// 3128 /// Note that 64-bit tables are part of the memory64 proposal for 3129 /// WebAssembly which is not standardized yet. is_64(&self) -> bool3130 pub fn is_64(&self) -> bool { 3131 matches!(self.ty.idx_type, IndexType::I64) 3132 } 3133 3134 /// Returns the element value type of this table. element(&self) -> &RefType3135 pub fn element(&self) -> &RefType { 3136 &self.element 3137 } 3138 3139 /// Returns minimum number of elements this table must have minimum(&self) -> u643140 pub fn minimum(&self) -> u64 { 3141 self.ty.limits.min 3142 } 3143 3144 /// Returns the optionally-specified maximum number of elements this table 3145 /// can have. 3146 /// 3147 /// If this returns `None` then the table is not limited in size. maximum(&self) -> Option<u64>3148 pub fn maximum(&self) -> Option<u64> { 3149 self.ty.limits.max 3150 } 3151 from_wasmtime_table(engine: &Engine, table: &Table) -> TableType3152 pub(crate) fn from_wasmtime_table(engine: &Engine, table: &Table) -> TableType { 3153 let element = RefType::from_wasm_type(engine, &table.ref_type); 3154 TableType { 3155 element, 3156 ty: *table, 3157 } 3158 } 3159 wasmtime_table(&self) -> &Table3160 pub(crate) fn wasmtime_table(&self) -> &Table { 3161 &self.ty 3162 } 3163 /// Construct a new table import whose entries are filled with this type’s default. 3164 /// 3165 /// Creates a host `Table` in the store with its initial size and element 3166 /// type’s default (e.g. `null_ref` for nullable refs). default_value(&self, store: impl AsContextMut) -> Result<RuntimeTable>3167 pub fn default_value(&self, store: impl AsContextMut) -> Result<RuntimeTable> { 3168 let val: ValType = self.element().clone().into(); 3169 let init_val = val 3170 .default_value() 3171 .context("table element type does not have a default value")? 3172 .ref_() 3173 .unwrap(); 3174 RuntimeTable::new(store, self.clone(), init_val) 3175 } 3176 } 3177 3178 // Memory Types 3179 3180 /// A builder for [`MemoryType`][crate::MemoryType]s. 3181 /// 3182 /// A new builder can be constructed via its `Default` implementation. 3183 /// 3184 /// When you're done configuring, get the underlying 3185 /// [`MemoryType`][crate::MemoryType] by calling the 3186 /// [`build`][crate::MemoryTypeBuilder::build] method. 3187 /// 3188 /// # Example 3189 /// 3190 /// ``` 3191 /// # fn foo() -> wasmtime::Result<()> { 3192 /// use wasmtime::MemoryTypeBuilder; 3193 /// 3194 /// let memory_type = MemoryTypeBuilder::new() 3195 /// // Set the minimum size, in pages. 3196 /// .min(4096) 3197 /// // Set the maximum size, in pages. 3198 /// .max(Some(4096)) 3199 /// // Set the page size to 1 byte (aka 2**0). 3200 /// .page_size_log2(0) 3201 /// // Get the underlying memory type. 3202 /// .build()?; 3203 /// # Ok(()) 3204 /// # } 3205 /// ``` 3206 pub struct MemoryTypeBuilder { 3207 ty: Memory, 3208 } 3209 3210 impl Default for MemoryTypeBuilder { default() -> Self3211 fn default() -> Self { 3212 MemoryTypeBuilder { 3213 ty: Memory { 3214 idx_type: IndexType::I32, 3215 limits: Limits { min: 0, max: None }, 3216 shared: false, 3217 page_size_log2: Memory::DEFAULT_PAGE_SIZE_LOG2, 3218 }, 3219 } 3220 } 3221 } 3222 3223 impl MemoryTypeBuilder { 3224 /// Create a new builder for a [`MemoryType`] with the default settings. 3225 /// 3226 /// By default memory types have the following properties: 3227 /// 3228 /// * The minimum memory size is 0 pages. 3229 /// * The maximum memory size is unspecified. 3230 /// * Memories use 32-bit indexes. 3231 /// * The page size is 64KiB. 3232 /// 3233 /// Each option can be configured through the methods on the returned 3234 /// builder. new() -> MemoryTypeBuilder3235 pub fn new() -> MemoryTypeBuilder { 3236 MemoryTypeBuilder::default() 3237 } 3238 validate(&self) -> Result<()>3239 fn validate(&self) -> Result<()> { 3240 if self 3241 .ty 3242 .limits 3243 .max 3244 .map_or(false, |max| max < self.ty.limits.min) 3245 { 3246 bail!("maximum page size cannot be smaller than the minimum page size"); 3247 } 3248 3249 match self.ty.page_size_log2 { 3250 0 | Memory::DEFAULT_PAGE_SIZE_LOG2 => {} 3251 x => bail!( 3252 "page size must be 2**16 or 2**0, but was given 2**{x}; note \ 3253 that future Wasm extensions might allow any power of two page \ 3254 size, but only 2**16 and 2**0 are currently valid", 3255 ), 3256 } 3257 3258 if self.ty.shared && self.ty.limits.max.is_none() { 3259 bail!("shared memories must have a maximum size"); 3260 } 3261 3262 let absolute_max = self.ty.max_size_based_on_index_type(); 3263 let min = self 3264 .ty 3265 .minimum_byte_size() 3266 .context("memory's minimum byte size must fit in a u64")?; 3267 if min > absolute_max { 3268 bail!("minimum size is too large for this memory type's index type"); 3269 } 3270 if self 3271 .ty 3272 .maximum_byte_size() 3273 .map_or(false, |max| max > absolute_max) 3274 { 3275 bail!("maximum size is too large for this memory type's index type"); 3276 } 3277 3278 Ok(()) 3279 } 3280 3281 /// Set the minimum size, in units of pages, for the memory type being 3282 /// built. 3283 /// 3284 /// The default minimum is `0`. min(&mut self, minimum: u64) -> &mut Self3285 pub fn min(&mut self, minimum: u64) -> &mut Self { 3286 self.ty.limits.min = minimum; 3287 self 3288 } 3289 3290 /// Set the maximum size, in units of pages, for the memory type being 3291 /// built. 3292 /// 3293 /// The default maximum is `None`. max(&mut self, maximum: Option<u64>) -> &mut Self3294 pub fn max(&mut self, maximum: Option<u64>) -> &mut Self { 3295 self.ty.limits.max = maximum; 3296 self 3297 } 3298 3299 /// Set whether this is a 64-bit memory or not. 3300 /// 3301 /// If a memory is not a 64-bit memory, then it is a 32-bit memory. 3302 /// 3303 /// The default is `false`, aka 32-bit memories. 3304 /// 3305 /// Note that 64-bit memories are part of [the memory64 3306 /// proposal](https://github.com/WebAssembly/memory64) for WebAssembly which 3307 /// is not fully standardized yet. memory64(&mut self, memory64: bool) -> &mut Self3308 pub fn memory64(&mut self, memory64: bool) -> &mut Self { 3309 self.ty.idx_type = match memory64 { 3310 true => IndexType::I64, 3311 false => IndexType::I32, 3312 }; 3313 self 3314 } 3315 3316 /// Set the sharedness for the memory type being built. 3317 /// 3318 /// The default is `false`, aka unshared. 3319 /// 3320 /// Note that shared memories are part of [the threads 3321 /// proposal](https://github.com/WebAssembly/threads) for WebAssembly which 3322 /// is not fully standardized yet. shared(&mut self, shared: bool) -> &mut Self3323 pub fn shared(&mut self, shared: bool) -> &mut Self { 3324 self.ty.shared = shared; 3325 self 3326 } 3327 3328 /// Set the log base 2 of the page size, in bytes, for the memory type being 3329 /// built. 3330 /// 3331 /// The default value is `16`, which results in the default Wasm page size 3332 /// of 64KiB (aka 2<sup>16</sup> or 65536). 3333 /// 3334 /// Other than `16`, the only valid value is `0`, which results in a page 3335 /// size of one byte (aka 2<sup>0</sup>). Single-byte page sizes can be used 3336 /// to get fine-grained control over a Wasm memory's resource consumption 3337 /// and run Wasm in embedded environments with less than 64KiB of RAM, for 3338 /// example. 3339 /// 3340 /// Future extensions to the core WebAssembly language might relax these 3341 /// constraints and introduce more valid page sizes, such as any power of 3342 /// two between 1 and 65536 inclusive. 3343 /// 3344 /// Note that non-default page sizes are part of [the custom-page-sizes 3345 /// proposal](https://github.com/WebAssembly/custom-page-sizes) for 3346 /// WebAssembly which is not fully standardized yet. page_size_log2(&mut self, page_size_log2: u8) -> &mut Self3347 pub fn page_size_log2(&mut self, page_size_log2: u8) -> &mut Self { 3348 self.ty.page_size_log2 = page_size_log2; 3349 self 3350 } 3351 3352 /// Get the underlying memory type that this builder has been building. 3353 /// 3354 /// # Errors 3355 /// 3356 /// Returns an error if the configured memory type is invalid, for example 3357 /// if the maximum size is smaller than the minimum size. build(&self) -> Result<MemoryType>3358 pub fn build(&self) -> Result<MemoryType> { 3359 self.validate()?; 3360 Ok(MemoryType { ty: self.ty }) 3361 } 3362 } 3363 3364 /// A descriptor for a WebAssembly memory type. 3365 /// 3366 /// Memories are described in units of pages (64KB) and represent contiguous 3367 /// chunks of addressable memory. 3368 #[derive(Debug, Clone, Hash, Eq, PartialEq)] 3369 pub struct MemoryType { 3370 ty: Memory, 3371 } 3372 3373 impl MemoryType { 3374 /// Creates a new descriptor for a 32-bit WebAssembly memory given the 3375 /// specified limits of the memory. 3376 /// 3377 /// The `minimum` and `maximum` values here are specified in units of 3378 /// WebAssembly pages, which are 64KiB by default. Use 3379 /// [`MemoryTypeBuilder`][crate::MemoryTypeBuilder] if you want a 3380 /// non-default page size. 3381 /// 3382 /// # Panics 3383 /// 3384 /// Panics if the minimum is greater than the maximum or if the minimum or 3385 /// maximum number of pages can result in a byte size that is not 3386 /// addressable with a 32-bit integer. new(minimum: u32, maximum: Option<u32>) -> MemoryType3387 pub fn new(minimum: u32, maximum: Option<u32>) -> MemoryType { 3388 MemoryTypeBuilder::default() 3389 .min(minimum.into()) 3390 .max(maximum.map(Into::into)) 3391 .build() 3392 .unwrap() 3393 } 3394 3395 /// Creates a new descriptor for a 64-bit WebAssembly memory given the 3396 /// specified limits of the memory. 3397 /// 3398 /// The `minimum` and `maximum` values here are specified in units of 3399 /// WebAssembly pages, which are 64KiB by default. Use 3400 /// [`MemoryTypeBuilder`][crate::MemoryTypeBuilder] if you want a 3401 /// non-default page size. 3402 /// 3403 /// Note that 64-bit memories are part of [the memory64 3404 /// proposal](https://github.com/WebAssembly/memory64) for WebAssembly which 3405 /// is not fully standardized yet. 3406 /// 3407 /// # Panics 3408 /// 3409 /// Panics if the minimum is greater than the maximum or if the minimum or 3410 /// maximum number of pages can result in a byte size that is not 3411 /// addressable with a 64-bit integer. new64(minimum: u64, maximum: Option<u64>) -> MemoryType3412 pub fn new64(minimum: u64, maximum: Option<u64>) -> MemoryType { 3413 MemoryTypeBuilder::default() 3414 .memory64(true) 3415 .min(minimum) 3416 .max(maximum) 3417 .build() 3418 .unwrap() 3419 } 3420 3421 /// Creates a new descriptor for shared WebAssembly memory given the 3422 /// specified limits of the memory. 3423 /// 3424 /// The `minimum` and `maximum` values here are specified in units of 3425 /// WebAssembly pages, which are 64KiB by default. Use 3426 /// [`MemoryTypeBuilder`][crate::MemoryTypeBuilder] if you want a 3427 /// non-default page size. 3428 /// 3429 /// Note that shared memories are part of [the threads 3430 /// proposal](https://github.com/WebAssembly/threads) for WebAssembly which 3431 /// is not fully standardized yet. 3432 /// 3433 /// # Panics 3434 /// 3435 /// Panics if the minimum is greater than the maximum or if the minimum or 3436 /// maximum number of pages can result in a byte size that is not 3437 /// addressable with a 32-bit integer. shared(minimum: u32, maximum: u32) -> MemoryType3438 pub fn shared(minimum: u32, maximum: u32) -> MemoryType { 3439 MemoryTypeBuilder::default() 3440 .shared(true) 3441 .min(minimum.into()) 3442 .max(Some(maximum.into())) 3443 .build() 3444 .unwrap() 3445 } 3446 3447 /// Creates a new [`MemoryTypeBuilder`] to configure all the various knobs 3448 /// of the final memory type being created. 3449 /// 3450 /// This is a convenience function for [`MemoryTypeBuilder::new`]. builder() -> MemoryTypeBuilder3451 pub fn builder() -> MemoryTypeBuilder { 3452 MemoryTypeBuilder::new() 3453 } 3454 3455 /// Returns whether this is a 64-bit memory or not. 3456 /// 3457 /// Note that 64-bit memories are part of the memory64 proposal for 3458 /// WebAssembly which is not standardized yet. is_64(&self) -> bool3459 pub fn is_64(&self) -> bool { 3460 matches!(self.ty.idx_type, IndexType::I64) 3461 } 3462 3463 /// Returns whether this is a shared memory or not. 3464 /// 3465 /// Note that shared memories are part of the threads proposal for 3466 /// WebAssembly which is not standardized yet. is_shared(&self) -> bool3467 pub fn is_shared(&self) -> bool { 3468 self.ty.shared 3469 } 3470 3471 /// Returns minimum number of WebAssembly pages this memory must have. 3472 /// 3473 /// Note that the return value, while a `u64`, will always fit into a `u32` 3474 /// for 32-bit memories. minimum(&self) -> u643475 pub fn minimum(&self) -> u64 { 3476 self.ty.limits.min 3477 } 3478 3479 /// Returns the optionally-specified maximum number of pages this memory 3480 /// can have. 3481 /// 3482 /// If this returns `None` then the memory is not limited in size. 3483 /// 3484 /// Note that the return value, while a `u64`, will always fit into a `u32` 3485 /// for 32-bit memories. maximum(&self) -> Option<u64>3486 pub fn maximum(&self) -> Option<u64> { 3487 self.ty.limits.max 3488 } 3489 3490 /// This memory's page size, in bytes. page_size(&self) -> u643491 pub fn page_size(&self) -> u64 { 3492 self.ty.page_size() 3493 } 3494 3495 /// The log2 of this memory's page size, in bytes. page_size_log2(&self) -> u83496 pub fn page_size_log2(&self) -> u8 { 3497 self.ty.page_size_log2 3498 } 3499 from_wasmtime_memory(memory: &Memory) -> MemoryType3500 pub(crate) fn from_wasmtime_memory(memory: &Memory) -> MemoryType { 3501 MemoryType { ty: *memory } 3502 } 3503 wasmtime_memory(&self) -> &Memory3504 pub(crate) fn wasmtime_memory(&self) -> &Memory { 3505 &self.ty 3506 } 3507 /// Construct a new memory import initialized to this memory type’s default 3508 /// state. 3509 /// 3510 /// Returns a host `Memory` or `SharedMemory` depending on if this is a 3511 /// shared memory type or not. The memory's type will have the same type as 3512 /// `self` and the initial contents of the memory, if any, will be all zero. default_value(&self, store: impl AsContextMut) -> Result<Extern>3513 pub fn default_value(&self, store: impl AsContextMut) -> Result<Extern> { 3514 Ok(if self.is_shared() { 3515 #[cfg(feature = "threads")] 3516 { 3517 let store = store.as_context(); 3518 Extern::SharedMemory(crate::SharedMemory::new(store.engine(), self.clone())?) 3519 } 3520 #[cfg(not(feature = "threads"))] 3521 { 3522 bail!("creation of shared memories disabled at compile time") 3523 } 3524 } else { 3525 Extern::Memory(crate::Memory::new(store, self.clone())?) 3526 }) 3527 } 3528 } 3529 3530 // Import Types 3531 3532 /// A descriptor for an imported value into a wasm module. 3533 /// 3534 /// This type is primarily accessed from the 3535 /// [`Module::imports`](crate::Module::imports) API. Each [`ImportType`] 3536 /// describes an import into the wasm module with the module/name that it's 3537 /// imported from as well as the type of item that's being imported. 3538 #[derive(Clone)] 3539 pub struct ImportType<'module> { 3540 /// The module of the import. 3541 module: &'module str, 3542 3543 /// The field of the import. 3544 name: &'module str, 3545 3546 /// The type of the import. 3547 ty: EntityType, 3548 types: &'module ModuleTypes, 3549 engine: &'module Engine, 3550 } 3551 3552 impl<'module> ImportType<'module> { 3553 /// Creates a new import descriptor which comes from `module` and `name` and 3554 /// is of type `ty`. new( module: &'module str, name: &'module str, ty: EntityType, types: &'module ModuleTypes, engine: &'module Engine, ) -> ImportType<'module>3555 pub(crate) fn new( 3556 module: &'module str, 3557 name: &'module str, 3558 ty: EntityType, 3559 types: &'module ModuleTypes, 3560 engine: &'module Engine, 3561 ) -> ImportType<'module> { 3562 assert!(ty.is_canonicalized_for_runtime_usage()); 3563 ImportType { 3564 module, 3565 name, 3566 ty, 3567 types, 3568 engine, 3569 } 3570 } 3571 3572 /// Returns the module name that this import is expected to come from. module(&self) -> &'module str3573 pub fn module(&self) -> &'module str { 3574 self.module 3575 } 3576 3577 /// Returns the field name of the module that this import is expected to 3578 /// come from. name(&self) -> &'module str3579 pub fn name(&self) -> &'module str { 3580 self.name 3581 } 3582 3583 /// Returns the expected type of this import. ty(&self) -> ExternType3584 pub fn ty(&self) -> ExternType { 3585 ExternType::from_wasmtime(self.engine, self.types, &self.ty) 3586 } 3587 } 3588 3589 impl<'module> fmt::Debug for ImportType<'module> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result3590 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 3591 f.debug_struct("ImportType") 3592 .field("module", &self.module()) 3593 .field("name", &self.name()) 3594 .field("ty", &self.ty()) 3595 .finish() 3596 } 3597 } 3598 3599 // Export Types 3600 3601 /// A descriptor for an exported WebAssembly value. 3602 /// 3603 /// This type is primarily accessed from the 3604 /// [`Module::exports`](crate::Module::exports) accessor and describes what 3605 /// names are exported from a wasm module and the type of the item that is 3606 /// exported. 3607 #[derive(Clone)] 3608 pub struct ExportType<'module> { 3609 /// The name of the export. 3610 name: &'module str, 3611 3612 /// The type of the export. 3613 ty: EntityType, 3614 types: &'module ModuleTypes, 3615 engine: &'module Engine, 3616 } 3617 3618 impl<'module> ExportType<'module> { 3619 /// Creates a new export which is exported with the given `name` and has the 3620 /// given `ty`. new( name: &'module str, ty: EntityType, types: &'module ModuleTypes, engine: &'module Engine, ) -> ExportType<'module>3621 pub(crate) fn new( 3622 name: &'module str, 3623 ty: EntityType, 3624 types: &'module ModuleTypes, 3625 engine: &'module Engine, 3626 ) -> ExportType<'module> { 3627 ExportType { 3628 name, 3629 ty, 3630 types, 3631 engine, 3632 } 3633 } 3634 3635 /// Returns the name by which this export is known. name(&self) -> &'module str3636 pub fn name(&self) -> &'module str { 3637 self.name 3638 } 3639 3640 /// Returns the type of this export. ty(&self) -> ExternType3641 pub fn ty(&self) -> ExternType { 3642 ExternType::from_wasmtime(self.engine, self.types, &self.ty) 3643 } 3644 } 3645 3646 impl<'module> fmt::Debug for ExportType<'module> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result3647 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 3648 f.debug_struct("ExportType") 3649 .field("name", &self.name().to_owned()) 3650 .field("ty", &self.ty()) 3651 .finish() 3652 } 3653 } 3654