| 1 | //! Types relating to type information provided by validation. |
| 2 | |
| 3 | use super::core::Module; |
| 4 | #[cfg (feature = "component-model" )] |
| 5 | use crate::validator::component::ComponentState; |
| 6 | #[cfg (feature = "component-model" )] |
| 7 | use crate::validator::component_types::{ComponentTypeAlloc, ComponentTypeList}; |
| 8 | use crate::{collections::map::Entry, AbstractHeapType}; |
| 9 | use crate::{prelude::*, CompositeInnerType}; |
| 10 | use crate::{ |
| 11 | Export, ExternalKind, GlobalType, Import, Matches, MemoryType, PackedIndex, RecGroup, RefType, |
| 12 | Result, SubType, TableType, TypeRef, UnpackedIndex, ValType, WithRecGroup, |
| 13 | }; |
| 14 | use crate::{FuncType, HeapType, ValidatorId}; |
| 15 | use alloc::sync::Arc; |
| 16 | use core::ops::{Deref, DerefMut, Index, Range}; |
| 17 | use core::{hash::Hash, mem}; |
| 18 | |
| 19 | /// A trait shared by all type identifiers. |
| 20 | /// |
| 21 | /// Any id that can be used to get a type from a `Types`. |
| 22 | // |
| 23 | // Or, internally, from a `TypeList`. |
| 24 | pub trait TypeIdentifier: core::fmt::Debug + Copy + Eq + Sized + 'static { |
| 25 | /// The data pointed to by this type of id. |
| 26 | type Data: TypeData<Id = Self>; |
| 27 | |
| 28 | /// Create a type id from an index. |
| 29 | #[doc (hidden)] |
| 30 | fn from_index(index: u32) -> Self; |
| 31 | |
| 32 | /// Get a shared reference to the list where this id's type data is stored |
| 33 | /// within. |
| 34 | #[doc (hidden)] |
| 35 | fn list(types: &TypeList) -> &SnapshotList<Self::Data>; |
| 36 | |
| 37 | /// Get an exclusive reference to the list where this id's type data is |
| 38 | /// stored within. |
| 39 | #[doc (hidden)] |
| 40 | fn list_mut(types: &mut TypeList) -> &mut SnapshotList<Self::Data>; |
| 41 | |
| 42 | /// The raw index of this id. |
| 43 | #[doc (hidden)] |
| 44 | fn index(&self) -> usize; |
| 45 | } |
| 46 | |
| 47 | /// A trait shared by all types within a `Types`. |
| 48 | /// |
| 49 | /// This is the data that can be retreived by indexing with the associated |
| 50 | /// [`TypeIdentifier`]. |
| 51 | pub trait TypeData: core::fmt::Debug { |
| 52 | /// The identifier for this type data. |
| 53 | type Id: TypeIdentifier<Data = Self>; |
| 54 | |
| 55 | /// Get the info for this type. |
| 56 | #[doc (hidden)] |
| 57 | fn type_info(&self, types: &TypeList) -> TypeInfo; |
| 58 | } |
| 59 | |
| 60 | macro_rules! define_type_id { |
| 61 | ($name:ident, $data:ty, $($list:ident).*, $type_str:expr) => { |
| 62 | #[doc = "Represents a unique identifier for a " ] |
| 63 | #[doc = $type_str] |
| 64 | #[doc = " type known to a [`crate::Validator`]." ] |
| 65 | #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| 66 | #[repr(C)] // Use fixed field layout to ensure minimal size. |
| 67 | pub struct $name { |
| 68 | /// The index into the associated list of types. |
| 69 | index: u32, |
| 70 | } |
| 71 | |
| 72 | impl TypeIdentifier for $name { |
| 73 | type Data = $data; |
| 74 | |
| 75 | fn from_index(index: u32) -> Self { |
| 76 | $name { index } |
| 77 | } |
| 78 | |
| 79 | fn list(types: &TypeList) -> &SnapshotList<Self::Data> { |
| 80 | &types.$($list).* |
| 81 | } |
| 82 | |
| 83 | fn list_mut(types: &mut TypeList) -> &mut SnapshotList<Self::Data> { |
| 84 | &mut types.$($list).* |
| 85 | } |
| 86 | |
| 87 | fn index(&self) -> usize { |
| 88 | usize::try_from(self.index).unwrap() |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | |
| 93 | // The size of type IDs was seen to have a large-ish impact in #844, so |
| 94 | // this assert ensures that it stays relatively small. |
| 95 | const _: () = { |
| 96 | assert!(core::mem::size_of::<$name>() <= 4); |
| 97 | }; |
| 98 | }; |
| 99 | } |
| 100 | pub(crate) use define_type_id; |
| 101 | |
| 102 | /// Represents a unique identifier for a core type type known to a |
| 103 | /// [`crate::Validator`]. |
| 104 | #[derive (Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| 105 | #[repr (C)] |
| 106 | pub struct CoreTypeId { |
| 107 | index: u32, |
| 108 | } |
| 109 | |
| 110 | #[test ] |
| 111 | fn assert_core_type_id_small() { |
| 112 | assert!(core::mem::size_of::<CoreTypeId>() <= 4); |
| 113 | } |
| 114 | |
| 115 | impl TypeIdentifier for CoreTypeId { |
| 116 | type Data = SubType; |
| 117 | |
| 118 | fn from_index(index: u32) -> Self { |
| 119 | CoreTypeId { index } |
| 120 | } |
| 121 | |
| 122 | fn list(types: &TypeList) -> &SnapshotList<Self::Data> { |
| 123 | &types.core_types |
| 124 | } |
| 125 | |
| 126 | fn list_mut(types: &mut TypeList) -> &mut SnapshotList<Self::Data> { |
| 127 | &mut types.core_types |
| 128 | } |
| 129 | |
| 130 | fn index(&self) -> usize { |
| 131 | usize::try_from(self.index).unwrap() |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | impl TypeData for SubType { |
| 136 | type Id = CoreTypeId; |
| 137 | |
| 138 | fn type_info(&self, _types: &TypeList) -> TypeInfo { |
| 139 | // TODO(#1036): calculate actual size for func, array, struct. |
| 140 | let size: u32 = 1 + match &self.composite_type.inner { |
| 141 | CompositeInnerType::Func(ty: &FuncType) => 1 + (ty.params().len() + ty.results().len()) as u32, |
| 142 | CompositeInnerType::Array(_) => 2, |
| 143 | CompositeInnerType::Struct(ty: &StructType) => 1 + 2 * ty.fields.len() as u32, |
| 144 | CompositeInnerType::Cont(_) => 1, |
| 145 | }; |
| 146 | TypeInfo::core(size) |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | define_type_id!( |
| 151 | RecGroupId, |
| 152 | Range<CoreTypeId>, |
| 153 | rec_group_elements, |
| 154 | "recursion group" |
| 155 | ); |
| 156 | |
| 157 | impl TypeData for Range<CoreTypeId> { |
| 158 | type Id = RecGroupId; |
| 159 | |
| 160 | fn type_info(&self, _types: &TypeList) -> TypeInfo { |
| 161 | let size: usize = self.end.index() - self.start.index(); |
| 162 | TypeInfo::core(size:u32::try_from(size).unwrap()) |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | /// Metadata about a type and its transitive structure. |
| 167 | /// |
| 168 | /// Currently contains two properties: |
| 169 | /// |
| 170 | /// * The "size" of a type - a proxy to the recursive size of a type if |
| 171 | /// everything in the type were unique (e.g. no shared references). Not an |
| 172 | /// approximation of runtime size, but instead of type-complexity size if |
| 173 | /// someone were to visit each element of the type individually. For example |
| 174 | /// `u32` has size 1 and `(list u32)` has size 2 (roughly). Used to prevent |
| 175 | /// massive trees of types. |
| 176 | /// |
| 177 | /// * Whether or not a type contains a "borrow" transitively inside of it. For |
| 178 | /// example `(borrow $t)` and `(list (borrow $t))` both contain borrows, but |
| 179 | /// `(list u32)` does not. Used to validate that component function results do |
| 180 | /// not contain borrows. |
| 181 | /// |
| 182 | /// Currently this is represented as a compact 32-bit integer to ensure that |
| 183 | /// `TypeId`, which this is stored in, remains relatively small. The maximum |
| 184 | /// type size allowed in wasmparser is 1M at this time which is 20 bits of |
| 185 | /// information, and then one more bit is used for whether or not a borrow is |
| 186 | /// used. Currently this uses the low 24 bits for the type size and the MSB for |
| 187 | /// the borrow bit. |
| 188 | #[derive (Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| 189 | // Only public because it shows up in a public trait's `doc(hidden)` method. |
| 190 | #[doc (hidden)] |
| 191 | pub struct TypeInfo(u32); |
| 192 | |
| 193 | impl TypeInfo { |
| 194 | /// Creates a new blank set of type information. |
| 195 | /// |
| 196 | /// Defaults to size 1 to ensure that this consumes space in the final type |
| 197 | /// structure. |
| 198 | pub(crate) fn new() -> TypeInfo { |
| 199 | TypeInfo::_new(1, false) |
| 200 | } |
| 201 | |
| 202 | /// Creates a new blank set of information about a leaf "borrow" type which |
| 203 | /// has size 1. |
| 204 | #[cfg (feature = "component-model" )] |
| 205 | pub(crate) fn borrow() -> TypeInfo { |
| 206 | TypeInfo::_new(1, true) |
| 207 | } |
| 208 | |
| 209 | /// Creates type information corresponding to a core type of the `size` |
| 210 | /// specified, meaning no borrows are contained within. |
| 211 | pub(crate) fn core(size: u32) -> TypeInfo { |
| 212 | TypeInfo::_new(size, false) |
| 213 | } |
| 214 | |
| 215 | fn _new(size: u32, contains_borrow: bool) -> TypeInfo { |
| 216 | assert!(size < (1 << 24)); |
| 217 | TypeInfo(size | ((contains_borrow as u32) << 31)) |
| 218 | } |
| 219 | |
| 220 | /// Combines another set of type information into this one, for example if |
| 221 | /// this is a record which has `other` as a field. |
| 222 | /// |
| 223 | /// Updates the size of `self` and whether or not this type contains a |
| 224 | /// borrow based on whether `other` contains a borrow. |
| 225 | /// |
| 226 | /// Returns an error if the type size would exceed this crate's static limit |
| 227 | /// of a type size. |
| 228 | #[cfg (feature = "component-model" )] |
| 229 | pub(crate) fn combine(&mut self, other: TypeInfo, offset: usize) -> Result<()> { |
| 230 | *self = TypeInfo::_new( |
| 231 | super::combine_type_sizes(self.size(), other.size(), offset)?, |
| 232 | self.contains_borrow() || other.contains_borrow(), |
| 233 | ); |
| 234 | Ok(()) |
| 235 | } |
| 236 | |
| 237 | pub(crate) fn size(&self) -> u32 { |
| 238 | self.0 & 0xffffff |
| 239 | } |
| 240 | |
| 241 | #[cfg (feature = "component-model" )] |
| 242 | pub(crate) fn contains_borrow(&self) -> bool { |
| 243 | (self.0 >> 31) != 0 |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | /// The entity type for imports and exports of a module. |
| 248 | #[derive (Debug, Clone, Copy)] |
| 249 | pub enum EntityType { |
| 250 | /// The entity is a function. |
| 251 | Func(CoreTypeId), |
| 252 | /// The entity is a table. |
| 253 | Table(TableType), |
| 254 | /// The entity is a memory. |
| 255 | Memory(MemoryType), |
| 256 | /// The entity is a global. |
| 257 | Global(GlobalType), |
| 258 | /// The entity is a tag. |
| 259 | Tag(CoreTypeId), |
| 260 | } |
| 261 | |
| 262 | impl EntityType { |
| 263 | #[cfg (feature = "component-model" )] |
| 264 | pub(crate) fn desc(&self) -> &'static str { |
| 265 | match self { |
| 266 | Self::Func(_) => "func" , |
| 267 | Self::Table(_) => "table" , |
| 268 | Self::Memory(_) => "memory" , |
| 269 | Self::Global(_) => "global" , |
| 270 | Self::Tag(_) => "tag" , |
| 271 | } |
| 272 | } |
| 273 | |
| 274 | pub(crate) fn info(&self, types: &TypeList) -> TypeInfo { |
| 275 | match self { |
| 276 | Self::Func(id: &CoreTypeId) | Self::Tag(id: &CoreTypeId) => types[*id].type_info(types), |
| 277 | Self::Table(_) | Self::Memory(_) | Self::Global(_) => TypeInfo::new(), |
| 278 | } |
| 279 | } |
| 280 | } |
| 281 | |
| 282 | #[allow (clippy::large_enum_variant)] |
| 283 | pub(super) enum TypesKind { |
| 284 | Module(Arc<Module>), |
| 285 | #[cfg (feature = "component-model" )] |
| 286 | Component(ComponentState), |
| 287 | } |
| 288 | |
| 289 | /// Represents the types known to a [`crate::Validator`] once validation has completed. |
| 290 | /// |
| 291 | /// The type information is returned via the [`crate::Validator::end`] method. |
| 292 | pub struct Types { |
| 293 | id: ValidatorId, |
| 294 | pub(super) list: TypeList, |
| 295 | pub(super) kind: TypesKind, |
| 296 | } |
| 297 | |
| 298 | #[derive (Clone, Copy)] |
| 299 | pub(super) enum TypesRefKind<'a> { |
| 300 | Module(&'a Module), |
| 301 | #[cfg (feature = "component-model" )] |
| 302 | Component(&'a ComponentState), |
| 303 | } |
| 304 | |
| 305 | /// Represents the types known to a [`crate::Validator`] during validation. |
| 306 | /// |
| 307 | /// Retrieved via the [`crate::Validator::types`] method. |
| 308 | #[derive (Clone, Copy)] |
| 309 | pub struct TypesRef<'a> { |
| 310 | id: ValidatorId, |
| 311 | pub(super) list: &'a TypeList, |
| 312 | pub(super) kind: TypesRefKind<'a>, |
| 313 | } |
| 314 | |
| 315 | impl<'a> TypesRef<'a> { |
| 316 | pub(crate) fn from_module(id: ValidatorId, types: &'a TypeList, module: &'a Module) -> Self { |
| 317 | Self { |
| 318 | id, |
| 319 | list: types, |
| 320 | kind: TypesRefKind::Module(module), |
| 321 | } |
| 322 | } |
| 323 | |
| 324 | #[cfg (feature = "component-model" )] |
| 325 | pub(crate) fn from_component( |
| 326 | id: ValidatorId, |
| 327 | types: &'a TypeList, |
| 328 | component: &'a ComponentState, |
| 329 | ) -> Self { |
| 330 | Self { |
| 331 | id, |
| 332 | list: types, |
| 333 | kind: TypesRefKind::Component(component), |
| 334 | } |
| 335 | } |
| 336 | |
| 337 | /// Get the id of the validator that these types are associated with. |
| 338 | #[inline ] |
| 339 | pub fn id(&self) -> ValidatorId { |
| 340 | self.id |
| 341 | } |
| 342 | |
| 343 | /// Gets a type based on its type id. |
| 344 | /// |
| 345 | /// Returns `None` if the type id is unknown. |
| 346 | pub fn get<T>(&self, id: T) -> Option<&'a T::Data> |
| 347 | where |
| 348 | T: TypeIdentifier, |
| 349 | { |
| 350 | self.list.get(id) |
| 351 | } |
| 352 | |
| 353 | /// Get the id of the rec group that the given type id was defined within. |
| 354 | pub fn rec_group_id_of(&self, id: CoreTypeId) -> RecGroupId { |
| 355 | self.list.rec_group_id_of(id) |
| 356 | } |
| 357 | |
| 358 | /// Get the types within a rec group. |
| 359 | pub fn rec_group_elements(&self, id: RecGroupId) -> impl ExactSizeIterator<Item = CoreTypeId> { |
| 360 | let range = &self.list.rec_group_elements[id]; |
| 361 | (range.start.index..range.end.index).map(|index| CoreTypeId { index }) |
| 362 | } |
| 363 | |
| 364 | /// Get the super type of the given type id, if any. |
| 365 | pub fn supertype_of(&self, id: CoreTypeId) -> Option<CoreTypeId> { |
| 366 | self.list.supertype_of(id) |
| 367 | } |
| 368 | |
| 369 | /// Gets a core WebAssembly type id from a type index. |
| 370 | /// |
| 371 | /// Note that this is not to be confused with |
| 372 | /// [`TypesRef::component_type_at`] which gets a component type from its |
| 373 | /// index, nor [`TypesRef::core_type_at_in_component`] which is for |
| 374 | /// learning about core types in components. |
| 375 | /// |
| 376 | /// # Panics |
| 377 | /// |
| 378 | /// This will panic if the `index` provided is out of bounds. |
| 379 | pub fn core_type_at_in_module(&self, index: u32) -> CoreTypeId { |
| 380 | match &self.kind { |
| 381 | TypesRefKind::Module(module) => module.types[index as usize].into(), |
| 382 | #[cfg (feature = "component-model" )] |
| 383 | TypesRefKind::Component(_) => panic!("use `core_type_at_in_component` instead" ), |
| 384 | } |
| 385 | } |
| 386 | |
| 387 | /// Returns the number of core types defined so far. |
| 388 | /// |
| 389 | /// Note that this is only for core modules, for components you should use |
| 390 | /// [`TypesRef::core_type_count_in_component`] instead. |
| 391 | pub fn core_type_count_in_module(&self) -> u32 { |
| 392 | match &self.kind { |
| 393 | TypesRefKind::Module(module) => module.types.len() as u32, |
| 394 | #[cfg (feature = "component-model" )] |
| 395 | TypesRefKind::Component(_) => 0, |
| 396 | } |
| 397 | } |
| 398 | |
| 399 | /// Gets the type of a table at the given table index. |
| 400 | /// |
| 401 | /// # Panics |
| 402 | /// |
| 403 | /// This will panic if the `index` provided is out of bounds. |
| 404 | pub fn table_at(&self, index: u32) -> TableType { |
| 405 | let tables = match &self.kind { |
| 406 | TypesRefKind::Module(module) => &module.tables, |
| 407 | #[cfg (feature = "component-model" )] |
| 408 | TypesRefKind::Component(component) => &component.core_tables, |
| 409 | }; |
| 410 | tables[index as usize] |
| 411 | } |
| 412 | |
| 413 | /// Returns the number of tables defined so far. |
| 414 | pub fn table_count(&self) -> u32 { |
| 415 | match &self.kind { |
| 416 | TypesRefKind::Module(module) => module.tables.len() as u32, |
| 417 | #[cfg (feature = "component-model" )] |
| 418 | TypesRefKind::Component(component) => component.core_tables.len() as u32, |
| 419 | } |
| 420 | } |
| 421 | |
| 422 | /// Gets the type of a memory at the given memory index. |
| 423 | /// |
| 424 | /// # Panics |
| 425 | /// |
| 426 | /// This will panic if the `index` provided is out of bounds. |
| 427 | pub fn memory_at(&self, index: u32) -> MemoryType { |
| 428 | let memories = match &self.kind { |
| 429 | TypesRefKind::Module(module) => &module.memories, |
| 430 | #[cfg (feature = "component-model" )] |
| 431 | TypesRefKind::Component(component) => &component.core_memories, |
| 432 | }; |
| 433 | |
| 434 | memories[index as usize] |
| 435 | } |
| 436 | |
| 437 | /// Returns the number of memories defined so far. |
| 438 | pub fn memory_count(&self) -> u32 { |
| 439 | match &self.kind { |
| 440 | TypesRefKind::Module(module) => module.memories.len() as u32, |
| 441 | #[cfg (feature = "component-model" )] |
| 442 | TypesRefKind::Component(component) => component.core_memories.len() as u32, |
| 443 | } |
| 444 | } |
| 445 | |
| 446 | /// Gets the type of a global at the given global index. |
| 447 | /// |
| 448 | /// # Panics |
| 449 | /// |
| 450 | /// This will panic if the `index` provided is out of bounds. |
| 451 | pub fn global_at(&self, index: u32) -> GlobalType { |
| 452 | let globals = match &self.kind { |
| 453 | TypesRefKind::Module(module) => &module.globals, |
| 454 | #[cfg (feature = "component-model" )] |
| 455 | TypesRefKind::Component(component) => &component.core_globals, |
| 456 | }; |
| 457 | |
| 458 | globals[index as usize] |
| 459 | } |
| 460 | |
| 461 | /// Returns the number of globals defined so far. |
| 462 | pub fn global_count(&self) -> u32 { |
| 463 | match &self.kind { |
| 464 | TypesRefKind::Module(module) => module.globals.len() as u32, |
| 465 | #[cfg (feature = "component-model" )] |
| 466 | TypesRefKind::Component(component) => component.core_globals.len() as u32, |
| 467 | } |
| 468 | } |
| 469 | |
| 470 | /// Gets the type of a tag at the given tag index. |
| 471 | /// |
| 472 | /// # Panics |
| 473 | /// |
| 474 | /// This will panic if the `index` provided is out of bounds. |
| 475 | pub fn tag_at(&self, index: u32) -> CoreTypeId { |
| 476 | let tags = match &self.kind { |
| 477 | TypesRefKind::Module(module) => &module.tags, |
| 478 | #[cfg (feature = "component-model" )] |
| 479 | TypesRefKind::Component(component) => &component.core_tags, |
| 480 | }; |
| 481 | tags[index as usize] |
| 482 | } |
| 483 | |
| 484 | /// Returns the number of tags defined so far. |
| 485 | pub fn tag_count(&self) -> u32 { |
| 486 | match &self.kind { |
| 487 | TypesRefKind::Module(module) => module.tags.len() as u32, |
| 488 | #[cfg (feature = "component-model" )] |
| 489 | TypesRefKind::Component(component) => component.core_tags.len() as u32, |
| 490 | } |
| 491 | } |
| 492 | |
| 493 | /// Gets the type of a core function at the given function index. |
| 494 | /// |
| 495 | /// # Panics |
| 496 | /// |
| 497 | /// This will panic if the `index` provided is out of bounds. |
| 498 | pub fn core_function_at(&self, index: u32) -> CoreTypeId { |
| 499 | match &self.kind { |
| 500 | TypesRefKind::Module(module) => module.types[module.functions[index as usize] as usize], |
| 501 | #[cfg (feature = "component-model" )] |
| 502 | TypesRefKind::Component(component) => component.core_funcs[index as usize], |
| 503 | } |
| 504 | } |
| 505 | |
| 506 | /// Gets the count of core functions defined so far. |
| 507 | /// |
| 508 | /// Note that this includes imported functions, defined functions, and for |
| 509 | /// components lowered/aliased functions. |
| 510 | pub fn function_count(&self) -> u32 { |
| 511 | match &self.kind { |
| 512 | TypesRefKind::Module(module) => module.functions.len() as u32, |
| 513 | #[cfg (feature = "component-model" )] |
| 514 | TypesRefKind::Component(component) => component.core_funcs.len() as u32, |
| 515 | } |
| 516 | } |
| 517 | |
| 518 | /// Gets the type of an element segment at the given element segment index. |
| 519 | /// |
| 520 | /// # Panics |
| 521 | /// |
| 522 | /// This will panic if the `index` provided is out of bounds. |
| 523 | pub fn element_at(&self, index: u32) -> RefType { |
| 524 | match &self.kind { |
| 525 | TypesRefKind::Module(module) => module.element_types[index as usize], |
| 526 | #[cfg (feature = "component-model" )] |
| 527 | TypesRefKind::Component(_) => { |
| 528 | panic!("no elements on a component" ) |
| 529 | } |
| 530 | } |
| 531 | } |
| 532 | |
| 533 | /// Returns the number of elements defined so far. |
| 534 | pub fn element_count(&self) -> u32 { |
| 535 | match &self.kind { |
| 536 | TypesRefKind::Module(module) => module.element_types.len() as u32, |
| 537 | #[cfg (feature = "component-model" )] |
| 538 | TypesRefKind::Component(_) => 0, |
| 539 | } |
| 540 | } |
| 541 | |
| 542 | /// Gets the entity type for the given import. |
| 543 | pub fn entity_type_from_import(&self, import: &Import) -> Option<EntityType> { |
| 544 | match &self.kind { |
| 545 | TypesRefKind::Module(module) => Some(match import.ty { |
| 546 | TypeRef::Func(idx) => EntityType::Func(*module.types.get(idx as usize)?), |
| 547 | TypeRef::Table(ty) => EntityType::Table(ty), |
| 548 | TypeRef::Memory(ty) => EntityType::Memory(ty), |
| 549 | TypeRef::Global(ty) => EntityType::Global(ty), |
| 550 | TypeRef::Tag(ty) => EntityType::Tag(*module.types.get(ty.func_type_idx as usize)?), |
| 551 | }), |
| 552 | #[cfg (feature = "component-model" )] |
| 553 | TypesRefKind::Component(_) => None, |
| 554 | } |
| 555 | } |
| 556 | |
| 557 | /// Gets the entity type from the given export. |
| 558 | pub fn entity_type_from_export(&self, export: &Export) -> Option<EntityType> { |
| 559 | match &self.kind { |
| 560 | TypesRefKind::Module(module) => Some(match export.kind { |
| 561 | ExternalKind::Func => EntityType::Func( |
| 562 | module.types[*module.functions.get(export.index as usize)? as usize], |
| 563 | ), |
| 564 | ExternalKind::Table => { |
| 565 | EntityType::Table(*module.tables.get(export.index as usize)?) |
| 566 | } |
| 567 | ExternalKind::Memory => { |
| 568 | EntityType::Memory(*module.memories.get(export.index as usize)?) |
| 569 | } |
| 570 | ExternalKind::Global => { |
| 571 | EntityType::Global(*module.globals.get(export.index as usize)?) |
| 572 | } |
| 573 | ExternalKind::Tag => EntityType::Tag( |
| 574 | module.types[*module.functions.get(export.index as usize)? as usize], |
| 575 | ), |
| 576 | }), |
| 577 | #[cfg (feature = "component-model" )] |
| 578 | TypesRefKind::Component(_) => None, |
| 579 | } |
| 580 | } |
| 581 | |
| 582 | /// Returns an iterator over the core wasm imports found. |
| 583 | /// |
| 584 | /// Returns `None` if this type information is for a component. |
| 585 | pub fn core_imports( |
| 586 | &self, |
| 587 | ) -> Option<impl Iterator<Item = (&'a str, &'a str, EntityType)> + 'a> { |
| 588 | match &self.kind { |
| 589 | TypesRefKind::Module(module) => Some( |
| 590 | module |
| 591 | .imports |
| 592 | .iter() |
| 593 | .flat_map(|((m, n), t)| t.iter().map(move |t| (m.as_str(), n.as_str(), *t))), |
| 594 | ), |
| 595 | #[cfg (feature = "component-model" )] |
| 596 | TypesRefKind::Component(_) => None, |
| 597 | } |
| 598 | } |
| 599 | |
| 600 | /// Returns an iterator over the core wasm exports found. |
| 601 | /// |
| 602 | /// Returns `None` if this type information is for a component. |
| 603 | pub fn core_exports(&self) -> Option<impl Iterator<Item = (&'a str, EntityType)> + 'a> { |
| 604 | match &self.kind { |
| 605 | TypesRefKind::Module(module) => { |
| 606 | Some(module.exports.iter().map(|(n, t)| (n.as_str(), *t))) |
| 607 | } |
| 608 | #[cfg (feature = "component-model" )] |
| 609 | TypesRefKind::Component(_) => None, |
| 610 | } |
| 611 | } |
| 612 | } |
| 613 | |
| 614 | impl<T> Index<T> for TypesRef<'_> |
| 615 | where |
| 616 | T: TypeIdentifier, |
| 617 | { |
| 618 | type Output = T::Data; |
| 619 | |
| 620 | fn index(&self, index: T) -> &Self::Output { |
| 621 | &self.list[index] |
| 622 | } |
| 623 | } |
| 624 | |
| 625 | impl Types { |
| 626 | pub(crate) fn from_module(id: ValidatorId, types: TypeList, module: Arc<Module>) -> Self { |
| 627 | Self { |
| 628 | id, |
| 629 | list: types, |
| 630 | kind: TypesKind::Module(module), |
| 631 | } |
| 632 | } |
| 633 | |
| 634 | #[cfg (feature = "component-model" )] |
| 635 | pub(crate) fn from_component( |
| 636 | id: ValidatorId, |
| 637 | types: TypeList, |
| 638 | component: ComponentState, |
| 639 | ) -> Self { |
| 640 | Self { |
| 641 | id, |
| 642 | list: types, |
| 643 | kind: TypesKind::Component(component), |
| 644 | } |
| 645 | } |
| 646 | |
| 647 | /// Return a [`TypesRef`] through which types can be inspected. |
| 648 | pub fn as_ref(&self) -> TypesRef<'_> { |
| 649 | TypesRef { |
| 650 | id: self.id, |
| 651 | list: &self.list, |
| 652 | kind: match &self.kind { |
| 653 | TypesKind::Module(module) => TypesRefKind::Module(module), |
| 654 | #[cfg (feature = "component-model" )] |
| 655 | TypesKind::Component(component) => TypesRefKind::Component(component), |
| 656 | }, |
| 657 | } |
| 658 | } |
| 659 | } |
| 660 | |
| 661 | impl<T> Index<T> for Types |
| 662 | where |
| 663 | T: TypeIdentifier, |
| 664 | { |
| 665 | type Output = T::Data; |
| 666 | |
| 667 | fn index(&self, id: T) -> &Self::Output { |
| 668 | &self.list[id] |
| 669 | } |
| 670 | } |
| 671 | |
| 672 | /// This is a type which mirrors a subset of the `Vec<T>` API, but is intended |
| 673 | /// to be able to be cheaply snapshotted and cloned. |
| 674 | /// |
| 675 | /// When each module's code sections start we "commit" the current list of types |
| 676 | /// in the global list of types. This means that the temporary `cur` vec here is |
| 677 | /// pushed onto `snapshots` and wrapped up in an `Arc`. At that point we clone |
| 678 | /// this entire list (which is then O(modules), not O(types in all modules)) and |
| 679 | /// pass out as a context to each function validator. |
| 680 | /// |
| 681 | /// Otherwise, though, this type behaves as if it were a large `Vec<T>`, but |
| 682 | /// it's represented by lists of contiguous chunks. |
| 683 | // |
| 684 | // Only public because it shows up in a public trait's `doc(hidden)` method. |
| 685 | #[doc (hidden)] |
| 686 | #[derive (Debug)] |
| 687 | pub struct SnapshotList<T> { |
| 688 | // All previous snapshots, the "head" of the list that this type represents. |
| 689 | // The first entry in this pair is the starting index for all elements |
| 690 | // contained in the list, and the second element is the list itself. Note |
| 691 | // the `Arc` wrapper around sub-lists, which makes cloning time for this |
| 692 | // `SnapshotList` O(snapshots) rather than O(snapshots_total), which for |
| 693 | // us in this context means the number of modules, not types. |
| 694 | // |
| 695 | // Note that this list is sorted least-to-greatest in order of the index for |
| 696 | // binary searching. |
| 697 | snapshots: Vec<Arc<Snapshot<T>>>, |
| 698 | |
| 699 | // This is the total length of all lists in the `snapshots` array. |
| 700 | snapshots_total: usize, |
| 701 | |
| 702 | // The current list of types for the current snapshot that are being built. |
| 703 | cur: Vec<T>, |
| 704 | } |
| 705 | |
| 706 | #[derive (Debug)] |
| 707 | struct Snapshot<T> { |
| 708 | prior_types: usize, |
| 709 | items: Vec<T>, |
| 710 | } |
| 711 | |
| 712 | impl<T> SnapshotList<T> { |
| 713 | /// Same as `<&[T]>::get` |
| 714 | pub(crate) fn get(&self, index: usize) -> Option<&T> { |
| 715 | // Check to see if this index falls on our local list |
| 716 | if index >= self.snapshots_total { |
| 717 | return self.cur.get(index - self.snapshots_total); |
| 718 | } |
| 719 | // ... and failing that we do a binary search to figure out which bucket |
| 720 | // it's in. Note the `i-1` in the `Err` case because if we don't find an |
| 721 | // exact match the type is located in the previous bucket. |
| 722 | let i = match self |
| 723 | .snapshots |
| 724 | .binary_search_by_key(&index, |snapshot| snapshot.prior_types) |
| 725 | { |
| 726 | Ok(i) => i, |
| 727 | Err(i) => i - 1, |
| 728 | }; |
| 729 | let snapshot = &self.snapshots[i]; |
| 730 | Some(&snapshot.items[index - snapshot.prior_types]) |
| 731 | } |
| 732 | |
| 733 | /// Same as `Vec::push` |
| 734 | pub(crate) fn push(&mut self, val: T) { |
| 735 | self.cur.push(val); |
| 736 | } |
| 737 | |
| 738 | /// Same as `<[T]>::len` |
| 739 | pub(crate) fn len(&self) -> usize { |
| 740 | self.cur.len() + self.snapshots_total |
| 741 | } |
| 742 | |
| 743 | /// Same as `Vec::truncate` but can only truncate uncommitted elements. |
| 744 | #[cfg (feature = "component-model" )] |
| 745 | pub(crate) fn truncate(&mut self, len: usize) { |
| 746 | assert!(len >= self.snapshots_total); |
| 747 | self.cur.truncate(len - self.snapshots_total); |
| 748 | } |
| 749 | |
| 750 | /// Commits previously pushed types into this snapshot vector, and returns a |
| 751 | /// clone of this list. |
| 752 | /// |
| 753 | /// The returned `SnapshotList` can be used to access all the same types as |
| 754 | /// this list itself. This list also is not changed (from an external |
| 755 | /// perspective) and can continue to access all the same types. |
| 756 | pub(crate) fn commit(&mut self) -> SnapshotList<T> { |
| 757 | // If the current chunk has new elements, commit them in to an |
| 758 | // `Arc`-wrapped vector in the snapshots list. Note the `shrink_to_fit` |
| 759 | // ahead of time to hopefully keep memory usage lower than it would |
| 760 | // otherwise be. |
| 761 | let len = self.cur.len(); |
| 762 | if len > 0 { |
| 763 | self.cur.shrink_to_fit(); |
| 764 | self.snapshots.push(Arc::new(Snapshot { |
| 765 | prior_types: self.snapshots_total, |
| 766 | items: mem::take(&mut self.cur), |
| 767 | })); |
| 768 | self.snapshots_total += len; |
| 769 | } |
| 770 | SnapshotList { |
| 771 | snapshots: self.snapshots.clone(), |
| 772 | snapshots_total: self.snapshots_total, |
| 773 | cur: Vec::new(), |
| 774 | } |
| 775 | } |
| 776 | } |
| 777 | |
| 778 | impl<T> Index<usize> for SnapshotList<T> { |
| 779 | type Output = T; |
| 780 | |
| 781 | #[inline ] |
| 782 | fn index(&self, index: usize) -> &T { |
| 783 | self.get(index).unwrap() |
| 784 | } |
| 785 | } |
| 786 | |
| 787 | impl<T, U> Index<U> for SnapshotList<T> |
| 788 | where |
| 789 | U: TypeIdentifier<Data = T>, |
| 790 | { |
| 791 | type Output = T; |
| 792 | |
| 793 | #[inline ] |
| 794 | fn index(&self, id: U) -> &T { |
| 795 | self.get(id.index()).unwrap() |
| 796 | } |
| 797 | } |
| 798 | |
| 799 | impl<T> Default for SnapshotList<T> { |
| 800 | fn default() -> SnapshotList<T> { |
| 801 | SnapshotList { |
| 802 | snapshots: Vec::new(), |
| 803 | snapshots_total: 0, |
| 804 | cur: Vec::new(), |
| 805 | } |
| 806 | } |
| 807 | } |
| 808 | |
| 809 | /// A snapshot list of types. |
| 810 | /// |
| 811 | /// Note that the snapshot lists below do not correspond with index spaces. Many |
| 812 | /// different kinds of types are in the same index space (e.g. all of the |
| 813 | /// component model's {component, instance, defined, func} types are in the same |
| 814 | /// index space). However, we store each of them in their own type-specific |
| 815 | /// snapshot list and give each of them their own identifier type. |
| 816 | #[derive (Default, Debug)] |
| 817 | // Only public because it shows up in a public trait's `doc(hidden)` method. |
| 818 | #[doc (hidden)] |
| 819 | pub struct TypeList { |
| 820 | // Core Wasm types. |
| 821 | // |
| 822 | // A primary map from `CoreTypeId` to `SubType`. |
| 823 | pub(super) core_types: SnapshotList<SubType>, |
| 824 | // The id of each core Wasm type's rec group. |
| 825 | // |
| 826 | // A secondary map from `CoreTypeId` to `RecGroupId`. |
| 827 | pub(super) core_type_to_rec_group: SnapshotList<RecGroupId>, |
| 828 | // The supertype of each core type. |
| 829 | // |
| 830 | // A secondary map from `CoreTypeId` to `Option<CoreTypeId>`. |
| 831 | pub(super) core_type_to_supertype: SnapshotList<Option<CoreTypeId>>, |
| 832 | // The subtyping depth of each core type. We use `u8::MAX` as a sentinel for |
| 833 | // an uninitialized entry. |
| 834 | // |
| 835 | // A secondary map from `CoreTypeId` to `u8`. |
| 836 | pub(super) core_type_to_depth: Option<IndexMap<CoreTypeId, u8>>, |
| 837 | // A primary map from `RecGroupId` to the range of the rec group's elements |
| 838 | // within `core_types`. |
| 839 | pub(super) rec_group_elements: SnapshotList<Range<CoreTypeId>>, |
| 840 | // A hash map from rec group elements to their canonical `RecGroupId`. |
| 841 | // |
| 842 | // This is `None` when a list is "committed" meaning that no more insertions |
| 843 | // can happen. |
| 844 | pub(super) canonical_rec_groups: Option<Map<RecGroup, RecGroupId>>, |
| 845 | |
| 846 | #[cfg (feature = "component-model" )] |
| 847 | pub(super) component: ComponentTypeList, |
| 848 | } |
| 849 | |
| 850 | impl TypeList { |
| 851 | pub fn get<T>(&self, id: T) -> Option<&T::Data> |
| 852 | where |
| 853 | T: TypeIdentifier, |
| 854 | { |
| 855 | T::list(self).get(id.index()) |
| 856 | } |
| 857 | |
| 858 | pub fn push<T>(&mut self, ty: T) -> T::Id |
| 859 | where |
| 860 | T: TypeData, |
| 861 | { |
| 862 | let index = u32::try_from(T::Id::list(self).len()).unwrap(); |
| 863 | let id = T::Id::from_index(index); |
| 864 | T::Id::list_mut(self).push(ty); |
| 865 | id |
| 866 | } |
| 867 | |
| 868 | /// Intern the given recursion group (that has already been canonicalized) |
| 869 | /// and return its associated id and whether this was a new recursion group |
| 870 | /// or not. |
| 871 | /// |
| 872 | /// If the `needs_type_canonicalization` flag is provided then the type will |
| 873 | /// be intern'd here and its indices will be canonicalized to `CoreTypeId` |
| 874 | /// from the previous `RecGroup`-based indices. |
| 875 | /// |
| 876 | /// If the `needs_type_canonicalization` flag is `false` then it must be |
| 877 | /// required that `RecGroup` doesn't have any rec-group-relative references |
| 878 | /// and it will additionally not be intern'd. |
| 879 | pub fn intern_canonical_rec_group( |
| 880 | &mut self, |
| 881 | needs_type_canonicalization: bool, |
| 882 | mut rec_group: RecGroup, |
| 883 | ) -> (bool, RecGroupId) { |
| 884 | let rec_group_id = self.rec_group_elements.len(); |
| 885 | let rec_group_id = u32::try_from(rec_group_id).unwrap(); |
| 886 | let rec_group_id = RecGroupId::from_index(rec_group_id); |
| 887 | |
| 888 | if needs_type_canonicalization { |
| 889 | let canonical_rec_groups = self |
| 890 | .canonical_rec_groups |
| 891 | .as_mut() |
| 892 | .expect("cannot intern into a committed list" ); |
| 893 | let entry = match canonical_rec_groups.entry(rec_group) { |
| 894 | Entry::Occupied(e) => return (false, *e.get()), |
| 895 | Entry::Vacant(e) => e, |
| 896 | }; |
| 897 | rec_group = entry.key().clone(); |
| 898 | entry.insert(rec_group_id); |
| 899 | } |
| 900 | |
| 901 | let start = self.core_types.len(); |
| 902 | let start = u32::try_from(start).unwrap(); |
| 903 | let start = CoreTypeId::from_index(start); |
| 904 | |
| 905 | for mut ty in rec_group.into_types() { |
| 906 | debug_assert_eq!(self.core_types.len(), self.core_type_to_supertype.len()); |
| 907 | debug_assert_eq!(self.core_types.len(), self.core_type_to_rec_group.len()); |
| 908 | |
| 909 | self.core_type_to_supertype |
| 910 | .push(ty.supertype_idx.and_then(|idx| match idx.unpack() { |
| 911 | UnpackedIndex::RecGroup(offset) => { |
| 912 | Some(CoreTypeId::from_index(start.index + offset)) |
| 913 | } |
| 914 | UnpackedIndex::Id(id) => Some(id), |
| 915 | // Only invalid wasm has this, at this point, so defer the |
| 916 | // error to later. |
| 917 | UnpackedIndex::Module(_) => None, |
| 918 | })); |
| 919 | ty.remap_indices(&mut |index| { |
| 920 | // Note that `UnpackedIndex::Id` is unmodified and |
| 921 | // `UnpackedIndex::Module` means that this is invalid wasm which |
| 922 | // will get an error returned later. |
| 923 | if let UnpackedIndex::RecGroup(offset) = index.unpack() { |
| 924 | *index = UnpackedIndex::Id(CoreTypeId::from_index(start.index + offset)) |
| 925 | .pack() |
| 926 | .unwrap(); |
| 927 | } |
| 928 | Ok(()) |
| 929 | }) |
| 930 | .expect("cannot fail" ); |
| 931 | self.core_types.push(ty); |
| 932 | self.core_type_to_rec_group.push(rec_group_id); |
| 933 | } |
| 934 | |
| 935 | let end = self.core_types.len(); |
| 936 | let end = u32::try_from(end).unwrap(); |
| 937 | let end = CoreTypeId::from_index(end); |
| 938 | |
| 939 | let range = start..end; |
| 940 | |
| 941 | self.rec_group_elements.push(range.clone()); |
| 942 | |
| 943 | return (true, rec_group_id); |
| 944 | } |
| 945 | |
| 946 | /// Helper for interning a sub type as a rec group; see |
| 947 | /// [`Self::intern_canonical_rec_group`]. |
| 948 | pub fn intern_sub_type(&mut self, sub_ty: SubType, offset: usize) -> CoreTypeId { |
| 949 | let (_is_new, group_id) = |
| 950 | self.intern_canonical_rec_group(false, RecGroup::implicit(offset, sub_ty)); |
| 951 | self[group_id].start |
| 952 | } |
| 953 | |
| 954 | /// Helper for interning a function type as a rec group; see |
| 955 | /// [`Self::intern_sub_type`]. |
| 956 | pub fn intern_func_type(&mut self, ty: FuncType, offset: usize) -> CoreTypeId { |
| 957 | self.intern_sub_type(SubType::func(ty, false), offset) |
| 958 | } |
| 959 | |
| 960 | /// Get the `CoreTypeId` for a local index into a rec group. |
| 961 | pub fn rec_group_local_id( |
| 962 | &self, |
| 963 | rec_group: RecGroupId, |
| 964 | index: u32, |
| 965 | offset: usize, |
| 966 | ) -> Result<CoreTypeId> { |
| 967 | let elems = &self[rec_group]; |
| 968 | let len = elems.end.index() - elems.start.index(); |
| 969 | let len = u32::try_from(len).unwrap(); |
| 970 | if index < len { |
| 971 | let id = u32::try_from(elems.start.index()).unwrap() + index; |
| 972 | let id = CoreTypeId::from_index(id); |
| 973 | Ok(id) |
| 974 | } else { |
| 975 | bail!( |
| 976 | offset, |
| 977 | "unknown type {index}: type index out of rec group bounds" |
| 978 | ) |
| 979 | } |
| 980 | } |
| 981 | |
| 982 | /// Get the id of the rec group that the given type id was defined within. |
| 983 | pub fn rec_group_id_of(&self, id: CoreTypeId) -> RecGroupId { |
| 984 | self.core_type_to_rec_group[id.index()] |
| 985 | } |
| 986 | |
| 987 | /// Get the super type of the given type id, if any. |
| 988 | pub fn supertype_of(&self, id: CoreTypeId) -> Option<CoreTypeId> { |
| 989 | self.core_type_to_supertype[id.index()] |
| 990 | } |
| 991 | |
| 992 | /// Get the subtyping depth of the given type. A type without any supertype |
| 993 | /// has depth 0. |
| 994 | pub fn get_subtyping_depth(&self, id: CoreTypeId) -> u8 { |
| 995 | let depth = self |
| 996 | .core_type_to_depth |
| 997 | .as_ref() |
| 998 | .expect("cannot get subtype depth from a committed list" )[&id]; |
| 999 | debug_assert!(usize::from(depth) <= crate::limits::MAX_WASM_SUBTYPING_DEPTH); |
| 1000 | depth |
| 1001 | } |
| 1002 | |
| 1003 | /// Set the subtyping depth of the given type. This may only be done once |
| 1004 | /// per type. |
| 1005 | pub fn set_subtyping_depth(&mut self, id: CoreTypeId, depth: u8) { |
| 1006 | debug_assert!(usize::from(depth) <= crate::limits::MAX_WASM_SUBTYPING_DEPTH); |
| 1007 | let map = self |
| 1008 | .core_type_to_depth |
| 1009 | .as_mut() |
| 1010 | .expect("cannot set a subtype depth in a committed list" ); |
| 1011 | debug_assert!(!map.contains_key(&id)); |
| 1012 | map.insert(id, depth); |
| 1013 | } |
| 1014 | |
| 1015 | /// Get the `CoreTypeId` for a canonicalized `PackedIndex`. |
| 1016 | /// |
| 1017 | /// Panics when given a non-canonicalized `PackedIndex`. |
| 1018 | pub fn at_canonicalized_packed_index( |
| 1019 | &self, |
| 1020 | rec_group: RecGroupId, |
| 1021 | index: PackedIndex, |
| 1022 | offset: usize, |
| 1023 | ) -> Result<CoreTypeId> { |
| 1024 | self.at_canonicalized_unpacked_index(rec_group, index.unpack(), offset) |
| 1025 | } |
| 1026 | |
| 1027 | /// Get the `CoreTypeId` for a canonicalized `UnpackedIndex`. |
| 1028 | /// |
| 1029 | /// Panics when given a non-canonicalized `PackedIndex`. |
| 1030 | pub fn at_canonicalized_unpacked_index( |
| 1031 | &self, |
| 1032 | rec_group: RecGroupId, |
| 1033 | index: UnpackedIndex, |
| 1034 | offset: usize, |
| 1035 | ) -> Result<CoreTypeId> { |
| 1036 | match index { |
| 1037 | UnpackedIndex::Module(_) => panic!("not canonicalized" ), |
| 1038 | UnpackedIndex::Id(id) => Ok(id), |
| 1039 | UnpackedIndex::RecGroup(idx) => self.rec_group_local_id(rec_group, idx, offset), |
| 1040 | } |
| 1041 | } |
| 1042 | |
| 1043 | /// Does `a` structurally match `b`? |
| 1044 | pub fn matches(&self, a: CoreTypeId, b: CoreTypeId) -> bool { |
| 1045 | let a = WithRecGroup::new(self, a); |
| 1046 | let a = WithRecGroup::map(a, |a| &self[a]); |
| 1047 | |
| 1048 | let b = WithRecGroup::new(self, b); |
| 1049 | let b = WithRecGroup::map(b, |b| &self[b]); |
| 1050 | |
| 1051 | Matches::matches(self, a, b) |
| 1052 | } |
| 1053 | |
| 1054 | /// Is `a == b` or was `a` declared (potentially transitively) to be a |
| 1055 | /// subtype of `b`? |
| 1056 | pub fn id_is_subtype(&self, mut a: CoreTypeId, b: CoreTypeId) -> bool { |
| 1057 | loop { |
| 1058 | if a == b { |
| 1059 | return true; |
| 1060 | } |
| 1061 | |
| 1062 | // TODO: maintain supertype vectors and implement this check in O(1) |
| 1063 | // instead of O(n) time. |
| 1064 | a = match self.supertype_of(a) { |
| 1065 | Some(a) => a, |
| 1066 | None => return false, |
| 1067 | }; |
| 1068 | } |
| 1069 | } |
| 1070 | |
| 1071 | /// Like `id_is_subtype` but for `RefType`s. |
| 1072 | /// |
| 1073 | /// Both `a` and `b` must be canonicalized already. |
| 1074 | pub fn reftype_is_subtype(&self, a: RefType, b: RefType) -> bool { |
| 1075 | // NB: Don't need `RecGroupId`s since we are calling from outside of the |
| 1076 | // rec group, and so any `PackedIndex`es we encounter have already been |
| 1077 | // canonicalized to `CoreTypeId`s directly. |
| 1078 | self.reftype_is_subtype_impl(a, None, b, None) |
| 1079 | } |
| 1080 | |
| 1081 | /// Implementation of `RefType` and `HeapType` subtyping. |
| 1082 | /// |
| 1083 | /// Panics if we need rec groups but aren't given them. Rec groups only need |
| 1084 | /// to be passed in when checking subtyping of `RefType`s that we encounter |
| 1085 | /// while validating a rec group itself. |
| 1086 | pub(crate) fn reftype_is_subtype_impl( |
| 1087 | &self, |
| 1088 | a: RefType, |
| 1089 | a_group: Option<RecGroupId>, |
| 1090 | b: RefType, |
| 1091 | b_group: Option<RecGroupId>, |
| 1092 | ) -> bool { |
| 1093 | if a == b && a_group == b_group { |
| 1094 | return true; |
| 1095 | } |
| 1096 | |
| 1097 | if a.is_nullable() && !b.is_nullable() { |
| 1098 | return false; |
| 1099 | } |
| 1100 | |
| 1101 | let core_type_id = |group: Option<RecGroupId>, index: UnpackedIndex| -> CoreTypeId { |
| 1102 | if let Some(id) = index.as_core_type_id() { |
| 1103 | id |
| 1104 | } else { |
| 1105 | self.at_canonicalized_unpacked_index(group.unwrap(), index, usize::MAX) |
| 1106 | .expect("type references are checked during canonicalization" ) |
| 1107 | } |
| 1108 | }; |
| 1109 | |
| 1110 | let subtype = |group, index| -> &SubType { |
| 1111 | let id = core_type_id(group, index); |
| 1112 | &self[id] |
| 1113 | }; |
| 1114 | |
| 1115 | use AbstractHeapType::*; |
| 1116 | use CompositeInnerType as CT; |
| 1117 | use HeapType as HT; |
| 1118 | match (a.heap_type(), b.heap_type()) { |
| 1119 | (a, b) if a == b => true, |
| 1120 | |
| 1121 | ( |
| 1122 | HT::Abstract { |
| 1123 | shared: a_shared, |
| 1124 | ty: a_ty, |
| 1125 | }, |
| 1126 | HT::Abstract { |
| 1127 | shared: b_shared, |
| 1128 | ty: b_ty, |
| 1129 | }, |
| 1130 | ) => a_shared == b_shared && a_ty.is_subtype_of(b_ty), |
| 1131 | |
| 1132 | (HT::Concrete(a), HT::Abstract { shared, ty }) => { |
| 1133 | let a_ty = &subtype(a_group, a).composite_type; |
| 1134 | if a_ty.shared != shared { |
| 1135 | return false; |
| 1136 | } |
| 1137 | match ty { |
| 1138 | Any | Eq => matches!(a_ty.inner, CT::Array(_) | CT::Struct(_)), |
| 1139 | Struct => matches!(a_ty.inner, CT::Struct(_)), |
| 1140 | Array => matches!(a_ty.inner, CT::Array(_)), |
| 1141 | Func => matches!(a_ty.inner, CT::Func(_)), |
| 1142 | Cont => matches!(a_ty.inner, CT::Cont(_)), |
| 1143 | // Nothing else matches. (Avoid full wildcard matches so |
| 1144 | // that adding/modifying variants is easier in the future.) |
| 1145 | Extern | Exn | I31 | None | NoFunc | NoExtern | NoExn | NoCont => false, |
| 1146 | } |
| 1147 | } |
| 1148 | |
| 1149 | (HT::Abstract { shared, ty }, HT::Concrete(b)) => { |
| 1150 | let b_ty = &subtype(b_group, b).composite_type; |
| 1151 | if shared != b_ty.shared { |
| 1152 | return false; |
| 1153 | } |
| 1154 | match ty { |
| 1155 | None => matches!(b_ty.inner, CT::Array(_) | CT::Struct(_)), |
| 1156 | NoFunc => matches!(b_ty.inner, CT::Func(_)), |
| 1157 | NoCont => matches!(b_ty.inner, CT::Cont(_)), |
| 1158 | // Nothing else matches. (Avoid full wildcard matches so |
| 1159 | // that adding/modifying variants is easier in the future.) |
| 1160 | Cont | Func | Extern | Exn | Any | Eq | Array | I31 | Struct | NoExtern |
| 1161 | | NoExn => false, |
| 1162 | } |
| 1163 | } |
| 1164 | |
| 1165 | (HT::Concrete(a), HT::Concrete(b)) => { |
| 1166 | self.id_is_subtype(core_type_id(a_group, a), core_type_id(b_group, b)) |
| 1167 | } |
| 1168 | } |
| 1169 | } |
| 1170 | |
| 1171 | /// Like `id_is_subtype` but for `RefType`s. |
| 1172 | /// |
| 1173 | /// Both `a` and `b` must be canonicalized already. |
| 1174 | pub fn valtype_is_subtype(&self, a: ValType, b: ValType) -> bool { |
| 1175 | match (a, b) { |
| 1176 | (a, b) if a == b => true, |
| 1177 | (ValType::Ref(a), ValType::Ref(b)) => self.reftype_is_subtype(a, b), |
| 1178 | (ValType::Ref(_), _) |
| 1179 | | (ValType::I32, _) |
| 1180 | | (ValType::I64, _) |
| 1181 | | (ValType::F32, _) |
| 1182 | | (ValType::F64, _) |
| 1183 | | (ValType::V128, _) => false, |
| 1184 | } |
| 1185 | } |
| 1186 | |
| 1187 | /// Is `ty` shared? |
| 1188 | pub fn valtype_is_shared(&self, ty: ValType) -> bool { |
| 1189 | match ty { |
| 1190 | ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => true, |
| 1191 | ValType::Ref(rt) => self.reftype_is_shared(rt), |
| 1192 | } |
| 1193 | } |
| 1194 | |
| 1195 | /// Is the reference type `ty` shared? |
| 1196 | /// |
| 1197 | /// This is complicated by concrete heap types whose shared-ness must be |
| 1198 | /// checked by looking at the type they point to. |
| 1199 | pub fn reftype_is_shared(&self, ty: RefType) -> bool { |
| 1200 | match ty.heap_type() { |
| 1201 | HeapType::Abstract { shared, .. } => shared, |
| 1202 | HeapType::Concrete(index) => { |
| 1203 | self[index.as_core_type_id().unwrap()].composite_type.shared |
| 1204 | } |
| 1205 | } |
| 1206 | } |
| 1207 | |
| 1208 | /// Get the top type of the given heap type. |
| 1209 | /// |
| 1210 | /// Concrete types must have had their indices canonicalized to core type |
| 1211 | /// ids, otherwise this method will panic. |
| 1212 | pub fn top_type(&self, heap_type: &HeapType) -> HeapType { |
| 1213 | use AbstractHeapType::*; |
| 1214 | match *heap_type { |
| 1215 | HeapType::Concrete(idx) => { |
| 1216 | let ty = &self[idx.as_core_type_id().unwrap()].composite_type; |
| 1217 | let shared = ty.shared; |
| 1218 | match ty.inner { |
| 1219 | CompositeInnerType::Func(_) => HeapType::Abstract { shared, ty: Func }, |
| 1220 | CompositeInnerType::Array(_) | CompositeInnerType::Struct(_) => { |
| 1221 | HeapType::Abstract { shared, ty: Any } |
| 1222 | } |
| 1223 | CompositeInnerType::Cont(_) => HeapType::Abstract { shared, ty: Cont }, |
| 1224 | } |
| 1225 | } |
| 1226 | HeapType::Abstract { shared, ty } => { |
| 1227 | let ty = match ty { |
| 1228 | Func | NoFunc => Func, |
| 1229 | Extern | NoExtern => Extern, |
| 1230 | Any | Eq | Struct | Array | I31 | None => Any, |
| 1231 | Exn | NoExn => Exn, |
| 1232 | Cont | NoCont => Cont, |
| 1233 | }; |
| 1234 | HeapType::Abstract { shared, ty } |
| 1235 | } |
| 1236 | } |
| 1237 | } |
| 1238 | |
| 1239 | pub fn commit(&mut self) -> TypeList { |
| 1240 | TypeList { |
| 1241 | core_types: self.core_types.commit(), |
| 1242 | core_type_to_rec_group: self.core_type_to_rec_group.commit(), |
| 1243 | core_type_to_supertype: self.core_type_to_supertype.commit(), |
| 1244 | core_type_to_depth: None, |
| 1245 | rec_group_elements: self.rec_group_elements.commit(), |
| 1246 | canonical_rec_groups: None, |
| 1247 | #[cfg (feature = "component-model" )] |
| 1248 | component: self.component.commit(), |
| 1249 | } |
| 1250 | } |
| 1251 | } |
| 1252 | |
| 1253 | impl<T> Index<T> for TypeList |
| 1254 | where |
| 1255 | T: TypeIdentifier, |
| 1256 | { |
| 1257 | type Output = T::Data; |
| 1258 | |
| 1259 | fn index(&self, id: T) -> &Self::Output { |
| 1260 | let arena: &SnapshotList<::Data> = T::list(self); |
| 1261 | &arena[id.index()] |
| 1262 | } |
| 1263 | } |
| 1264 | |
| 1265 | /// Thin wrapper around `TypeList` which provides an allocator of unique ids for |
| 1266 | /// types contained within this list. |
| 1267 | pub(crate) struct TypeAlloc { |
| 1268 | list: TypeList, |
| 1269 | #[cfg (feature = "component-model" )] |
| 1270 | pub(super) component_alloc: ComponentTypeAlloc, |
| 1271 | } |
| 1272 | |
| 1273 | impl Default for TypeAlloc { |
| 1274 | fn default() -> TypeAlloc { |
| 1275 | let mut ret: TypeAlloc = TypeAlloc { |
| 1276 | list: TypeList::default(), |
| 1277 | #[cfg (feature = "component-model" )] |
| 1278 | component_alloc: ComponentTypeAlloc::default(), |
| 1279 | }; |
| 1280 | ret.list.core_type_to_depth = Some(Default::default()); |
| 1281 | ret.list.canonical_rec_groups = Some(Default::default()); |
| 1282 | ret |
| 1283 | } |
| 1284 | } |
| 1285 | |
| 1286 | impl Deref for TypeAlloc { |
| 1287 | type Target = TypeList; |
| 1288 | fn deref(&self) -> &TypeList { |
| 1289 | &self.list |
| 1290 | } |
| 1291 | } |
| 1292 | |
| 1293 | impl DerefMut for TypeAlloc { |
| 1294 | fn deref_mut(&mut self) -> &mut TypeList { |
| 1295 | &mut self.list |
| 1296 | } |
| 1297 | } |
| 1298 | |
| 1299 | impl<T> Index<T> for TypeAlloc |
| 1300 | where |
| 1301 | T: TypeIdentifier, |
| 1302 | { |
| 1303 | type Output = T::Data; |
| 1304 | |
| 1305 | #[inline ] |
| 1306 | fn index(&self, id: T) -> &T::Data { |
| 1307 | &self.list[id] |
| 1308 | } |
| 1309 | } |
| 1310 | |