Next Generation WASM Microkernel Operating System
at main 1893 lines 63 kB view raw
1// Copyright 2025 Jonas Kruckenberg 2// 3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or 4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or 5// http://opensource.org/licenses/MIT>, at your option. This file may not be 6// copied, modified, or distributed except according to those terms. 7 8use alloc::string::{String, ToString}; 9use alloc::vec::Vec; 10use core::fmt; 11use core::fmt::{Display, Write}; 12 13use anyhow::{bail, ensure}; 14 15use crate::wasm::Engine; 16use crate::wasm::indices::{CanonicalizedTypeIndex, VMSharedTypeIndex}; 17use crate::wasm::translate::{ 18 EntityType, Global, Memory, ModuleTypes, Table, Tag, WasmCompositeType, WasmCompositeTypeInner, 19 WasmFieldType, WasmFuncType, WasmHeapType, WasmHeapTypeInner, WasmRefType, WasmStorageType, 20 WasmSubType, WasmValType, 21}; 22use crate::wasm::type_registry::RegisteredType; 23 24/// Indicator of whether a global value, struct's field, or array type's 25/// elements are mutable or not. 26#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] 27pub enum Mutability { 28 /// The global value, struct field, or array elements are constant and the 29 /// value does not change. 30 Const, 31 /// The value of the global, struct field, or array elements can change over 32 /// time. 33 Var, 34} 35 36impl Mutability { 37 /// Is this constant? 38 #[inline] 39 pub fn is_const(self) -> bool { 40 self == Self::Const 41 } 42 43 /// Is this variable? 44 #[inline] 45 pub fn is_var(self) -> bool { 46 self == Self::Var 47 } 48} 49 50/// Indicator of whether a type is final or not. 51/// 52/// Final types may not be the supertype of other types. 53#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] 54pub enum Finality { 55 /// The associated type is final. 56 Final, 57 /// The associated type is not final. 58 NonFinal, 59} 60 61impl Finality { 62 /// Is this final? 63 #[inline] 64 pub fn is_final(self) -> bool { 65 self == Self::Final 66 } 67 68 /// Is this non-final? 69 #[inline] 70 pub fn is_non_final(self) -> bool { 71 self == Self::NonFinal 72 } 73} 74 75/// Possible value types in WebAssembly. 76/// 77/// # Subtyping and Equality 78/// 79/// `ValType` does not implement `Eq`, because reference types have a subtyping 80/// relationship, and so 99.99% of the time you actually want to check whether 81/// one type matches (i.e. is a subtype of) another type. You can use the 82/// [`ValType::matches`] and [`Val::matches_ty`][crate::wasm::Val::matches_ty] methods 83/// to perform these types of checks. If, however, you are in that 0.01% 84/// scenario where you need to check precise equality between types, you can use 85/// the [`ValType::eq`] method. 86#[derive(Clone, Hash)] 87pub enum ValType { 88 // NB: the ordering of variants here is intended to match the ordering in 89 // `wasmtime_environ::WasmType` to help improve codegen when converting. 90 // 91 /// Signed 32 bit integer. 92 I32, 93 /// Signed 64 bit integer. 94 I64, 95 /// Floating point 32 bit integer. 96 F32, 97 /// Floating point 64 bit integer. 98 F64, 99 /// A 128 bit number. 100 V128, 101 /// An opaque reference to some type on the heap. 102 Ref(RefType), 103} 104 105impl fmt::Debug for ValType { 106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 107 fmt::Display::fmt(self, f) 108 } 109} 110 111impl Display for ValType { 112 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 113 match self { 114 ValType::I32 => write!(f, "i32"), 115 ValType::I64 => write!(f, "i64"), 116 ValType::F32 => write!(f, "f32"), 117 ValType::F64 => write!(f, "f64"), 118 ValType::V128 => write!(f, "v128"), 119 ValType::Ref(r) => Display::fmt(r, f), 120 } 121 } 122} 123 124impl ValType { 125 /// The `externref` type, aka `(ref null extern)`. 126 pub const EXTERNREF: Self = ValType::Ref(RefType::EXTERNREF); 127 128 /// The `nullexternref` type, aka `(ref null noextern)`. 129 pub const NULLEXTERNREF: Self = ValType::Ref(RefType::NULLEXTERNREF); 130 131 /// The `funcref` type, aka `(ref null func)`. 132 pub const FUNCREF: Self = ValType::Ref(RefType::FUNCREF); 133 134 /// The `nullfuncref` type, aka `(ref null nofunc)`. 135 pub const NULLFUNCREF: Self = ValType::Ref(RefType::NULLFUNCREF); 136 137 /// The `anyref` type, aka `(ref null any)`. 138 pub const ANYREF: Self = ValType::Ref(RefType::ANYREF); 139 140 /// The `eqref` type, aka `(ref null eq)`. 141 pub const EQREF: Self = ValType::Ref(RefType::EQREF); 142 143 /// The `i31ref` type, aka `(ref null i31)`. 144 pub const I31REF: Self = ValType::Ref(RefType::I31REF); 145 146 /// The `arrayref` type, aka `(ref null array)`. 147 pub const ARRAYREF: Self = ValType::Ref(RefType::ARRAYREF); 148 149 /// The `structref` type, aka `(ref null struct)`. 150 pub const STRUCTREF: Self = ValType::Ref(RefType::STRUCTREF); 151 152 /// The `nullref` type, aka `(ref null none)`. 153 pub const NULLREF: Self = ValType::Ref(RefType::NULLREF); 154 155 /// Returns true if `ValType` matches any of the numeric types. (e.g. `I32`, 156 /// `I64`, `F32`, `F64`). 157 #[inline] 158 pub fn is_num(&self) -> bool { 159 matches!( 160 self, 161 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 162 ) 163 } 164 165 /// Is this the `i32` type? 166 #[inline] 167 pub fn is_i32(&self) -> bool { 168 matches!(self, ValType::I32) 169 } 170 171 /// Is this the `i64` type? 172 #[inline] 173 pub fn is_i64(&self) -> bool { 174 matches!(self, ValType::I64) 175 } 176 177 /// Is this the `f32` type? 178 #[inline] 179 pub fn is_f32(&self) -> bool { 180 matches!(self, ValType::F32) 181 } 182 183 /// Is this the `f64` type? 184 #[inline] 185 pub fn is_f64(&self) -> bool { 186 matches!(self, ValType::F64) 187 } 188 189 /// Is this the `v128` type? 190 #[inline] 191 pub fn is_v128(&self) -> bool { 192 matches!(self, ValType::V128) 193 } 194 195 /// Returns true if `ValType` is any kind of reference type. 196 #[inline] 197 pub fn is_ref(&self) -> bool { 198 matches!(self, ValType::Ref(_)) 199 } 200 201 /// Is this the `funcref` (aka `(ref null func)`) type? 202 #[inline] 203 pub fn is_funcref(&self) -> bool { 204 matches!( 205 self, 206 ValType::Ref(RefType { 207 nullable: true, 208 heap_type: HeapType { 209 inner: HeapTypeInner::Func, 210 shared: _ 211 } 212 }) 213 ) 214 } 215 216 /// Is this the `externref` (aka `(ref null extern)`) type? 217 #[inline] 218 pub fn is_externref(&self) -> bool { 219 matches!( 220 self, 221 ValType::Ref(RefType { 222 nullable: true, 223 heap_type: HeapType { 224 inner: HeapTypeInner::Extern, 225 shared: _ 226 } 227 }) 228 ) 229 } 230 231 /// Is this the `anyref` (aka `(ref null any)`) type? 232 #[inline] 233 pub fn is_anyref(&self) -> bool { 234 matches!( 235 self, 236 ValType::Ref(RefType { 237 nullable: true, 238 heap_type: HeapType { 239 inner: HeapTypeInner::Any, 240 shared: _ 241 } 242 }) 243 ) 244 } 245 246 /// Get the underlying reference type, if this value type is a reference 247 /// type. 248 #[inline] 249 pub fn as_ref(&self) -> Option<&RefType> { 250 match self { 251 ValType::Ref(r) => Some(r), 252 _ => None, 253 } 254 } 255 256 /// Get the underlying reference type, panicking if this value type is not a 257 /// reference type. 258 #[inline] 259 pub fn unwrap_ref(&self) -> &RefType { 260 self.as_ref() 261 .expect("ValType::unwrap_ref on a non-reference type") 262 } 263 264 /// Does this value type match the other type? 265 /// 266 /// That is, is this value type a subtype of the other? 267 /// 268 /// # Panics 269 /// 270 /// Panics if either type is associated with a different engine from the 271 /// other. 272 pub fn matches(&self, other: &ValType) -> bool { 273 match (self, other) { 274 (Self::I32, Self::I32) => true, 275 (Self::I64, Self::I64) => true, 276 (Self::F32, Self::F32) => true, 277 (Self::F64, Self::F64) => true, 278 (Self::V128, Self::V128) => true, 279 (Self::Ref(a), Self::Ref(b)) => a.matches(b), 280 (Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128 | Self::Ref(_), _) => false, 281 } 282 } 283 284 /// Is value type `a` precisely equal to value type `b`? 285 /// 286 /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they 287 /// are not exactly the same value type. 288 /// 289 /// # Panics 290 /// 291 /// Panics if either type is associated with a different engine. 292 pub fn eq(a: &Self, b: &Self) -> bool { 293 a.matches(b) && b.matches(a) 294 } 295 296 pub fn ensure_matches(&self, engine: &Engine, other: &ValType) -> crate::Result<()> { 297 if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) { 298 bail!("type used with wrong engine"); 299 } 300 if self.matches(other) { 301 Ok(()) 302 } else { 303 bail!("type mismatch: expected {other}, found {self}") 304 } 305 } 306 307 pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool { 308 match self { 309 Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128 => true, 310 Self::Ref(r) => r.comes_from_same_engine(engine), 311 } 312 } 313 314 pub(crate) fn to_wasm_type(&self) -> WasmValType { 315 match self { 316 Self::I32 => WasmValType::I32, 317 Self::I64 => WasmValType::I64, 318 Self::F32 => WasmValType::F32, 319 Self::F64 => WasmValType::F64, 320 Self::V128 => WasmValType::V128, 321 Self::Ref(r) => WasmValType::Ref(r.to_wasm_type()), 322 } 323 } 324 325 #[inline] 326 pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmValType) -> Self { 327 match ty { 328 WasmValType::I32 => Self::I32, 329 WasmValType::I64 => Self::I64, 330 WasmValType::F32 => Self::F32, 331 WasmValType::F64 => Self::F64, 332 WasmValType::V128 => Self::V128, 333 WasmValType::Ref(r) => Self::Ref(RefType::from_wasm_type(engine, r)), 334 } 335 } 336} 337 338/// Opaque references to data in the Wasm heap or to host data. 339/// 340/// # Subtyping and Equality 341/// 342/// `RefType` does not implement `Eq`, because reference types have a subtyping 343/// relationship, and so 99.99% of the time you actually want to check whether 344/// one type matches (i.e. is a subtype of) another type. You can use the 345/// [`RefType::matches`] and [`Ref::matches_ty`][crate::Ref::matches_ty] methods 346/// to perform these types of checks. If, however, you are in that 0.01% 347/// scenario where you need to check precise equality between types, you can use 348/// the [`RefType::eq`] method. 349#[derive(Clone, Hash)] 350pub struct RefType { 351 nullable: bool, 352 heap_type: HeapType, 353} 354 355impl fmt::Debug for RefType { 356 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 357 Display::fmt(self, f) 358 } 359} 360 361impl fmt::Display for RefType { 362 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 363 write!(f, "(ref ")?; 364 if self.is_nullable() { 365 write!(f, "null ")?; 366 } 367 write!(f, "{})", self.heap_type()) 368 } 369} 370 371impl RefType { 372 /// The `externref` type, aka `(ref null extern)`. 373 pub const EXTERNREF: Self = RefType { 374 nullable: true, 375 heap_type: HeapType::EXTERN, 376 }; 377 378 /// The `nullexternref` type, aka `(ref null noextern)`. 379 pub const NULLEXTERNREF: Self = RefType { 380 nullable: true, 381 heap_type: HeapType::NOEXTERN, 382 }; 383 384 /// The `funcref` type, aka `(ref null func)`. 385 pub const FUNCREF: Self = RefType { 386 nullable: true, 387 heap_type: HeapType::FUNC, 388 }; 389 390 /// The `nullfuncref` type, aka `(ref null nofunc)`. 391 pub const NULLFUNCREF: Self = RefType { 392 nullable: true, 393 heap_type: HeapType::NOFUNC, 394 }; 395 396 /// The `anyref` type, aka `(ref null any)`. 397 pub const ANYREF: Self = RefType { 398 nullable: true, 399 heap_type: HeapType::ANY, 400 }; 401 402 /// The `eqref` type, aka `(ref null eq)`. 403 pub const EQREF: Self = RefType { 404 nullable: true, 405 heap_type: HeapType::EQ, 406 }; 407 408 /// The `i31ref` type, aka `(ref null i31)`. 409 pub const I31REF: Self = RefType { 410 nullable: true, 411 heap_type: HeapType::I31, 412 }; 413 414 /// The `arrayref` type, aka `(ref null array)`. 415 pub const ARRAYREF: Self = RefType { 416 nullable: true, 417 heap_type: HeapType::ARRAY, 418 }; 419 420 /// The `structref` type, aka `(ref null struct)`. 421 pub const STRUCTREF: Self = RefType { 422 nullable: true, 423 heap_type: HeapType::STRUCT, 424 }; 425 426 /// The `nullref` type, aka `(ref null none)`. 427 pub const NULLREF: Self = RefType { 428 nullable: true, 429 heap_type: HeapType::NONE, 430 }; 431 432 /// Construct a new reference type. 433 pub fn new(nullable: bool, heap_type: HeapType) -> RefType { 434 RefType { 435 nullable, 436 heap_type, 437 } 438 } 439 440 /// Can this type of reference be null? 441 pub fn is_nullable(&self) -> bool { 442 self.nullable 443 } 444 445 /// The heap type that this is a reference to. 446 #[inline] 447 pub fn heap_type(&self) -> &HeapType { 448 &self.heap_type 449 } 450 451 /// Does this reference type match the other? 452 /// 453 /// That is, is this reference type a subtype of the other? 454 /// 455 /// # Panics 456 /// 457 /// Panics if either type is associated with a different engine from the 458 /// other. 459 pub fn matches(&self, other: &RefType) -> bool { 460 if self.is_nullable() && !other.is_nullable() { 461 return false; 462 } 463 self.heap_type().matches(other.heap_type()) 464 } 465 466 /// Is reference type `a` precisely equal to reference type `b`? 467 /// 468 /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they 469 /// are not exactly the same reference type. 470 /// 471 /// # Panics 472 /// 473 /// Panics if either type is associated with a different engine. 474 pub fn eq(a: &RefType, b: &RefType) -> bool { 475 a.matches(b) && b.matches(a) 476 } 477 478 pub fn ensure_matches(&self, engine: &Engine, other: &RefType) -> crate::Result<()> { 479 if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) { 480 bail!("type used with wrong engine"); 481 } 482 if self.matches(other) { 483 Ok(()) 484 } else { 485 bail!("type mismatch: expected {other}, found {self}") 486 } 487 } 488 489 pub(super) fn comes_from_same_engine(&self, engine: &Engine) -> bool { 490 self.heap_type().comes_from_same_engine(engine) 491 } 492 493 pub(super) fn to_wasm_type(&self) -> WasmRefType { 494 WasmRefType { 495 nullable: self.is_nullable(), 496 heap_type: self.heap_type().to_wasm_type(), 497 } 498 } 499 500 pub(super) fn from_wasm_type(engine: &Engine, ty: &WasmRefType) -> RefType { 501 RefType { 502 nullable: ty.nullable, 503 heap_type: HeapType::from_wasm_type(engine, &ty.heap_type), 504 } 505 } 506} 507 508#[derive(Debug, Clone, Hash)] 509pub struct HeapType { 510 pub shared: bool, 511 pub inner: HeapTypeInner, 512} 513 514#[derive(Debug, Clone, Hash)] 515pub enum HeapTypeInner { 516 /// The abstract `extern` heap type represents external host data. 517 /// 518 /// This is the top type for the external type hierarchy, and therefore is 519 /// the common supertype of all external reference types. 520 Extern, 521 /// The abstract `noextern` heap type represents the null external 522 /// reference. 523 /// 524 /// This is the bottom type for the external type hierarchy, and therefore 525 /// is the common subtype of all external reference types. 526 NoExtern, 527 528 /// The abstract `func` heap type represents a reference to any kind of 529 /// function. 530 /// 531 /// This is the top type for the function references type hierarchy, and is 532 /// therefore a supertype of every function reference. 533 Func, 534 /// A reference to a function of a specific, concrete type. 535 /// 536 /// These are subtypes of `func` and supertypes of `nofunc`. 537 ConcreteFunc(FuncType), 538 /// The abstract `nofunc` heap type represents the null function reference. 539 /// 540 /// This is the bottom type for the function references type hierarchy, and 541 /// therefore `nofunc` is a subtype of all function reference types. 542 NoFunc, 543 544 /// The abstract `any` heap type represents all internal Wasm data. 545 /// 546 /// This is the top type of the internal type hierarchy, and is therefore a 547 /// supertype of all internal types (such as `eq`, `i31`, `struct`s, and 548 /// `array`s). 549 Any, 550 /// The abstract `eq` heap type represenets all internal Wasm references 551 /// that can be compared for equality. 552 /// 553 /// This is a subtype of `any` and a supertype of `i31`, `array`, `struct`, 554 /// and `none` heap types. 555 Eq, 556 /// The `i31` heap type represents unboxed 31-bit integers. 557 /// 558 /// This is a subtype of `any` and `eq`, and a supertype of `none`. 559 I31, 560 /// The abstract `array` heap type represents a reference to any kind of 561 /// array. 562 /// 563 /// This is a subtype of `any` and `eq`, and a supertype of all concrete 564 /// array types, as well as a supertype of the abstract `none` heap type. 565 Array, 566 /// A reference to an array of a specific, concrete type. 567 /// 568 /// These are subtypes of the `array` heap type (therefore also a subtype of 569 /// `any` and `eq`) and supertypes of the `none` heap type. 570 ConcreteArray(ArrayType), 571 /// The abstract `struct` heap type represents a reference to any kind of 572 /// struct. 573 /// 574 /// This is a subtype of `any` and `eq`, and a supertype of all concrete 575 /// struct types, as well as a supertype of the abstract `none` heap type. 576 Struct, 577 /// A reference to an struct of a specific, concrete type. 578 /// 579 /// These are subtypes of the `struct` heap type (therefore also a subtype 580 /// of `any` and `eq`) and supertypes of the `none` heap type. 581 ConcreteStruct(StructType), 582 /// The abstract `none` heap type represents the null internal reference. 583 /// 584 /// This is the bottom type for the internal type hierarchy, and therefore 585 /// `none` is a subtype of internal types. 586 None, 587 588 /// The abstract `exn` heap type represents exception references. 589 /// 590 /// This is the top type for the exception type hierarchy, and therefore is 591 /// the common supertype of all exception reference types. 592 Exn, 593 /// The abstract `noexn` heap type represents the null exception reference. 594 /// 595 /// This is the bottom type for the exception type hierarchy, and therefore 596 /// is the common subtype of all exception reference types. 597 NoExn, 598 599 /// The abstract `cont` heap type represents continuation references. 600 /// 601 /// This is the top type for the continuation type hierarchy, and therefore is 602 /// the common supertype of all continuation reference types. 603 Cont, 604 /// The abstract `nocont` heap type represents the null continuation reference. 605 /// 606 /// This is the bottom type for the continuation type hierarchy, and therefore 607 /// is the common subtype of all continuation reference types. 608 NoCont, 609} 610 611impl Display for HeapType { 612 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 613 if self.shared { 614 f.write_str("shared ")?; 615 } 616 match &self.inner { 617 HeapTypeInner::Extern => write!(f, "extern"), 618 HeapTypeInner::NoExtern => write!(f, "noextern"), 619 HeapTypeInner::Func => write!(f, "func"), 620 HeapTypeInner::NoFunc => write!(f, "nofunc"), 621 HeapTypeInner::Any => write!(f, "any"), 622 HeapTypeInner::Eq => write!(f, "eq"), 623 HeapTypeInner::I31 => write!(f, "i31"), 624 HeapTypeInner::Array => write!(f, "array"), 625 HeapTypeInner::Struct => write!(f, "struct"), 626 HeapTypeInner::None => write!(f, "none"), 627 HeapTypeInner::ConcreteFunc(ty) => write!(f, "(concrete func {:?})", ty.type_index()), 628 HeapTypeInner::ConcreteArray(ty) => write!(f, "(concrete array {:?})", ty.type_index()), 629 HeapTypeInner::ConcreteStruct(ty) => { 630 write!(f, "(concrete struct {:?})", ty.type_index()) 631 } 632 HeapTypeInner::Exn => write!(f, "exn"), 633 HeapTypeInner::NoExn => write!(f, "noexn"), 634 HeapTypeInner::Cont => write!(f, "cont"), 635 HeapTypeInner::NoCont => write!(f, "nocont"), 636 } 637 } 638} 639 640impl HeapType { 641 pub const FUNC: Self = HeapType { 642 shared: false, 643 inner: HeapTypeInner::Func, 644 }; 645 pub const NOFUNC: Self = HeapType { 646 shared: false, 647 inner: HeapTypeInner::NoFunc, 648 }; 649 pub const EXTERN: Self = HeapType { 650 shared: false, 651 inner: HeapTypeInner::Extern, 652 }; 653 pub const NOEXTERN: Self = HeapType { 654 shared: false, 655 inner: HeapTypeInner::NoExtern, 656 }; 657 pub const ANY: Self = HeapType { 658 shared: false, 659 inner: HeapTypeInner::Any, 660 }; 661 pub const EQ: Self = HeapType { 662 shared: false, 663 inner: HeapTypeInner::Eq, 664 }; 665 pub const I31: Self = HeapType { 666 shared: false, 667 inner: HeapTypeInner::I31, 668 }; 669 pub const ARRAY: Self = HeapType { 670 shared: false, 671 inner: HeapTypeInner::Array, 672 }; 673 pub const STRUCT: Self = HeapType { 674 shared: false, 675 inner: HeapTypeInner::Struct, 676 }; 677 pub const NONE: Self = HeapType { 678 shared: false, 679 inner: HeapTypeInner::None, 680 }; 681 pub const EXN: Self = HeapType { 682 shared: false, 683 inner: HeapTypeInner::Exn, 684 }; 685 pub const NOEXN: Self = HeapType { 686 shared: false, 687 inner: HeapTypeInner::NoExn, 688 }; 689 pub const CONT: Self = HeapType { 690 shared: false, 691 inner: HeapTypeInner::Cont, 692 }; 693 pub const NOCONT: Self = HeapType { 694 shared: false, 695 inner: HeapTypeInner::NoCont, 696 }; 697 pub const fn concrete_func(f: FuncType) -> HeapType { 698 HeapType { 699 shared: false, 700 inner: HeapTypeInner::ConcreteFunc(f), 701 } 702 } 703 704 /// Is this the abstract `extern` heap type? 705 pub fn is_extern(&self) -> bool { 706 matches!(self.inner, HeapTypeInner::Extern) 707 } 708 709 /// Is this the abstract `func` heap type? 710 pub fn is_func(&self) -> bool { 711 matches!(self.inner, HeapTypeInner::Func) 712 } 713 714 /// Is this the abstract `nofunc` heap type? 715 pub fn is_no_func(&self) -> bool { 716 matches!(self.inner, HeapTypeInner::NoFunc) 717 } 718 719 /// Is this the abstract `any` heap type? 720 pub fn is_any(&self) -> bool { 721 matches!(self.inner, HeapTypeInner::Any) 722 } 723 724 /// Is this the abstract `i31` heap type? 725 pub fn is_i31(&self) -> bool { 726 matches!(self.inner, HeapTypeInner::I31) 727 } 728 729 /// Is this the abstract `none` heap type? 730 pub fn is_none(&self) -> bool { 731 matches!(self.inner, HeapTypeInner::None) 732 } 733 734 /// Is this an abstract type? 735 /// 736 /// Types that are not abstract are concrete, user-defined types. 737 pub fn is_abstract(&self) -> bool { 738 !self.is_concrete() 739 } 740 741 /// Is this a concrete, user-defined heap type? 742 /// 743 /// Types that are not concrete, user-defined types are abstract types. 744 #[inline] 745 pub fn is_concrete(&self) -> bool { 746 matches!( 747 self.inner, 748 HeapTypeInner::ConcreteFunc(_) 749 | HeapTypeInner::ConcreteArray(_) 750 | HeapTypeInner::ConcreteStruct(_) 751 ) 752 } 753 754 /// Is this a concrete, user-defined function type? 755 pub fn is_concrete_func(&self) -> bool { 756 matches!(self.inner, HeapTypeInner::ConcreteFunc(_)) 757 } 758 759 /// Get the underlying concrete, user-defined function type, if any. 760 /// 761 /// Returns `None` if this is not a concrete function type. 762 pub fn as_concrete_func(&self) -> Option<&FuncType> { 763 match &self.inner { 764 HeapTypeInner::ConcreteFunc(f) => Some(f), 765 _ => None, 766 } 767 } 768 769 /// Get the underlying concrete, user-defined type, panicking if this is not 770 /// a concrete function type. 771 pub fn unwrap_concrete_func(&self) -> &FuncType { 772 self.as_concrete_func().unwrap() 773 } 774 775 /// Is this a concrete, user-defined array type? 776 pub fn is_concrete_array(&self) -> bool { 777 matches!(self.inner, HeapTypeInner::ConcreteArray(_)) 778 } 779 780 /// Get the underlying concrete, user-defined array type, if any. 781 /// 782 /// Returns `None` for if this is not a concrete array type. 783 pub fn as_concrete_array(&self) -> Option<&ArrayType> { 784 match &self.inner { 785 HeapTypeInner::ConcreteArray(f) => Some(f), 786 _ => None, 787 } 788 } 789 790 /// Get the underlying concrete, user-defined type, panicking if this is not 791 /// a concrete array type. 792 pub fn unwrap_concrete_array(&self) -> &ArrayType { 793 self.as_concrete_array().unwrap() 794 } 795 796 /// Is this a concrete, user-defined struct type? 797 pub fn is_concrete_struct(&self) -> bool { 798 matches!(self.inner, HeapTypeInner::ConcreteStruct(_)) 799 } 800 801 /// Get the underlying concrete, user-defined struct type, if any. 802 /// 803 /// Returns `None` for if this is not a concrete struct type. 804 pub fn as_concrete_struct(&self) -> Option<&StructType> { 805 match &self.inner { 806 HeapTypeInner::ConcreteStruct(f) => Some(f), 807 _ => None, 808 } 809 } 810 811 /// Get the underlying concrete, user-defined type, panicking if this is not 812 /// a concrete struct type. 813 pub fn unwrap_concrete_struct(&self) -> &StructType { 814 self.as_concrete_struct().unwrap() 815 } 816 817 pub fn is_shared(&self) -> bool { 818 self.shared 819 } 820 821 /// Get the top type of this heap type's type hierarchy. 822 /// 823 /// The returned heap type is a supertype of all types in this heap type's 824 /// type hierarchy. 825 pub fn top(&self) -> HeapType { 826 let inner = match self.inner { 827 HeapTypeInner::Func | HeapTypeInner::ConcreteFunc(_) | HeapTypeInner::NoFunc => { 828 HeapTypeInner::Func 829 } 830 831 HeapTypeInner::Extern | HeapTypeInner::NoExtern => HeapTypeInner::Extern, 832 833 HeapTypeInner::Any 834 | HeapTypeInner::Eq 835 | HeapTypeInner::I31 836 | HeapTypeInner::Array 837 | HeapTypeInner::ConcreteArray(_) 838 | HeapTypeInner::Struct 839 | HeapTypeInner::ConcreteStruct(_) 840 | HeapTypeInner::None => HeapTypeInner::Any, 841 842 HeapTypeInner::Exn | HeapTypeInner::NoExn => HeapTypeInner::Exn, 843 HeapTypeInner::Cont | HeapTypeInner::NoCont => HeapTypeInner::Cont, 844 }; 845 846 HeapType { 847 shared: self.shared, 848 inner, 849 } 850 } 851 852 /// Is this the top type within its type hierarchy? 853 #[inline] 854 pub fn is_top(&self) -> bool { 855 matches!( 856 self.inner, 857 HeapTypeInner::Any 858 | HeapTypeInner::Extern 859 | HeapTypeInner::Func 860 | HeapTypeInner::Exn 861 | HeapTypeInner::Cont 862 ) 863 } 864 865 /// Get the bottom type of this heap type's type hierarchy. 866 /// 867 /// The returned heap type is a subtype of all types in this heap type's 868 /// type hierarchy. 869 pub fn bottom(&self) -> HeapType { 870 let inner = match self.inner { 871 HeapTypeInner::Extern | HeapTypeInner::NoExtern => HeapTypeInner::NoExtern, 872 873 HeapTypeInner::Func | HeapTypeInner::ConcreteFunc(_) | HeapTypeInner::NoFunc => { 874 HeapTypeInner::NoFunc 875 } 876 877 HeapTypeInner::Any 878 | HeapTypeInner::Eq 879 | HeapTypeInner::I31 880 | HeapTypeInner::Array 881 | HeapTypeInner::ConcreteArray(_) 882 | HeapTypeInner::Struct 883 | HeapTypeInner::ConcreteStruct(_) 884 | HeapTypeInner::None => HeapTypeInner::None, 885 886 HeapTypeInner::Exn | HeapTypeInner::NoExn => HeapTypeInner::NoExn, 887 HeapTypeInner::Cont | HeapTypeInner::NoCont => HeapTypeInner::NoCont, 888 }; 889 890 HeapType { 891 shared: self.shared, 892 inner, 893 } 894 } 895 896 /// Is this the bottom type within its type hierarchy? 897 #[inline] 898 pub fn is_bottom(&self) -> bool { 899 matches!( 900 self.inner, 901 HeapTypeInner::None 902 | HeapTypeInner::NoExtern 903 | HeapTypeInner::NoFunc 904 | HeapTypeInner::NoExn 905 | HeapTypeInner::NoCont 906 ) 907 } 908 909 /// Does this heap type match the other heap type? 910 /// 911 /// That is, is this heap type a subtype of the other? 912 /// 913 /// # Panics 914 /// 915 /// Panics if either type is associated with a different engine from the 916 /// other. 917 pub fn matches(&self, other: &HeapType) -> bool { 918 match (&self.inner, &other.inner) { 919 (HeapTypeInner::Extern, HeapTypeInner::Extern) => true, 920 (HeapTypeInner::Extern, _) => false, 921 922 (HeapTypeInner::NoExtern, HeapTypeInner::NoExtern | HeapTypeInner::Extern) => true, 923 (HeapTypeInner::NoExtern, _) => false, 924 925 ( 926 HeapTypeInner::NoFunc, 927 HeapTypeInner::NoFunc | HeapTypeInner::ConcreteFunc(_) | HeapTypeInner::Func, 928 ) => true, 929 (HeapTypeInner::NoFunc, _) => false, 930 931 (HeapTypeInner::ConcreteFunc(_), HeapTypeInner::Func) => true, 932 (HeapTypeInner::ConcreteFunc(a), HeapTypeInner::ConcreteFunc(b)) => { 933 assert!(a.comes_from_same_engine(b.engine())); 934 a.engine() 935 .type_registry() 936 .is_subtype(a.type_index(), b.type_index()) 937 } 938 (HeapTypeInner::ConcreteFunc(_), _) => false, 939 940 (HeapTypeInner::Func, HeapTypeInner::Func) => true, 941 (HeapTypeInner::Func, _) => false, 942 943 ( 944 HeapTypeInner::None, 945 HeapTypeInner::None 946 | HeapTypeInner::ConcreteArray(_) 947 | HeapTypeInner::Array 948 | HeapTypeInner::ConcreteStruct(_) 949 | HeapTypeInner::Struct 950 | HeapTypeInner::I31 951 | HeapTypeInner::Eq 952 | HeapTypeInner::Any, 953 ) => true, 954 (HeapTypeInner::None, _) => false, 955 956 ( 957 HeapTypeInner::ConcreteArray(_), 958 HeapTypeInner::Array | HeapTypeInner::Eq | HeapTypeInner::Any, 959 ) => true, 960 (HeapTypeInner::ConcreteArray(a), HeapTypeInner::ConcreteArray(b)) => { 961 assert!(a.comes_from_same_engine(b.engine())); 962 a.engine() 963 .type_registry() 964 .is_subtype(a.type_index(), b.type_index()) 965 } 966 (HeapTypeInner::ConcreteArray(_), _) => false, 967 968 ( 969 HeapTypeInner::Array, 970 HeapTypeInner::Array | HeapTypeInner::Eq | HeapTypeInner::Any, 971 ) => true, 972 (HeapTypeInner::Array, _) => false, 973 974 ( 975 HeapTypeInner::ConcreteStruct(_), 976 HeapTypeInner::Struct | HeapTypeInner::Eq | HeapTypeInner::Any, 977 ) => true, 978 (HeapTypeInner::ConcreteStruct(a), HeapTypeInner::ConcreteStruct(b)) => { 979 assert!(a.comes_from_same_engine(b.engine())); 980 a.engine() 981 .type_registry() 982 .is_subtype(a.type_index(), b.type_index()) 983 } 984 (HeapTypeInner::ConcreteStruct(_), _) => false, 985 986 ( 987 HeapTypeInner::Struct, 988 HeapTypeInner::Struct | HeapTypeInner::Eq | HeapTypeInner::Any, 989 ) => true, 990 (HeapTypeInner::Struct, _) => false, 991 992 (HeapTypeInner::I31, HeapTypeInner::I31 | HeapTypeInner::Eq | HeapTypeInner::Any) => { 993 true 994 } 995 (HeapTypeInner::I31, _) => false, 996 997 (HeapTypeInner::Eq, HeapTypeInner::Eq | HeapTypeInner::Any) => true, 998 (HeapTypeInner::Eq, _) => false, 999 1000 (HeapTypeInner::Any, HeapTypeInner::Any) => true, 1001 (HeapTypeInner::Any, _) => false, 1002 1003 (HeapTypeInner::Exn, HeapTypeInner::Exn) => true, 1004 (HeapTypeInner::Exn, _) => false, 1005 (HeapTypeInner::NoExn, HeapTypeInner::NoExn | HeapTypeInner::Exn) => true, 1006 (HeapTypeInner::NoExn, _) => false, 1007 1008 (HeapTypeInner::Cont, HeapTypeInner::Cont) => true, 1009 (HeapTypeInner::Cont, _) => false, 1010 // ( 1011 // HeapTypeInner::ConcreteCont(_), 1012 // HeapTypeInner::Cont, 1013 // ) => true, 1014 // (HeapTypeInner::ConcreteCont(_a), HeapTypeInner::ConcreteCont(_b)) => { 1015 // // assert!(a.comes_from_same_engine(b.engine())); 1016 // // a.engine() 1017 // // .type_registry() 1018 // // .is_subtype(a.type_index(), b.type_index()) 1019 // todo!() 1020 // } 1021 // (HeapTypeInner::ConcreteCont(_), _) => false, 1022 (HeapTypeInner::NoCont, HeapTypeInner::NoCont | HeapTypeInner::Cont) => true, 1023 (HeapTypeInner::NoCont, _) => false, 1024 } 1025 } 1026 1027 /// Is heap type `a` precisely equal to heap type `b`? 1028 /// 1029 /// Returns `false` even if `a` is a subtype of `b` or vice versa, if they 1030 /// are not exactly the same heap type. 1031 /// 1032 /// # Panics 1033 /// 1034 /// Panics if either type is associated with a different engine from the 1035 /// other. 1036 pub fn eq(a: &HeapType, b: &HeapType) -> bool { 1037 a.matches(b) && b.matches(a) 1038 } 1039 1040 pub(crate) fn ensure_matches(&self, engine: &Engine, other: &HeapType) -> crate::Result<()> { 1041 if !self.comes_from_same_engine(engine) || !other.comes_from_same_engine(engine) { 1042 bail!("type used with wrong engine"); 1043 } 1044 if self.matches(other) { 1045 Ok(()) 1046 } else { 1047 bail!("type mismatch: expected {other}, found {self}"); 1048 } 1049 } 1050 1051 pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool { 1052 match &self.inner { 1053 HeapTypeInner::Extern 1054 | HeapTypeInner::NoExtern 1055 | HeapTypeInner::Func 1056 | HeapTypeInner::NoFunc 1057 | HeapTypeInner::Any 1058 | HeapTypeInner::Eq 1059 | HeapTypeInner::I31 1060 | HeapTypeInner::Array 1061 | HeapTypeInner::Struct 1062 | HeapTypeInner::None 1063 | HeapTypeInner::Exn 1064 | HeapTypeInner::NoExn 1065 | HeapTypeInner::Cont 1066 | HeapTypeInner::NoCont => true, 1067 HeapTypeInner::ConcreteFunc(ty) => ty.comes_from_same_engine(engine), 1068 HeapTypeInner::ConcreteArray(ty) => ty.comes_from_same_engine(engine), 1069 HeapTypeInner::ConcreteStruct(ty) => ty.comes_from_same_engine(engine), 1070 } 1071 } 1072 1073 pub(crate) fn as_registered_type(&self) -> Option<&RegisteredType> { 1074 match &self.inner { 1075 HeapTypeInner::ConcreteFunc(f) => Some(&f.registered_type), 1076 HeapTypeInner::ConcreteArray(a) => Some(&a.registered_type), 1077 HeapTypeInner::ConcreteStruct(a) => Some(&a.registered_type), 1078 1079 HeapTypeInner::Extern 1080 | HeapTypeInner::NoExtern 1081 | HeapTypeInner::Func 1082 | HeapTypeInner::NoFunc 1083 | HeapTypeInner::Any 1084 | HeapTypeInner::Eq 1085 | HeapTypeInner::I31 1086 | HeapTypeInner::Array 1087 | HeapTypeInner::Struct 1088 | HeapTypeInner::None 1089 | HeapTypeInner::Exn 1090 | HeapTypeInner::NoExn 1091 | HeapTypeInner::Cont 1092 | HeapTypeInner::NoCont => None, 1093 } 1094 } 1095 1096 pub(crate) fn to_wasm_type(&self) -> WasmHeapType { 1097 let inner = match &self.inner { 1098 HeapTypeInner::Extern => WasmHeapTypeInner::Extern, 1099 HeapTypeInner::NoExtern => WasmHeapTypeInner::NoExtern, 1100 HeapTypeInner::Func => WasmHeapTypeInner::Func, 1101 HeapTypeInner::NoFunc => WasmHeapTypeInner::NoFunc, 1102 HeapTypeInner::Any => WasmHeapTypeInner::Any, 1103 HeapTypeInner::Eq => WasmHeapTypeInner::Eq, 1104 HeapTypeInner::I31 => WasmHeapTypeInner::I31, 1105 HeapTypeInner::Array => WasmHeapTypeInner::Array, 1106 HeapTypeInner::Struct => WasmHeapTypeInner::Struct, 1107 HeapTypeInner::None => WasmHeapTypeInner::None, 1108 HeapTypeInner::ConcreteFunc(f) => { 1109 WasmHeapTypeInner::ConcreteFunc(CanonicalizedTypeIndex::Engine(f.type_index())) 1110 } 1111 HeapTypeInner::ConcreteArray(a) => { 1112 WasmHeapTypeInner::ConcreteArray(CanonicalizedTypeIndex::Engine(a.type_index())) 1113 } 1114 HeapTypeInner::ConcreteStruct(a) => { 1115 WasmHeapTypeInner::ConcreteStruct(CanonicalizedTypeIndex::Engine(a.type_index())) 1116 } 1117 HeapTypeInner::Exn => WasmHeapTypeInner::Exn, 1118 HeapTypeInner::NoExn => WasmHeapTypeInner::NoExn, 1119 HeapTypeInner::Cont => WasmHeapTypeInner::Cont, 1120 HeapTypeInner::NoCont => WasmHeapTypeInner::NoCont, 1121 }; 1122 WasmHeapType { 1123 shared: self.shared, 1124 inner, 1125 } 1126 } 1127 1128 pub(crate) fn from_wasm_type(engine: &Engine, ty: &WasmHeapType) -> HeapType { 1129 let inner = match ty.inner { 1130 WasmHeapTypeInner::Extern => HeapTypeInner::Extern, 1131 WasmHeapTypeInner::NoExtern => HeapTypeInner::NoExtern, 1132 WasmHeapTypeInner::Func => HeapTypeInner::Func, 1133 WasmHeapTypeInner::NoFunc => HeapTypeInner::NoFunc, 1134 WasmHeapTypeInner::Any => HeapTypeInner::Any, 1135 WasmHeapTypeInner::Eq => HeapTypeInner::Eq, 1136 WasmHeapTypeInner::I31 => HeapTypeInner::I31, 1137 WasmHeapTypeInner::Array => HeapTypeInner::Array, 1138 WasmHeapTypeInner::Struct => HeapTypeInner::Struct, 1139 WasmHeapTypeInner::None => HeapTypeInner::None, 1140 WasmHeapTypeInner::ConcreteFunc(CanonicalizedTypeIndex::Engine(idx)) => { 1141 HeapTypeInner::ConcreteFunc(FuncType::from_shared_type_index(engine, idx)) 1142 } 1143 WasmHeapTypeInner::ConcreteArray(CanonicalizedTypeIndex::Engine(idx)) => { 1144 HeapTypeInner::ConcreteArray(ArrayType::from_shared_type_index(engine, idx)) 1145 } 1146 WasmHeapTypeInner::ConcreteStruct(CanonicalizedTypeIndex::Engine(idx)) => { 1147 HeapTypeInner::ConcreteStruct(StructType::from_shared_type_index(engine, idx)) 1148 } 1149 1150 WasmHeapTypeInner::ConcreteFunc( 1151 CanonicalizedTypeIndex::Module(_) | CanonicalizedTypeIndex::RecGroup(_), 1152 ) 1153 | WasmHeapTypeInner::ConcreteArray( 1154 CanonicalizedTypeIndex::Module(_) | CanonicalizedTypeIndex::RecGroup(_), 1155 ) 1156 | WasmHeapTypeInner::ConcreteStruct( 1157 CanonicalizedTypeIndex::Module(_) | CanonicalizedTypeIndex::RecGroup(_), 1158 ) => { 1159 panic!( 1160 "HeapTypeInner::from_wasm_type on non-canonicalized-for-runtime-usage heap type" 1161 ) 1162 } 1163 1164 WasmHeapTypeInner::Exn => HeapTypeInner::Exn, 1165 WasmHeapTypeInner::NoExn => HeapTypeInner::NoExn, 1166 1167 WasmHeapTypeInner::Cont => HeapTypeInner::Cont, 1168 WasmHeapTypeInner::ConcreteCont(_) => todo!(), 1169 WasmHeapTypeInner::NoCont => HeapTypeInner::NoCont, 1170 }; 1171 HeapType { 1172 inner, 1173 shared: ty.shared, 1174 } 1175 } 1176} 1177 1178/// A list of all possible types which can be externally referenced from a 1179/// WebAssembly module. 1180/// 1181/// This list can be found in [`ImportType`] or [`ExportType`], so these types 1182/// can either be imported or exported. 1183#[derive(Debug, Clone)] 1184pub enum ExternType { 1185 /// This external type is the type of a WebAssembly function. 1186 Func(FuncType), 1187 /// This external type is the type of a WebAssembly global. 1188 Global(GlobalType), 1189 /// This external type is the type of a WebAssembly table. 1190 Table(TableType), 1191 /// This external type is the type of a WebAssembly memory. 1192 Memory(MemoryType), 1193 /// This external type is the type of a WebAssembly tag. 1194 Tag(TagType), 1195} 1196 1197/// The storage type of a `struct` field or `array` element. 1198/// 1199/// This is either a packed 8- or -16 bit integer, or else it is some unpacked 1200/// Wasm value type. 1201#[derive(Clone, Hash)] 1202pub enum StorageType { 1203 /// `i8`, an 8-bit integer. 1204 I8, 1205 /// `i16`, a 16-bit integer. 1206 I16, 1207 /// A value type. 1208 ValType(ValType), 1209} 1210impl fmt::Display for StorageType { 1211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1212 match self { 1213 StorageType::I8 => write!(f, "i8"), 1214 StorageType::I16 => write!(f, "i16"), 1215 StorageType::ValType(ty) => fmt::Display::fmt(ty, f), 1216 } 1217 } 1218} 1219 1220impl StorageType { 1221 pub(super) fn from_wasm_type(engine: &Engine, ty: &WasmStorageType) -> Self { 1222 match ty { 1223 WasmStorageType::I8 => Self::I8, 1224 WasmStorageType::I16 => Self::I16, 1225 WasmStorageType::Val(ty) => Self::ValType(ValType::from_wasm_type(engine, ty)), 1226 } 1227 } 1228} 1229 1230/// The type of a `struct` field or an `array`'s elements. 1231/// 1232/// This is a pair of both the field's storage type and its mutability 1233/// (i.e. whether the field can be updated or not). 1234#[derive(Clone, Hash)] 1235pub struct FieldType { 1236 mutability: Mutability, 1237 element_type: StorageType, 1238} 1239impl fmt::Display for FieldType { 1240 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1241 if self.mutability.is_var() { 1242 write!(f, "(mut {})", self.element_type) 1243 } else { 1244 fmt::Display::fmt(&self.element_type, f) 1245 } 1246 } 1247} 1248 1249impl FieldType { 1250 /// Construct a new field type from the given parts. 1251 #[inline] 1252 pub fn new(mutability: Mutability, element_type: StorageType) -> Self { 1253 Self { 1254 mutability, 1255 element_type, 1256 } 1257 } 1258 1259 /// Get whether or not this field type is mutable. 1260 #[inline] 1261 pub fn mutability(&self) -> Mutability { 1262 self.mutability 1263 } 1264 1265 /// Get this field type's storage type. 1266 #[inline] 1267 pub fn element_type(&self) -> &StorageType { 1268 &self.element_type 1269 } 1270 1271 pub(super) fn from_wasm_type(engine: &Engine, ty: &WasmFieldType) -> Self { 1272 Self { 1273 mutability: if ty.mutable { 1274 Mutability::Var 1275 } else { 1276 Mutability::Const 1277 }, 1278 element_type: StorageType::from_wasm_type(engine, &ty.element_type), 1279 } 1280 } 1281} 1282 1283/// The type of a WebAssembly struct. 1284/// 1285/// WebAssembly structs are a static, fixed-length, ordered sequence of 1286/// fields. Fields are named by index, not an identifier. Each field is mutable 1287/// or constant and stores unpacked [`Val`][crate::wasm::Val]s or packed 8-/16-bit 1288/// integers. 1289/// 1290/// # Subtyping and Equality 1291/// 1292/// `StructType` does not implement `Eq`, because reference types have a 1293/// subtyping relationship, and so 99.99% of the time you actually want to check 1294/// whether one type matches (i.e. is a subtype of) another type. You can use 1295/// the [`StructType::matches`] method to perform these types of checks. If, 1296/// however, you are in that 0.01% scenario where you need to check precise 1297/// equality between types, you can use the [`StructType::eq`] method. 1298// 1299// TODO: Once we have struct values, update above docs with a reference to the 1300// future `Struct::matches_ty` method 1301#[derive(Debug, Clone, Hash)] 1302pub struct StructType { 1303 registered_type: RegisteredType, 1304} 1305impl fmt::Display for StructType { 1306 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1307 write!(f, "(struct")?; 1308 for field in self.fields() { 1309 write!(f, " (field {field})")?; 1310 } 1311 write!(f, ")")?; 1312 Ok(()) 1313 } 1314} 1315 1316impl StructType { 1317 pub fn fields(&self) -> impl ExactSizeIterator<Item = FieldType> { 1318 let engine = self.engine(); 1319 1320 self.registered_type 1321 .unwrap_struct() 1322 .fields 1323 .iter() 1324 .map(|wasm_ty| FieldType::from_wasm_type(engine, wasm_ty)) 1325 } 1326 1327 pub(super) fn engine(&self) -> &Engine { 1328 self.registered_type.engine() 1329 } 1330 pub(super) fn comes_from_same_engine(&self, other: &Engine) -> bool { 1331 Engine::same(self.engine(), other) 1332 } 1333 pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> StructType { 1334 let ty = engine.type_registry().root(engine, index).expect( 1335 "VMSharedTypeIndex is not registered in the Engine! Wrong \ 1336 engine? Didn't root the index somewhere?", 1337 ); 1338 Self::from_registered_type(ty) 1339 } 1340 pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self { 1341 debug_assert!(registered_type.is_struct()); 1342 Self { registered_type } 1343 } 1344 pub(crate) fn type_index(&self) -> VMSharedTypeIndex { 1345 self.registered_type.index() 1346 } 1347} 1348 1349/// The type of a WebAssembly array. 1350/// 1351/// WebAssembly arrays are dynamically-sized, but not resizable. They contain 1352/// either unpacked [`Val`][crate::Val]s or packed 8-/16-bit integers. 1353/// 1354/// # Subtyping and Equality 1355/// 1356/// `ArrayType` does not implement `Eq`, because reference types have a 1357/// subtyping relationship, and so 99.99% of the time you actually want to check 1358/// whether one type matches (i.e. is a subtype of) another type. You can use 1359/// the [`ArrayType::matches`] method to perform these types of checks. If, 1360/// however, you are in that 0.01% scenario where you need to check precise 1361/// equality between types, you can use the [`ArrayType::eq`] method. 1362// 1363// TODO: Once we have array values, update above docs with a reference to the 1364// future `Array::matches_ty` method 1365#[derive(Debug, Clone, Hash)] 1366pub struct ArrayType { 1367 registered_type: RegisteredType, 1368} 1369impl fmt::Display for ArrayType { 1370 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1371 let field_ty = self.field_type(); 1372 write!(f, "(array (field {field_ty}))")?; 1373 Ok(()) 1374 } 1375} 1376 1377impl ArrayType { 1378 pub fn field_type(&self) -> FieldType { 1379 todo!() 1380 } 1381 pub(crate) fn type_index(&self) -> VMSharedTypeIndex { 1382 self.registered_type.index() 1383 } 1384 pub(super) fn engine(&self) -> &Engine { 1385 self.registered_type.engine() 1386 } 1387 pub(super) fn comes_from_same_engine(&self, other: &Engine) -> bool { 1388 Engine::same(self.engine(), other) 1389 } 1390 pub(crate) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> ArrayType { 1391 let ty = engine.type_registry().root(engine, index).expect( 1392 "VMSharedTypeIndex is not registered in the Engine! Wrong \ 1393 engine? Didn't root the index somewhere?", 1394 ); 1395 Self::from_registered_type(ty) 1396 } 1397 pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self { 1398 debug_assert!(registered_type.is_array()); 1399 Self { registered_type } 1400 } 1401} 1402 1403/// The type of a WebAssembly function. 1404/// 1405/// WebAssembly functions can have 0 or more parameters and results. 1406/// 1407/// # Subtyping and Equality 1408/// 1409/// `FuncType` does not implement `Eq`, because reference types have a subtyping 1410/// relationship, and so 99.99% of the time you actually want to check whether 1411/// one type matches (i.e. is a subtype of) another type. You can use the 1412/// [`FuncType::matches`] and [`Func::matches_ty`][crate::Func::matches_ty] 1413/// methods to perform these types of checks. If, however, you are in that 0.01% 1414/// scenario where you need to check precise equality between types, you can use 1415/// the [`FuncType::eq`] method. 1416#[derive(Debug, Clone, Hash)] 1417pub struct FuncType { 1418 registered_type: RegisteredType, 1419} 1420impl Display for FuncType { 1421 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1422 write!(f, "(type (func")?; 1423 if self.params().len() > 0 { 1424 write!(f, " (param")?; 1425 for p in self.params() { 1426 write!(f, " {p}")?; 1427 } 1428 write!(f, ")")?; 1429 } 1430 if self.results().len() > 0 { 1431 write!(f, " (result")?; 1432 for r in self.results() { 1433 write!(f, " {r}")?; 1434 } 1435 write!(f, ")")?; 1436 } 1437 write!(f, "))") 1438 } 1439} 1440 1441impl FuncType { 1442 /// Creates a new function type from the given parameters and results. 1443 /// 1444 /// The function type returned will represent a function which takes 1445 /// `params` as arguments and returns `results` when it is finished. 1446 /// 1447 /// The resulting function type will be final and without a supertype. 1448 /// 1449 /// # Panics 1450 /// 1451 /// Panics if any parameter or value type is not associated with the given 1452 /// engine. 1453 pub fn new( 1454 engine: &Engine, 1455 params: impl IntoIterator<Item = ValType>, 1456 results: impl IntoIterator<Item = ValType>, 1457 ) -> Self { 1458 Self::with_finality_and_supertype(engine, Finality::Final, None, params, results) 1459 .expect("cannot fail without a supertype") 1460 } 1461 1462 /// Create a new function type with the given finality, supertype, parameter 1463 /// types, and result types. 1464 /// 1465 /// Returns an error if the supertype is final, or if this function type 1466 /// does not match the supertype. 1467 /// 1468 /// # Panics 1469 /// 1470 /// Panics if any parameter or value type is not associated with the given 1471 /// engine. 1472 pub fn with_finality_and_supertype( 1473 engine: &Engine, 1474 finality: Finality, 1475 supertype: Option<&Self>, 1476 params: impl IntoIterator<Item = ValType>, 1477 results: impl IntoIterator<Item = ValType>, 1478 ) -> crate::Result<Self> { 1479 let params = params.into_iter(); 1480 let results = results.into_iter(); 1481 1482 let mut wasm_params = Vec::with_capacity({ 1483 let size_hint = params.size_hint(); 1484 let cap = size_hint.1.unwrap_or(size_hint.0); 1485 // Only reserve space if we have a supertype, as that is the only time 1486 // that this vec is used. 1487 usize::from(supertype.is_some()) * cap 1488 }); 1489 1490 let mut wasm_results = Vec::with_capacity({ 1491 let size_hint = results.size_hint(); 1492 let cap = size_hint.1.unwrap_or(size_hint.0); 1493 // Same as above. 1494 usize::from(supertype.is_some()) * cap 1495 }); 1496 1497 // Keep any of our parameters' and results' `RegisteredType`s alive 1498 // across `Self::from_wasm_func_type`. If one of our given `ValType`s is 1499 // the only thing keeping a type in the registry, we don't want to 1500 // unregister it when we convert the `ValType` into a `WasmValType` just 1501 // before we register our new `WasmFuncType` that will reference it. 1502 let mut registrations = smallvec::SmallVec::<[_; 4]>::new(); 1503 1504 let mut to_wasm_type = |ty: ValType, vec: &mut Vec<_>| { 1505 assert!(ty.comes_from_same_engine(engine)); 1506 1507 if supertype.is_some() { 1508 vec.push(ty.clone()); 1509 } 1510 1511 if let Some(r) = ty.as_ref() 1512 && let Some(r) = r.heap_type().as_registered_type() 1513 { 1514 registrations.push(r.clone()); 1515 } 1516 1517 ty.to_wasm_type() 1518 }; 1519 1520 let wasm_func_ty = WasmFuncType { 1521 params: params.map(|p| to_wasm_type(p, &mut wasm_params)).collect(), 1522 results: results 1523 .map(|r| to_wasm_type(r, &mut wasm_results)) 1524 .collect(), 1525 }; 1526 1527 if let Some(supertype) = supertype { 1528 assert!(supertype.comes_from_same_engine(engine)); 1529 ensure!( 1530 supertype.finality().is_non_final(), 1531 "cannot create a subtype of a final supertype" 1532 ); 1533 ensure!( 1534 Self::matches_impl( 1535 wasm_params.iter().cloned(), 1536 supertype.params(), 1537 wasm_results.iter().cloned(), 1538 supertype.results() 1539 ), 1540 "function type must match its supertype: found (func{params}{results}), expected \ 1541 {supertype}", 1542 params = if wasm_params.is_empty() { 1543 String::new() 1544 } else { 1545 let mut s = " (params".to_string(); 1546 for p in &wasm_params { 1547 write!(&mut s, " {p}").unwrap(); 1548 } 1549 s.push(')'); 1550 s 1551 }, 1552 results = if wasm_results.is_empty() { 1553 String::new() 1554 } else { 1555 let mut s = " (results".to_string(); 1556 for r in &wasm_results { 1557 write!(&mut s, " {r}").unwrap(); 1558 } 1559 s.push(')'); 1560 s 1561 }, 1562 ); 1563 } 1564 1565 Ok(Self::from_wasm_func_type( 1566 engine, 1567 finality.is_final(), 1568 supertype.map(|ty| ty.type_index().into()), 1569 wasm_func_ty, 1570 )) 1571 } 1572 1573 pub fn param(&self, i: usize) -> Option<ValType> { 1574 let engine = self.engine(); 1575 1576 self.registered_type 1577 .unwrap_func() 1578 .params 1579 .get(i) 1580 .map(|ty| ValType::from_wasm_type(engine, ty)) 1581 } 1582 1583 pub fn params(&self) -> impl ExactSizeIterator<Item = ValType> + '_ { 1584 let engine = self.engine(); 1585 1586 self.registered_type 1587 .unwrap_func() 1588 .params 1589 .iter() 1590 .map(|ty| ValType::from_wasm_type(engine, ty)) 1591 } 1592 1593 pub fn result(&self, i: usize) -> Option<ValType> { 1594 let engine = self.engine(); 1595 self.registered_type 1596 .unwrap_func() 1597 .results 1598 .get(i) 1599 .map(|ty| ValType::from_wasm_type(engine, ty)) 1600 } 1601 1602 pub fn results(&self) -> impl ExactSizeIterator<Item = ValType> + '_ { 1603 let engine = self.engine(); 1604 1605 self.registered_type 1606 .unwrap_func() 1607 .results 1608 .iter() 1609 .map(|ty| ValType::from_wasm_type(engine, ty)) 1610 } 1611 1612 /// Get the finality of this function type. 1613 pub fn finality(&self) -> Finality { 1614 if self.registered_type.is_final { 1615 Finality::Final 1616 } else { 1617 Finality::NonFinal 1618 } 1619 } 1620 1621 /// Get the supertype of this function type, if any. 1622 pub fn supertype(&self) -> Option<Self> { 1623 self.registered_type 1624 .supertype 1625 .map(|ty| Self::from_shared_type_index(self.engine(), ty.unwrap_engine_type_index())) 1626 } 1627 1628 pub(super) fn type_index(&self) -> VMSharedTypeIndex { 1629 self.registered_type.index() 1630 } 1631 1632 pub(super) fn engine(&self) -> &Engine { 1633 self.registered_type.engine() 1634 } 1635 1636 /// Does this function type match the other function type? 1637 /// 1638 /// That is, is this function type a subtype of the other function type? 1639 /// 1640 /// # Panics 1641 /// 1642 /// Panics if either type is associated with a different engine from the 1643 /// other. 1644 pub fn matches(&self, other: &FuncType) -> bool { 1645 assert!(self.comes_from_same_engine(other.engine())); 1646 1647 // Avoid matching on structure for subtyping checks when we have 1648 // precisely the same type. 1649 if self.type_index() == other.type_index() { 1650 return true; 1651 } 1652 1653 Self::matches_impl( 1654 self.params(), 1655 other.params(), 1656 self.results(), 1657 other.results(), 1658 ) 1659 } 1660 1661 fn matches_impl( 1662 a_params: impl ExactSizeIterator<Item = ValType>, 1663 b_params: impl ExactSizeIterator<Item = ValType>, 1664 a_results: impl ExactSizeIterator<Item = ValType>, 1665 b_results: impl ExactSizeIterator<Item = ValType>, 1666 ) -> bool { 1667 a_params.len() == b_params.len() 1668 && a_results.len() == b_results.len() 1669 // Params are contravariant and results are covariant. For more 1670 // details and a refresher on variance, read 1671 // https://github.com/bytecodealliance/wasm-tools/blob/f1d89a4/crates/wasmparser/src/readers/core/types/matches.rs#L137-L174 1672 && a_params 1673 .zip(b_params) 1674 .all(|(a, b)| b.matches(&a)) 1675 && a_results 1676 .zip(b_results) 1677 .all(|(a, b)| a.matches(&b)) 1678 } 1679 1680 pub(super) fn comes_from_same_engine(&self, other: &Engine) -> bool { 1681 Engine::same(self.engine(), other) 1682 } 1683 pub(super) fn from_shared_type_index(engine: &Engine, index: VMSharedTypeIndex) -> FuncType { 1684 let ty = engine.type_registry().root(engine, index).expect( 1685 "VMSharedTypeIndex is not registered in the Engine! Wrong \ 1686 engine? Didn't root the index somewhere?", 1687 ); 1688 Self::from_registered_type(ty) 1689 } 1690 pub(super) fn from_registered_type(registered_type: RegisteredType) -> Self { 1691 debug_assert!(registered_type.is_func()); 1692 Self { registered_type } 1693 } 1694 pub(super) fn into_registered_type(self) -> RegisteredType { 1695 self.registered_type 1696 } 1697 1698 pub(super) fn from_wasm_func_type( 1699 engine: &Engine, 1700 is_final: bool, 1701 supertype: Option<CanonicalizedTypeIndex>, 1702 ty: WasmFuncType, 1703 ) -> Self { 1704 let registered_type = engine.type_registry().register_type( 1705 engine, 1706 WasmSubType { 1707 is_final, 1708 supertype, 1709 composite_type: WasmCompositeType { 1710 shared: false, 1711 inner: WasmCompositeTypeInner::Func(ty), 1712 }, 1713 }, 1714 ); 1715 1716 Self { registered_type } 1717 } 1718} 1719 1720/// A descriptor for a table in a WebAssembly module. 1721/// 1722/// Tables are contiguous chunks of a specific element, typically a `funcref` or 1723/// an `externref`. The most common use for tables is a function table through 1724/// which `call_indirect` can invoke other functions. 1725#[derive(Debug, Clone, Hash)] 1726pub struct TableType { 1727 // Keep a `wasmtime::RefType` so that `TableType::element` doesn't need to 1728 // take an `&Engine`. 1729 element: RefType, 1730 ty: Table, 1731} 1732 1733impl TableType { 1734 /// Returns the element value type of this table. 1735 pub fn element(&self) -> &RefType { 1736 &self.element 1737 } 1738 1739 /// Returns minimum number of elements this table must have 1740 pub fn minimum(&self) -> u64 { 1741 self.ty.limits.min 1742 } 1743 1744 /// Returns the optionally-specified maximum number of elements this table 1745 /// can have. 1746 /// 1747 /// If this returns `None` then the table is not limited in size. 1748 pub fn maximum(&self) -> Option<u64> { 1749 self.ty.limits.max 1750 } 1751 1752 pub(super) fn to_wasm_table(&self) -> &Table { 1753 &self.ty 1754 } 1755 1756 pub(super) fn from_wasm_table(engine: &Engine, table: &Table) -> Self { 1757 let element = RefType::from_wasm_type(engine, &table.element_type); 1758 1759 Self { 1760 element, 1761 ty: table.clone(), 1762 } 1763 } 1764} 1765 1766/// A descriptor for a WebAssembly memory type. 1767/// 1768/// Memories are described in units of pages (64KB) and represent contiguous 1769/// chunks of addressable memory. 1770#[derive(Debug, Clone, Hash)] 1771pub struct MemoryType { 1772 ty: Memory, 1773} 1774 1775impl MemoryType { 1776 pub(super) fn from_wasm_memory(memory: &Memory) -> Self { 1777 Self { ty: memory.clone() } 1778 } 1779} 1780 1781/// A WebAssembly global descriptor. 1782/// 1783/// This type describes an instance of a global in a WebAssembly module. Globals 1784/// are local to an [`Instance`](crate::wasm::Instance) and are either immutable or 1785/// mutable. 1786#[derive(Debug, Clone, Hash)] 1787pub struct GlobalType { 1788 content: ValType, 1789 mutability: Mutability, 1790} 1791 1792impl GlobalType { 1793 pub fn content(&self) -> &ValType { 1794 &self.content 1795 } 1796 1797 pub fn mutability(&self) -> Mutability { 1798 self.mutability 1799 } 1800 1801 pub(super) fn to_wasm_global(&self) -> Global { 1802 Global { 1803 content_type: self.content.to_wasm_type(), 1804 mutable: self.mutability == Mutability::Const, 1805 shared: false, 1806 } 1807 } 1808 1809 pub(super) fn from_wasm_global(engine: &Engine, ty: &Global) -> Self { 1810 let content = ValType::from_wasm_type(engine, &ty.content_type); 1811 Self { 1812 content, 1813 mutability: if ty.mutable { 1814 Mutability::Var 1815 } else { 1816 Mutability::Const 1817 }, 1818 } 1819 } 1820} 1821 1822/// A descriptor for a tag in a WebAssembly module. 1823/// 1824/// This type describes an instance of a tag in a WebAssembly 1825/// module. Tags are local to an [`Instance`](crate::wasm::Instance). 1826#[derive(Debug, Clone, Hash)] 1827pub struct TagType { 1828 ty: FuncType, 1829} 1830 1831impl TagType { 1832 pub(super) fn from_wasm_tag(engine: &Engine, ty: Tag) -> Self { 1833 let ty = FuncType::from_shared_type_index(engine, ty.signature.unwrap_engine_type_index()); 1834 1835 Self { ty } 1836 } 1837} 1838 1839/// A descriptor for an imported value into a wasm module. 1840/// 1841/// This type is primarily accessed from the 1842/// [`Module::imports`](crate::wasm::Module::imports) API. Each [`ImportType`] 1843/// describes an import into the wasm module with the module/name that it's 1844/// imported from as well as the type of item that's being imported. 1845#[derive(Clone)] 1846pub struct ImportType<'module> { 1847 /// The module of the import. 1848 module: &'module str, 1849 1850 /// The field of the import. 1851 name: &'module str, 1852 1853 /// The type of the import. 1854 ty: EntityType, 1855 types: &'module ModuleTypes, 1856 engine: &'module Engine, 1857} 1858 1859impl fmt::Debug for ImportType<'_> { 1860 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1861 f.debug_struct("ImportType") 1862 .field("module", &self.module) 1863 .field("name", &self.name) 1864 .field("ty", &self.ty) 1865 .finish() 1866 } 1867} 1868 1869/// A descriptor for an exported WebAssembly value. 1870/// 1871/// This type is primarily accessed from the 1872/// [`Module::exports`](crate::wasm::Module::exports) accessor and describes what 1873/// names are exported from a wasm module and the type of the item that is 1874/// exported. 1875#[derive(Clone)] 1876pub struct ExportType<'module> { 1877 /// The name of the export. 1878 name: &'module str, 1879 1880 /// The type of the export. 1881 ty: EntityType, 1882 types: &'module ModuleTypes, 1883 engine: &'module Engine, 1884} 1885 1886impl fmt::Debug for ExportType<'_> { 1887 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1888 f.debug_struct("ExportType") 1889 .field("name", &self.name) 1890 .field("ty", &self.ty) 1891 .finish() 1892 } 1893}