1 //! A dataflow-graph-like intermediate representation of a component 2 //! 3 //! This module contains `ComponentDfg` which is an intermediate step towards 4 //! becoming a full-fledged `Component`. The main purpose for the existence of 5 //! this representation of a component is to track dataflow between various 6 //! items within a component and support edits to them after the initial inlined 7 //! translation of a component. 8 //! 9 //! Currently fused adapters are represented with a core WebAssembly module 10 //! which gets "injected" into the final component as-if the component already 11 //! bundled it. In doing so the adapter modules need to be partitioned and 12 //! inserted into the final sequence of modules to instantiate. While this is 13 //! possible to do with a flat `GlobalInitializer` list it gets unwieldy really 14 //! quickly especially when other translation features are added. 15 //! 16 //! This module is largely a duplicate of the `component::info` module in this 17 //! crate. The hierarchy here uses `*Id` types instead of `*Index` types to 18 //! represent that they don't have any necessary implicit ordering. Additionally 19 //! nothing is kept in an ordered list and instead this is worked with in a 20 //! general dataflow fashion where dependencies are walked during processing. 21 //! 22 //! The `ComponentDfg::finish` method will convert the dataflow graph to a 23 //! linearized `GlobalInitializer` list which is intended to not be edited after 24 //! it's created. 25 //! 26 //! The `ComponentDfg` is created as part of the `component::inline` phase of 27 //! translation where the dataflow performed there allows identification of 28 //! fused adapters, what arguments make their way to core wasm modules, etc. 29 30 use crate::component::*; 31 use crate::error::Result; 32 use crate::prelude::*; 33 use crate::{EntityIndex, EntityRef, ModuleInternedTypeIndex, PrimaryMap, WasmValType}; 34 use cranelift_entity::packed_option::PackedOption; 35 use indexmap::IndexMap; 36 use info::LinearMemoryOptions; 37 use std::collections::HashMap; 38 use std::hash::Hash; 39 use std::ops::Index; 40 use wasmparser::component_types::ComponentCoreModuleTypeId; 41 42 /// High-level representation of a component as a "data-flow graph". 43 #[derive(Default)] 44 pub struct ComponentDfg { 45 /// Same as `Component::import_types` 46 pub import_types: PrimaryMap<ImportIndex, (String, TypeDef)>, 47 48 /// Same as `Component::imports` 49 pub imports: PrimaryMap<RuntimeImportIndex, (ImportIndex, Vec<String>)>, 50 51 /// Same as `Component::exports` 52 pub exports: IndexMap<String, Export>, 53 54 /// All trampolines and their type signature which will need to get 55 /// compiled by Cranelift. 56 pub trampolines: Intern<TrampolineIndex, (ModuleInternedTypeIndex, Trampoline)>, 57 58 /// A map from `UnsafeIntrinsic::index()` to that intrinsic's 59 /// module-interned type. 60 pub unsafe_intrinsics: [PackedOption<ModuleInternedTypeIndex>; UnsafeIntrinsic::len() as usize], 61 62 /// Know reallocation functions which are used by `lowerings` (e.g. will be 63 /// used by the host) 64 pub reallocs: Intern<ReallocId, CoreDef>, 65 66 /// Same as `reallocs`, but for async-lifted functions. 67 pub callbacks: Intern<CallbackId, CoreDef>, 68 69 /// Same as `reallocs`, but for post-return. 70 pub post_returns: Intern<PostReturnId, CoreDef>, 71 72 /// Same as `reallocs`, but for memories. 73 pub memories: Intern<MemoryId, CoreExport<MemoryIndex>>, 74 75 /// Same as `reallocs`, but for tables. 76 pub tables: Intern<TableId, CoreExport<TableIndex>>, 77 78 /// Metadata about identified fused adapters. 79 /// 80 /// Note that this list is required to be populated in-order where the 81 /// "left" adapters cannot depend on "right" adapters. Currently this falls 82 /// out of the inlining pass of translation. 83 pub adapters: Intern<AdapterId, Adapter>, 84 85 /// Metadata about all known core wasm instances created. 86 /// 87 /// This is mostly an ordered list and is not deduplicated based on contents 88 /// unlike the items above. Creation of an `Instance` is side-effectful and 89 /// all instances here are always required to be created. These are 90 /// considered "roots" in dataflow. 91 pub instances: PrimaryMap<InstanceId, Instance>, 92 93 /// Number of component instances that were created during the inlining 94 /// phase (this is not edited after creation). 95 pub num_runtime_component_instances: u32, 96 97 /// Known adapter modules and how they are instantiated. 98 /// 99 /// This map is not filled in on the initial creation of a `ComponentDfg`. 100 /// Instead these modules are filled in by the `inline::adapt` phase where 101 /// adapter modules are identified and filled in here. 102 /// 103 /// The payload here is the static module index representing the core wasm 104 /// adapter module that was generated as well as the arguments to the 105 /// instantiation of the adapter module. 106 pub adapter_modules: PrimaryMap<AdapterModuleId, (StaticModuleIndex, Vec<CoreDef>)>, 107 108 /// Metadata about where adapters can be found within their respective 109 /// adapter modules. 110 /// 111 /// Like `adapter_modules` this is not filled on the initial creation of 112 /// `ComponentDfg` but rather is created alongside `adapter_modules` during 113 /// the `inline::adapt` phase of translation. 114 /// 115 /// The values here are the module that the adapter is present within along 116 /// as the core wasm index of the export corresponding to the lowered 117 /// version of the adapter. 118 pub adapter_partitionings: PrimaryMap<AdapterId, (AdapterModuleId, EntityIndex)>, 119 120 /// Defined resources in this component sorted by index with metadata about 121 /// each resource. 122 /// 123 /// Note that each index here is a unique resource, and that may mean it was 124 /// the same component instantiated twice for example. 125 pub resources: PrimaryMap<DefinedResourceIndex, Resource>, 126 127 /// Metadata about all imported resources into this component. This records 128 /// both how many imported resources there are (the size of this map) along 129 /// with what the corresponding runtime import is. 130 pub imported_resources: PrimaryMap<ResourceIndex, RuntimeImportIndex>, 131 132 /// The total number of future tables that will be used by this component. 133 pub num_future_tables: usize, 134 135 /// The total number of stream tables that will be used by this component. 136 pub num_stream_tables: usize, 137 138 /// The total number of error-context tables that will be used by this 139 /// component. 140 pub num_error_context_tables: usize, 141 142 /// An ordered list of side effects induced by instantiating this component. 143 /// 144 /// Currently all side effects are either instantiating core wasm modules or 145 /// declaring a resource. These side effects affect the dataflow processing 146 /// of this component by idnicating what order operations should be 147 /// performed during instantiation. 148 pub side_effects: Vec<SideEffect>, 149 150 /// Interned map of id-to-`CanonicalOptions`, or all sets-of-options used by 151 /// this component. 152 pub options: Intern<OptionsId, CanonicalOptions>, 153 } 154 155 /// Possible side effects that are possible with instantiating this component. 156 pub enum SideEffect { 157 /// A core wasm instance was created. 158 /// 159 /// Instantiation is side-effectful due to the presence of constructs such 160 /// as traps and the core wasm `start` function which may call component 161 /// imports. Instantiation order from the original component must be done in 162 /// the same order. 163 Instance(InstanceId, RuntimeComponentInstanceIndex), 164 165 /// A resource was declared in this component. 166 /// 167 /// This is a bit less side-effectful than instantiation but this serves as 168 /// the order in which resources are initialized in a component with their 169 /// destructors. Destructors are loaded from core wasm instances (or 170 /// lowerings) which are produced by prior side-effectful operations. 171 Resource(DefinedResourceIndex), 172 } 173 174 /// A sound approximation of a particular module's set of instantiations. 175 /// 176 /// This type forms a simple lattice that we can use in static analyses that in 177 /// turn let us specialize a module's compilation to exactly the imports it is 178 /// given. 179 #[derive(Clone, Copy, Default)] 180 pub enum AbstractInstantiations<'a> { 181 /// The associated module is instantiated many times. 182 Many, 183 184 /// The module is instantiated exactly once, with the given definitions as 185 /// arguments to that instantiation. 186 One(&'a [info::CoreDef]), 187 188 /// The module is never instantiated. 189 #[default] 190 None, 191 } 192 193 impl AbstractInstantiations<'_> { 194 /// Join two facts about a particular module's instantiation together. 195 /// 196 /// This is the least-upper-bound operation on the lattice. join(&mut self, other: Self)197 pub fn join(&mut self, other: Self) { 198 *self = match (*self, other) { 199 (Self::Many, _) | (_, Self::Many) => Self::Many, 200 (Self::One(a), Self::One(b)) if a == b => Self::One(a), 201 (Self::One(_), Self::One(_)) => Self::Many, 202 (Self::One(a), Self::None) | (Self::None, Self::One(a)) => Self::One(a), 203 (Self::None, Self::None) => Self::None, 204 } 205 } 206 } 207 208 macro_rules! id { 209 ($(pub struct $name:ident(u32);)*) => ($( 210 #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] 211 #[expect(missing_docs, reason = "tedious to document")] 212 pub struct $name(u32); 213 cranelift_entity::entity_impl!($name); 214 )*) 215 } 216 217 id! { 218 pub struct InstanceId(u32); 219 pub struct MemoryId(u32); 220 pub struct TableId(u32); 221 pub struct ReallocId(u32); 222 pub struct CallbackId(u32); 223 pub struct AdapterId(u32); 224 pub struct PostReturnId(u32); 225 pub struct AdapterModuleId(u32); 226 pub struct OptionsId(u32); 227 } 228 229 /// Same as `info::InstantiateModule` 230 #[expect(missing_docs, reason = "tedious to document variants")] 231 pub enum Instance { 232 Static(StaticModuleIndex, Box<[CoreDef]>), 233 Import( 234 RuntimeImportIndex, 235 IndexMap<String, IndexMap<String, CoreDef>>, 236 ), 237 } 238 239 /// Same as `info::Export` 240 #[expect(missing_docs, reason = "tedious to document variants")] 241 pub enum Export { 242 LiftedFunction { 243 ty: TypeFuncIndex, 244 func: CoreDef, 245 options: OptionsId, 246 }, 247 ModuleStatic { 248 ty: ComponentCoreModuleTypeId, 249 index: StaticModuleIndex, 250 }, 251 ModuleImport { 252 ty: TypeModuleIndex, 253 import: RuntimeImportIndex, 254 }, 255 Instance { 256 ty: TypeComponentInstanceIndex, 257 exports: IndexMap<String, Export>, 258 }, 259 Type(TypeDef), 260 } 261 262 /// Same as `info::CoreDef`, except has an extra `Adapter` variant. 263 #[derive(Debug, Clone, Hash, Eq, PartialEq)] 264 #[expect(missing_docs, reason = "tedious to document variants")] 265 pub enum CoreDef { 266 Export(CoreExport<EntityIndex>), 267 InstanceFlags(RuntimeComponentInstanceIndex), 268 Trampoline(TrampolineIndex), 269 UnsafeIntrinsic(ModuleInternedTypeIndex, UnsafeIntrinsic), 270 TaskMayBlock, 271 272 /// This is a special variant not present in `info::CoreDef` which 273 /// represents that this definition refers to a fused adapter function. This 274 /// adapter is fully processed after the initial translation and 275 /// identification of adapters. 276 /// 277 /// During translation into `info::CoreDef` this variant is erased and 278 /// replaced by `info::CoreDef::Export` since adapters are always 279 /// represented as the exports of a core wasm instance. 280 Adapter(AdapterId), 281 } 282 283 impl<T> From<CoreExport<T>> for CoreDef 284 where 285 EntityIndex: From<T>, 286 { from(export: CoreExport<T>) -> CoreDef287 fn from(export: CoreExport<T>) -> CoreDef { 288 CoreDef::Export(export.map_index(|i| i.into())) 289 } 290 } 291 292 /// Same as `info::CoreExport` 293 #[derive(Debug, Clone, Hash, Eq, PartialEq)] 294 #[expect(missing_docs, reason = "self-describing fields")] 295 pub struct CoreExport<T> { 296 pub instance: InstanceId, 297 pub item: ExportItem<T>, 298 } 299 300 impl<T> CoreExport<T> { 301 #[expect(missing_docs, reason = "self-describing function")] map_index<U>(self, f: impl FnOnce(T) -> U) -> CoreExport<U>302 pub fn map_index<U>(self, f: impl FnOnce(T) -> U) -> CoreExport<U> { 303 CoreExport { 304 instance: self.instance, 305 item: match self.item { 306 ExportItem::Index(i) => ExportItem::Index(f(i)), 307 ExportItem::Name(s) => ExportItem::Name(s), 308 }, 309 } 310 } 311 } 312 313 /// Same as `info::Trampoline` 314 #[derive(Clone, PartialEq, Eq, Hash)] 315 #[expect(missing_docs, reason = "self-describing fields")] 316 pub enum Trampoline { 317 LowerImport { 318 import: RuntimeImportIndex, 319 options: OptionsId, 320 lower_ty: TypeFuncIndex, 321 }, 322 Transcoder { 323 op: Transcode, 324 from: MemoryId, 325 from64: bool, 326 to: MemoryId, 327 to64: bool, 328 }, 329 ResourceNew { 330 instance: RuntimeComponentInstanceIndex, 331 ty: TypeResourceTableIndex, 332 }, 333 ResourceRep { 334 instance: RuntimeComponentInstanceIndex, 335 ty: TypeResourceTableIndex, 336 }, 337 ResourceDrop { 338 instance: RuntimeComponentInstanceIndex, 339 ty: TypeResourceTableIndex, 340 }, 341 BackpressureInc { 342 instance: RuntimeComponentInstanceIndex, 343 }, 344 BackpressureDec { 345 instance: RuntimeComponentInstanceIndex, 346 }, 347 TaskReturn { 348 instance: RuntimeComponentInstanceIndex, 349 results: TypeTupleIndex, 350 options: OptionsId, 351 }, 352 TaskCancel { 353 instance: RuntimeComponentInstanceIndex, 354 }, 355 WaitableSetNew { 356 instance: RuntimeComponentInstanceIndex, 357 }, 358 WaitableSetWait { 359 instance: RuntimeComponentInstanceIndex, 360 options: OptionsId, 361 }, 362 WaitableSetPoll { 363 instance: RuntimeComponentInstanceIndex, 364 options: OptionsId, 365 }, 366 WaitableSetDrop { 367 instance: RuntimeComponentInstanceIndex, 368 }, 369 WaitableJoin { 370 instance: RuntimeComponentInstanceIndex, 371 }, 372 ThreadYield { 373 instance: RuntimeComponentInstanceIndex, 374 cancellable: bool, 375 }, 376 SubtaskDrop { 377 instance: RuntimeComponentInstanceIndex, 378 }, 379 SubtaskCancel { 380 instance: RuntimeComponentInstanceIndex, 381 async_: bool, 382 }, 383 StreamNew { 384 instance: RuntimeComponentInstanceIndex, 385 ty: TypeStreamTableIndex, 386 }, 387 StreamRead { 388 instance: RuntimeComponentInstanceIndex, 389 ty: TypeStreamTableIndex, 390 options: OptionsId, 391 }, 392 StreamWrite { 393 instance: RuntimeComponentInstanceIndex, 394 ty: TypeStreamTableIndex, 395 options: OptionsId, 396 }, 397 StreamCancelRead { 398 instance: RuntimeComponentInstanceIndex, 399 ty: TypeStreamTableIndex, 400 async_: bool, 401 }, 402 StreamCancelWrite { 403 instance: RuntimeComponentInstanceIndex, 404 ty: TypeStreamTableIndex, 405 async_: bool, 406 }, 407 StreamDropReadable { 408 instance: RuntimeComponentInstanceIndex, 409 ty: TypeStreamTableIndex, 410 }, 411 StreamDropWritable { 412 instance: RuntimeComponentInstanceIndex, 413 ty: TypeStreamTableIndex, 414 }, 415 FutureNew { 416 instance: RuntimeComponentInstanceIndex, 417 ty: TypeFutureTableIndex, 418 }, 419 FutureRead { 420 instance: RuntimeComponentInstanceIndex, 421 ty: TypeFutureTableIndex, 422 options: OptionsId, 423 }, 424 FutureWrite { 425 instance: RuntimeComponentInstanceIndex, 426 ty: TypeFutureTableIndex, 427 options: OptionsId, 428 }, 429 FutureCancelRead { 430 instance: RuntimeComponentInstanceIndex, 431 ty: TypeFutureTableIndex, 432 async_: bool, 433 }, 434 FutureCancelWrite { 435 instance: RuntimeComponentInstanceIndex, 436 ty: TypeFutureTableIndex, 437 async_: bool, 438 }, 439 FutureDropReadable { 440 instance: RuntimeComponentInstanceIndex, 441 ty: TypeFutureTableIndex, 442 }, 443 FutureDropWritable { 444 instance: RuntimeComponentInstanceIndex, 445 ty: TypeFutureTableIndex, 446 }, 447 ErrorContextNew { 448 instance: RuntimeComponentInstanceIndex, 449 ty: TypeComponentLocalErrorContextTableIndex, 450 options: OptionsId, 451 }, 452 ErrorContextDebugMessage { 453 instance: RuntimeComponentInstanceIndex, 454 ty: TypeComponentLocalErrorContextTableIndex, 455 options: OptionsId, 456 }, 457 ErrorContextDrop { 458 instance: RuntimeComponentInstanceIndex, 459 ty: TypeComponentLocalErrorContextTableIndex, 460 }, 461 ResourceTransferOwn, 462 ResourceTransferBorrow, 463 PrepareCall { 464 memory: Option<MemoryId>, 465 }, 466 SyncStartCall { 467 callback: Option<CallbackId>, 468 }, 469 AsyncStartCall { 470 callback: Option<CallbackId>, 471 post_return: Option<PostReturnId>, 472 }, 473 FutureTransfer, 474 StreamTransfer, 475 ErrorContextTransfer, 476 Trap, 477 EnterSyncCall, 478 ExitSyncCall, 479 ContextGet { 480 instance: RuntimeComponentInstanceIndex, 481 slot: u32, 482 }, 483 ContextSet { 484 instance: RuntimeComponentInstanceIndex, 485 slot: u32, 486 }, 487 ThreadIndex, 488 ThreadNewIndirect { 489 instance: RuntimeComponentInstanceIndex, 490 start_func_ty_idx: ComponentTypeIndex, 491 start_func_table_id: TableId, 492 }, 493 ThreadSuspendToSuspended { 494 instance: RuntimeComponentInstanceIndex, 495 cancellable: bool, 496 }, 497 ThreadSuspend { 498 instance: RuntimeComponentInstanceIndex, 499 cancellable: bool, 500 }, 501 ThreadSuspendTo { 502 instance: RuntimeComponentInstanceIndex, 503 cancellable: bool, 504 }, 505 ThreadUnsuspend { 506 instance: RuntimeComponentInstanceIndex, 507 }, 508 ThreadYieldToSuspended { 509 instance: RuntimeComponentInstanceIndex, 510 cancellable: bool, 511 }, 512 } 513 514 #[derive(Copy, Clone, Hash, Eq, PartialEq)] 515 #[expect(missing_docs, reason = "self-describing fields")] 516 pub struct FutureInfo { 517 pub instance: RuntimeComponentInstanceIndex, 518 pub payload_type: Option<InterfaceType>, 519 } 520 521 #[derive(Copy, Clone, Hash, Eq, PartialEq)] 522 #[expect(missing_docs, reason = "self-describing fields")] 523 pub struct StreamInfo { 524 pub instance: RuntimeComponentInstanceIndex, 525 pub payload_type: InterfaceType, 526 } 527 528 /// Same as `info::CanonicalOptionsDataModel`. 529 #[derive(Clone, Hash, Eq, PartialEq)] 530 #[expect(missing_docs, reason = "self-describing fields")] 531 pub enum CanonicalOptionsDataModel { 532 Gc {}, 533 LinearMemory { 534 memory: Option<MemoryId>, 535 realloc: Option<ReallocId>, 536 }, 537 } 538 539 /// Same as `info::CanonicalOptions` 540 #[derive(Clone, Hash, Eq, PartialEq)] 541 #[expect(missing_docs, reason = "self-describing fields")] 542 pub struct CanonicalOptions { 543 pub instance: RuntimeComponentInstanceIndex, 544 pub string_encoding: StringEncoding, 545 pub callback: Option<CallbackId>, 546 pub post_return: Option<PostReturnId>, 547 pub async_: bool, 548 pub cancellable: bool, 549 pub core_type: ModuleInternedTypeIndex, 550 pub data_model: CanonicalOptionsDataModel, 551 } 552 553 /// Same as `info::Resource` 554 #[expect(missing_docs, reason = "self-describing fields")] 555 pub struct Resource { 556 pub rep: WasmValType, 557 pub dtor: Option<CoreDef>, 558 pub instance: RuntimeComponentInstanceIndex, 559 } 560 561 /// A helper structure to "intern" and deduplicate values of type `V` with an 562 /// identifying key `K`. 563 /// 564 /// Note that this can also be used where `V` can't be intern'd to represent a 565 /// flat list of items. 566 pub struct Intern<K: EntityRef, V> { 567 intern_map: HashMap<V, K>, 568 key_map: PrimaryMap<K, V>, 569 } 570 571 impl<K, V> Intern<K, V> 572 where 573 K: EntityRef, 574 { 575 /// Inserts the `value` specified into this set, returning either a fresh 576 /// key `K` if this value hasn't been seen before or otherwise returning the 577 /// previous `K` used to represent value. 578 /// 579 /// Note that this should only be used for component model items where the 580 /// creation of `value` is not side-effectful. push(&mut self, value: V) -> K where V: Hash + Eq + Clone,581 pub fn push(&mut self, value: V) -> K 582 where 583 V: Hash + Eq + Clone, 584 { 585 *self 586 .intern_map 587 .entry(value.clone()) 588 .or_insert_with(|| self.key_map.push(value)) 589 } 590 591 /// Returns an iterator of all the values contained within this set. iter(&self) -> impl Iterator<Item = (K, &V)>592 pub fn iter(&self) -> impl Iterator<Item = (K, &V)> { 593 self.key_map.iter() 594 } 595 } 596 597 impl<K: EntityRef, V> Index<K> for Intern<K, V> { 598 type Output = V; index(&self, key: K) -> &V599 fn index(&self, key: K) -> &V { 600 &self.key_map[key] 601 } 602 } 603 604 impl<K: EntityRef, V> Default for Intern<K, V> { default() -> Intern<K, V>605 fn default() -> Intern<K, V> { 606 Intern { 607 intern_map: HashMap::new(), 608 key_map: PrimaryMap::new(), 609 } 610 } 611 } 612 613 impl ComponentDfg { 614 /// Consumes the intermediate `ComponentDfg` to produce a final `Component` 615 /// with a linear initializer list. finish( self, wasmtime_types: &mut ComponentTypesBuilder, wasmparser_types: wasmparser::types::TypesRef<'_>, ) -> Result<ComponentTranslation>616 pub fn finish( 617 self, 618 wasmtime_types: &mut ComponentTypesBuilder, 619 wasmparser_types: wasmparser::types::TypesRef<'_>, 620 ) -> Result<ComponentTranslation> { 621 let mut linearize = LinearizeDfg { 622 dfg: &self, 623 initializers: Vec::new(), 624 runtime_memories: Default::default(), 625 runtime_tables: Default::default(), 626 runtime_post_return: Default::default(), 627 runtime_reallocs: Default::default(), 628 runtime_callbacks: Default::default(), 629 runtime_instances: Default::default(), 630 num_lowerings: 0, 631 unsafe_intrinsics: Default::default(), 632 trampolines: Default::default(), 633 trampoline_defs: Default::default(), 634 trampoline_map: Default::default(), 635 options: Default::default(), 636 options_map: Default::default(), 637 }; 638 639 // Handle all side effects of this component in the order that they're 640 // defined. This will, for example, process all instantiations necessary 641 // of core wasm modules. 642 for item in linearize.dfg.side_effects.iter() { 643 linearize.side_effect(item); 644 } 645 646 // Next the exports of the instance are handled which will likely end up 647 // creating some lowered imports, perhaps some saved modules, etc. 648 let mut export_items = PrimaryMap::new(); 649 let mut exports = NameMap::default(); 650 for (name, export) in self.exports.iter() { 651 let export = 652 linearize.export(export, &mut export_items, wasmtime_types, wasmparser_types)?; 653 exports.insert(name, &mut NameMapNoIntern, false, export)?; 654 } 655 656 // With all those pieces done the results of the dataflow-based 657 // linearization are recorded into the `Component`. The number of 658 // runtime values used for each index space is used from the `linearize` 659 // result. 660 Ok(ComponentTranslation { 661 trampolines: linearize.trampoline_defs, 662 component: Component { 663 exports, 664 export_items, 665 initializers: linearize.initializers, 666 unsafe_intrinsics: linearize.unsafe_intrinsics, 667 trampolines: linearize.trampolines, 668 num_lowerings: linearize.num_lowerings, 669 options: linearize.options, 670 671 num_runtime_memories: linearize.runtime_memories.len() as u32, 672 num_runtime_tables: linearize.runtime_tables.len() as u32, 673 num_runtime_post_returns: linearize.runtime_post_return.len() as u32, 674 num_runtime_reallocs: linearize.runtime_reallocs.len() as u32, 675 num_runtime_callbacks: linearize.runtime_callbacks.len() as u32, 676 num_runtime_instances: linearize.runtime_instances.len() as u32, 677 imports: self.imports, 678 import_types: self.import_types, 679 num_runtime_component_instances: self.num_runtime_component_instances, 680 num_future_tables: self.num_future_tables, 681 num_stream_tables: self.num_stream_tables, 682 num_error_context_tables: self.num_error_context_tables, 683 num_resources: (self.resources.len() + self.imported_resources.len()) as u32, 684 imported_resources: self.imported_resources, 685 defined_resource_instances: self 686 .resources 687 .iter() 688 .map(|(_, r)| r.instance) 689 .collect(), 690 }, 691 }) 692 } 693 694 /// Converts the provided defined index into a normal index, adding in the 695 /// number of imported resources. resource_index(&self, defined: DefinedResourceIndex) -> ResourceIndex696 pub fn resource_index(&self, defined: DefinedResourceIndex) -> ResourceIndex { 697 ResourceIndex::from_u32(defined.as_u32() + (self.imported_resources.len() as u32)) 698 } 699 } 700 701 struct LinearizeDfg<'a> { 702 dfg: &'a ComponentDfg, 703 initializers: Vec<GlobalInitializer>, 704 unsafe_intrinsics: [PackedOption<ModuleInternedTypeIndex>; UnsafeIntrinsic::len() as usize], 705 trampolines: PrimaryMap<TrampolineIndex, ModuleInternedTypeIndex>, 706 trampoline_defs: PrimaryMap<TrampolineIndex, info::Trampoline>, 707 options: PrimaryMap<OptionsIndex, info::CanonicalOptions>, 708 trampoline_map: HashMap<TrampolineIndex, TrampolineIndex>, 709 runtime_memories: HashMap<MemoryId, RuntimeMemoryIndex>, 710 runtime_tables: HashMap<TableId, RuntimeTableIndex>, 711 runtime_reallocs: HashMap<ReallocId, RuntimeReallocIndex>, 712 runtime_callbacks: HashMap<CallbackId, RuntimeCallbackIndex>, 713 runtime_post_return: HashMap<PostReturnId, RuntimePostReturnIndex>, 714 runtime_instances: HashMap<RuntimeInstance, RuntimeInstanceIndex>, 715 options_map: HashMap<OptionsId, OptionsIndex>, 716 num_lowerings: u32, 717 } 718 719 #[derive(Copy, Clone, Hash, Eq, PartialEq)] 720 enum RuntimeInstance { 721 Normal(InstanceId), 722 Adapter(AdapterModuleId), 723 } 724 725 impl LinearizeDfg<'_> { side_effect(&mut self, effect: &SideEffect)726 fn side_effect(&mut self, effect: &SideEffect) { 727 match effect { 728 SideEffect::Instance(i, ci) => { 729 self.instantiate(*i, &self.dfg.instances[*i], *ci); 730 } 731 SideEffect::Resource(i) => { 732 self.resource(*i, &self.dfg.resources[*i]); 733 } 734 } 735 } 736 instantiate( &mut self, instance: InstanceId, args: &Instance, component_instance: RuntimeComponentInstanceIndex, )737 fn instantiate( 738 &mut self, 739 instance: InstanceId, 740 args: &Instance, 741 component_instance: RuntimeComponentInstanceIndex, 742 ) { 743 log::trace!("creating instance {instance:?}"); 744 let instantiation = match args { 745 Instance::Static(index, args) => InstantiateModule::Static( 746 *index, 747 args.iter().map(|def| self.core_def(def)).collect(), 748 ), 749 Instance::Import(index, args) => InstantiateModule::Import( 750 *index, 751 args.iter() 752 .map(|(module, values)| { 753 let values = values 754 .iter() 755 .map(|(name, def)| (name.clone(), self.core_def(def))) 756 .collect(); 757 (module.clone(), values) 758 }) 759 .collect(), 760 ), 761 }; 762 let index = RuntimeInstanceIndex::new(self.runtime_instances.len()); 763 self.initializers.push(GlobalInitializer::InstantiateModule( 764 instantiation, 765 Some(component_instance), 766 )); 767 let prev = self 768 .runtime_instances 769 .insert(RuntimeInstance::Normal(instance), index); 770 assert!(prev.is_none()); 771 } 772 resource(&mut self, index: DefinedResourceIndex, resource: &Resource)773 fn resource(&mut self, index: DefinedResourceIndex, resource: &Resource) { 774 let dtor = resource.dtor.as_ref().map(|dtor| self.core_def(dtor)); 775 self.initializers 776 .push(GlobalInitializer::Resource(info::Resource { 777 dtor, 778 index, 779 rep: resource.rep, 780 instance: resource.instance, 781 })); 782 } 783 export( &mut self, export: &Export, items: &mut PrimaryMap<ExportIndex, info::Export>, wasmtime_types: &mut ComponentTypesBuilder, wasmparser_types: wasmparser::types::TypesRef<'_>, ) -> Result<ExportIndex>784 fn export( 785 &mut self, 786 export: &Export, 787 items: &mut PrimaryMap<ExportIndex, info::Export>, 788 wasmtime_types: &mut ComponentTypesBuilder, 789 wasmparser_types: wasmparser::types::TypesRef<'_>, 790 ) -> Result<ExportIndex> { 791 let item = match export { 792 Export::LiftedFunction { ty, func, options } => { 793 let func = self.core_def(func); 794 let options = self.options(*options); 795 info::Export::LiftedFunction { 796 ty: *ty, 797 func, 798 options, 799 } 800 } 801 Export::ModuleStatic { ty, index } => info::Export::ModuleStatic { 802 ty: wasmtime_types.convert_module(wasmparser_types, *ty)?, 803 index: *index, 804 }, 805 Export::ModuleImport { ty, import } => info::Export::ModuleImport { 806 ty: *ty, 807 import: *import, 808 }, 809 Export::Instance { ty, exports } => info::Export::Instance { 810 ty: *ty, 811 exports: { 812 let mut map = NameMap::default(); 813 for (name, export) in exports { 814 let export = 815 self.export(export, items, wasmtime_types, wasmparser_types)?; 816 map.insert(name, &mut NameMapNoIntern, false, export)?; 817 } 818 map 819 }, 820 }, 821 Export::Type(def) => info::Export::Type(*def), 822 }; 823 Ok(items.push(item)) 824 } 825 options(&mut self, options: OptionsId) -> OptionsIndex826 fn options(&mut self, options: OptionsId) -> OptionsIndex { 827 self.intern_no_init( 828 options, 829 |me| &mut me.options_map, 830 |me, options| me.convert_options(options), 831 ) 832 } 833 convert_options(&mut self, options: OptionsId) -> OptionsIndex834 fn convert_options(&mut self, options: OptionsId) -> OptionsIndex { 835 let options = &self.dfg.options[options]; 836 let data_model = match options.data_model { 837 CanonicalOptionsDataModel::Gc {} => info::CanonicalOptionsDataModel::Gc {}, 838 CanonicalOptionsDataModel::LinearMemory { memory, realloc } => { 839 info::CanonicalOptionsDataModel::LinearMemory(LinearMemoryOptions { 840 memory: memory.map(|mem| self.runtime_memory(mem)), 841 realloc: realloc.map(|mem| self.runtime_realloc(mem)), 842 }) 843 } 844 }; 845 let callback = options.callback.map(|mem| self.runtime_callback(mem)); 846 let post_return = options.post_return.map(|mem| self.runtime_post_return(mem)); 847 let options = info::CanonicalOptions { 848 instance: options.instance, 849 string_encoding: options.string_encoding, 850 callback, 851 post_return, 852 async_: options.async_, 853 cancellable: options.cancellable, 854 core_type: options.core_type, 855 data_model, 856 }; 857 self.options.push(options) 858 } 859 runtime_memory(&mut self, mem: MemoryId) -> RuntimeMemoryIndex860 fn runtime_memory(&mut self, mem: MemoryId) -> RuntimeMemoryIndex { 861 self.intern( 862 mem, 863 |me| &mut me.runtime_memories, 864 |me, mem| me.core_export(&me.dfg.memories[mem]), 865 |index, export| GlobalInitializer::ExtractMemory(ExtractMemory { index, export }), 866 ) 867 } 868 runtime_table(&mut self, table: TableId) -> RuntimeTableIndex869 fn runtime_table(&mut self, table: TableId) -> RuntimeTableIndex { 870 self.intern( 871 table, 872 |me| &mut me.runtime_tables, 873 |me, table| me.core_export(&me.dfg.tables[table]), 874 |index, export| GlobalInitializer::ExtractTable(ExtractTable { index, export }), 875 ) 876 } 877 runtime_realloc(&mut self, realloc: ReallocId) -> RuntimeReallocIndex878 fn runtime_realloc(&mut self, realloc: ReallocId) -> RuntimeReallocIndex { 879 self.intern( 880 realloc, 881 |me| &mut me.runtime_reallocs, 882 |me, realloc| me.core_def(&me.dfg.reallocs[realloc]), 883 |index, def| GlobalInitializer::ExtractRealloc(ExtractRealloc { index, def }), 884 ) 885 } 886 runtime_callback(&mut self, callback: CallbackId) -> RuntimeCallbackIndex887 fn runtime_callback(&mut self, callback: CallbackId) -> RuntimeCallbackIndex { 888 self.intern( 889 callback, 890 |me| &mut me.runtime_callbacks, 891 |me, callback| me.core_def(&me.dfg.callbacks[callback]), 892 |index, def| GlobalInitializer::ExtractCallback(ExtractCallback { index, def }), 893 ) 894 } 895 runtime_post_return(&mut self, post_return: PostReturnId) -> RuntimePostReturnIndex896 fn runtime_post_return(&mut self, post_return: PostReturnId) -> RuntimePostReturnIndex { 897 self.intern( 898 post_return, 899 |me| &mut me.runtime_post_return, 900 |me, post_return| me.core_def(&me.dfg.post_returns[post_return]), 901 |index, def| GlobalInitializer::ExtractPostReturn(ExtractPostReturn { index, def }), 902 ) 903 } 904 core_def(&mut self, def: &CoreDef) -> info::CoreDef905 fn core_def(&mut self, def: &CoreDef) -> info::CoreDef { 906 match def { 907 CoreDef::Export(e) => info::CoreDef::Export(self.core_export(e)), 908 CoreDef::InstanceFlags(i) => info::CoreDef::InstanceFlags(*i), 909 CoreDef::Adapter(id) => info::CoreDef::Export(self.adapter(*id)), 910 CoreDef::Trampoline(index) => info::CoreDef::Trampoline(self.trampoline(*index)), 911 CoreDef::UnsafeIntrinsic(ty, i) => { 912 let index = usize::try_from(i.index()).unwrap(); 913 if self.unsafe_intrinsics[index].is_none() { 914 self.unsafe_intrinsics[index] = Some(*ty).into(); 915 } 916 info::CoreDef::UnsafeIntrinsic(*i) 917 } 918 CoreDef::TaskMayBlock => info::CoreDef::TaskMayBlock, 919 } 920 } 921 trampoline(&mut self, index: TrampolineIndex) -> TrampolineIndex922 fn trampoline(&mut self, index: TrampolineIndex) -> TrampolineIndex { 923 if let Some(idx) = self.trampoline_map.get(&index) { 924 return *idx; 925 } 926 let (signature, trampoline) = &self.dfg.trampolines[index]; 927 let trampoline = match trampoline { 928 Trampoline::LowerImport { 929 import, 930 options, 931 lower_ty, 932 } => { 933 let index = LoweredIndex::from_u32(self.num_lowerings); 934 self.num_lowerings += 1; 935 self.initializers.push(GlobalInitializer::LowerImport { 936 index, 937 import: *import, 938 }); 939 info::Trampoline::LowerImport { 940 index, 941 options: self.options(*options), 942 lower_ty: *lower_ty, 943 } 944 } 945 Trampoline::Transcoder { 946 op, 947 from, 948 from64, 949 to, 950 to64, 951 } => info::Trampoline::Transcoder { 952 op: *op, 953 from: self.runtime_memory(*from), 954 from64: *from64, 955 to: self.runtime_memory(*to), 956 to64: *to64, 957 }, 958 Trampoline::ResourceNew { instance, ty } => info::Trampoline::ResourceNew { 959 instance: *instance, 960 ty: *ty, 961 }, 962 Trampoline::ResourceDrop { instance, ty } => info::Trampoline::ResourceDrop { 963 instance: *instance, 964 ty: *ty, 965 }, 966 Trampoline::ResourceRep { instance, ty } => info::Trampoline::ResourceRep { 967 instance: *instance, 968 ty: *ty, 969 }, 970 Trampoline::BackpressureInc { instance } => info::Trampoline::BackpressureInc { 971 instance: *instance, 972 }, 973 Trampoline::BackpressureDec { instance } => info::Trampoline::BackpressureDec { 974 instance: *instance, 975 }, 976 Trampoline::TaskReturn { 977 instance, 978 results, 979 options, 980 } => info::Trampoline::TaskReturn { 981 instance: *instance, 982 results: *results, 983 options: self.options(*options), 984 }, 985 Trampoline::TaskCancel { instance } => info::Trampoline::TaskCancel { 986 instance: *instance, 987 }, 988 Trampoline::WaitableSetNew { instance } => info::Trampoline::WaitableSetNew { 989 instance: *instance, 990 }, 991 Trampoline::WaitableSetWait { instance, options } => { 992 info::Trampoline::WaitableSetWait { 993 instance: *instance, 994 options: self.options(*options), 995 } 996 } 997 Trampoline::WaitableSetPoll { instance, options } => { 998 info::Trampoline::WaitableSetPoll { 999 instance: *instance, 1000 options: self.options(*options), 1001 } 1002 } 1003 Trampoline::WaitableSetDrop { instance } => info::Trampoline::WaitableSetDrop { 1004 instance: *instance, 1005 }, 1006 Trampoline::WaitableJoin { instance } => info::Trampoline::WaitableJoin { 1007 instance: *instance, 1008 }, 1009 Trampoline::ThreadYield { 1010 instance, 1011 cancellable, 1012 } => info::Trampoline::ThreadYield { 1013 instance: *instance, 1014 cancellable: *cancellable, 1015 }, 1016 Trampoline::SubtaskDrop { instance } => info::Trampoline::SubtaskDrop { 1017 instance: *instance, 1018 }, 1019 Trampoline::SubtaskCancel { instance, async_ } => info::Trampoline::SubtaskCancel { 1020 instance: *instance, 1021 async_: *async_, 1022 }, 1023 Trampoline::StreamNew { instance, ty } => info::Trampoline::StreamNew { 1024 instance: *instance, 1025 ty: *ty, 1026 }, 1027 Trampoline::StreamRead { 1028 instance, 1029 ty, 1030 options, 1031 } => info::Trampoline::StreamRead { 1032 instance: *instance, 1033 ty: *ty, 1034 options: self.options(*options), 1035 }, 1036 Trampoline::StreamWrite { 1037 instance, 1038 ty, 1039 options, 1040 } => info::Trampoline::StreamWrite { 1041 instance: *instance, 1042 ty: *ty, 1043 options: self.options(*options), 1044 }, 1045 Trampoline::StreamCancelRead { 1046 instance, 1047 ty, 1048 async_, 1049 } => info::Trampoline::StreamCancelRead { 1050 instance: *instance, 1051 ty: *ty, 1052 async_: *async_, 1053 }, 1054 Trampoline::StreamCancelWrite { 1055 instance, 1056 ty, 1057 async_, 1058 } => info::Trampoline::StreamCancelWrite { 1059 instance: *instance, 1060 ty: *ty, 1061 async_: *async_, 1062 }, 1063 Trampoline::StreamDropReadable { instance, ty } => { 1064 info::Trampoline::StreamDropReadable { 1065 instance: *instance, 1066 ty: *ty, 1067 } 1068 } 1069 Trampoline::StreamDropWritable { instance, ty } => { 1070 info::Trampoline::StreamDropWritable { 1071 instance: *instance, 1072 ty: *ty, 1073 } 1074 } 1075 Trampoline::FutureNew { instance, ty } => info::Trampoline::FutureNew { 1076 instance: *instance, 1077 ty: *ty, 1078 }, 1079 Trampoline::FutureRead { 1080 instance, 1081 ty, 1082 options, 1083 } => info::Trampoline::FutureRead { 1084 instance: *instance, 1085 ty: *ty, 1086 options: self.options(*options), 1087 }, 1088 Trampoline::FutureWrite { 1089 instance, 1090 ty, 1091 options, 1092 } => info::Trampoline::FutureWrite { 1093 instance: *instance, 1094 ty: *ty, 1095 options: self.options(*options), 1096 }, 1097 Trampoline::FutureCancelRead { 1098 instance, 1099 ty, 1100 async_, 1101 } => info::Trampoline::FutureCancelRead { 1102 instance: *instance, 1103 ty: *ty, 1104 async_: *async_, 1105 }, 1106 Trampoline::FutureCancelWrite { 1107 instance, 1108 ty, 1109 async_, 1110 } => info::Trampoline::FutureCancelWrite { 1111 instance: *instance, 1112 ty: *ty, 1113 async_: *async_, 1114 }, 1115 Trampoline::FutureDropReadable { instance, ty } => { 1116 info::Trampoline::FutureDropReadable { 1117 instance: *instance, 1118 ty: *ty, 1119 } 1120 } 1121 Trampoline::FutureDropWritable { instance, ty } => { 1122 info::Trampoline::FutureDropWritable { 1123 instance: *instance, 1124 ty: *ty, 1125 } 1126 } 1127 Trampoline::ErrorContextNew { 1128 instance, 1129 ty, 1130 options, 1131 } => info::Trampoline::ErrorContextNew { 1132 instance: *instance, 1133 ty: *ty, 1134 options: self.options(*options), 1135 }, 1136 Trampoline::ErrorContextDebugMessage { 1137 instance, 1138 ty, 1139 options, 1140 } => info::Trampoline::ErrorContextDebugMessage { 1141 instance: *instance, 1142 ty: *ty, 1143 options: self.options(*options), 1144 }, 1145 Trampoline::ErrorContextDrop { instance, ty } => info::Trampoline::ErrorContextDrop { 1146 instance: *instance, 1147 ty: *ty, 1148 }, 1149 Trampoline::ResourceTransferOwn => info::Trampoline::ResourceTransferOwn, 1150 Trampoline::ResourceTransferBorrow => info::Trampoline::ResourceTransferBorrow, 1151 Trampoline::PrepareCall { memory } => info::Trampoline::PrepareCall { 1152 memory: memory.map(|v| self.runtime_memory(v)), 1153 }, 1154 Trampoline::SyncStartCall { callback } => info::Trampoline::SyncStartCall { 1155 callback: callback.map(|v| self.runtime_callback(v)), 1156 }, 1157 Trampoline::AsyncStartCall { 1158 callback, 1159 post_return, 1160 } => info::Trampoline::AsyncStartCall { 1161 callback: callback.map(|v| self.runtime_callback(v)), 1162 post_return: post_return.map(|v| self.runtime_post_return(v)), 1163 }, 1164 Trampoline::FutureTransfer => info::Trampoline::FutureTransfer, 1165 Trampoline::StreamTransfer => info::Trampoline::StreamTransfer, 1166 Trampoline::ErrorContextTransfer => info::Trampoline::ErrorContextTransfer, 1167 Trampoline::Trap => info::Trampoline::Trap, 1168 Trampoline::EnterSyncCall => info::Trampoline::EnterSyncCall, 1169 Trampoline::ExitSyncCall => info::Trampoline::ExitSyncCall, 1170 Trampoline::ContextGet { instance, slot } => info::Trampoline::ContextGet { 1171 instance: *instance, 1172 slot: *slot, 1173 }, 1174 Trampoline::ContextSet { instance, slot } => info::Trampoline::ContextSet { 1175 instance: *instance, 1176 slot: *slot, 1177 }, 1178 Trampoline::ThreadIndex => info::Trampoline::ThreadIndex, 1179 Trampoline::ThreadNewIndirect { 1180 instance, 1181 start_func_ty_idx, 1182 start_func_table_id, 1183 } => info::Trampoline::ThreadNewIndirect { 1184 instance: *instance, 1185 start_func_ty_idx: *start_func_ty_idx, 1186 start_func_table_idx: self.runtime_table(*start_func_table_id), 1187 }, 1188 Trampoline::ThreadSuspendToSuspended { 1189 instance, 1190 cancellable, 1191 } => info::Trampoline::ThreadSuspendToSuspended { 1192 instance: *instance, 1193 cancellable: *cancellable, 1194 }, 1195 Trampoline::ThreadSuspendTo { 1196 instance, 1197 cancellable, 1198 } => info::Trampoline::ThreadSuspendTo { 1199 instance: *instance, 1200 cancellable: *cancellable, 1201 }, 1202 Trampoline::ThreadSuspend { 1203 instance, 1204 cancellable, 1205 } => info::Trampoline::ThreadSuspend { 1206 instance: *instance, 1207 cancellable: *cancellable, 1208 }, 1209 Trampoline::ThreadUnsuspend { instance } => info::Trampoline::ThreadUnsuspend { 1210 instance: *instance, 1211 }, 1212 Trampoline::ThreadYieldToSuspended { 1213 instance, 1214 cancellable, 1215 } => info::Trampoline::ThreadYieldToSuspended { 1216 instance: *instance, 1217 cancellable: *cancellable, 1218 }, 1219 }; 1220 let i1 = self.trampolines.push(*signature); 1221 let i2 = self.trampoline_defs.push(trampoline); 1222 assert_eq!(i1, i2); 1223 self.trampoline_map.insert(index, i1); 1224 i1 1225 } 1226 core_export<T>(&mut self, export: &CoreExport<T>) -> info::CoreExport<T> where T: Clone,1227 fn core_export<T>(&mut self, export: &CoreExport<T>) -> info::CoreExport<T> 1228 where 1229 T: Clone, 1230 { 1231 let instance = export.instance; 1232 log::trace!("referencing export of {instance:?}"); 1233 info::CoreExport { 1234 instance: self.runtime_instances[&RuntimeInstance::Normal(instance)], 1235 item: export.item.clone(), 1236 } 1237 } 1238 adapter(&mut self, adapter: AdapterId) -> info::CoreExport<EntityIndex>1239 fn adapter(&mut self, adapter: AdapterId) -> info::CoreExport<EntityIndex> { 1240 let (adapter_module, entity_index) = self.dfg.adapter_partitionings[adapter]; 1241 1242 // Instantiates the adapter module if it hasn't already been 1243 // instantiated or otherwise returns the index that the module was 1244 // already instantiated at. 1245 let instance = self.adapter_module(adapter_module); 1246 1247 // This adapter is always an export of the instance. 1248 info::CoreExport { 1249 instance, 1250 item: ExportItem::Index(entity_index), 1251 } 1252 } 1253 adapter_module(&mut self, adapter_module: AdapterModuleId) -> RuntimeInstanceIndex1254 fn adapter_module(&mut self, adapter_module: AdapterModuleId) -> RuntimeInstanceIndex { 1255 self.intern( 1256 RuntimeInstance::Adapter(adapter_module), 1257 |me| &mut me.runtime_instances, 1258 |me, _| { 1259 log::debug!("instantiating {adapter_module:?}"); 1260 let (module_index, args) = &me.dfg.adapter_modules[adapter_module]; 1261 let args = args.iter().map(|arg| me.core_def(arg)).collect(); 1262 let instantiate = InstantiateModule::Static(*module_index, args); 1263 GlobalInitializer::InstantiateModule(instantiate, None) 1264 }, 1265 |_, init| init, 1266 ) 1267 } 1268 1269 /// Helper function to manage interning of results to avoid duplicate 1270 /// initializers being inserted into the final list. 1271 /// 1272 /// * `key` - the key being referenced which is used to deduplicate. 1273 /// * `map` - a closure to access the interning map on `Self` 1274 /// * `gen` - a closure to generate an intermediate value with `Self` from 1275 /// `K`. This is only used if `key` hasn't previously been seen. This 1276 /// closure can recursively intern other values possibly. 1277 /// * `init` - a closure to use the result of `gen` to create the final 1278 /// initializer now that the index `V` of the runtime item is known. 1279 /// 1280 /// This is used by all the other interning methods above to lazily append 1281 /// initializers on-demand and avoid pushing more than one initializer at a 1282 /// time. intern<K, V, T>( &mut self, key: K, map: impl Fn(&mut Self) -> &mut HashMap<K, V>, generate: impl FnOnce(&mut Self, K) -> T, init: impl FnOnce(V, T) -> GlobalInitializer, ) -> V where K: Hash + Eq + Copy, V: EntityRef,1283 fn intern<K, V, T>( 1284 &mut self, 1285 key: K, 1286 map: impl Fn(&mut Self) -> &mut HashMap<K, V>, 1287 generate: impl FnOnce(&mut Self, K) -> T, 1288 init: impl FnOnce(V, T) -> GlobalInitializer, 1289 ) -> V 1290 where 1291 K: Hash + Eq + Copy, 1292 V: EntityRef, 1293 { 1294 self.intern_(key, map, generate, |me, key, val| { 1295 me.initializers.push(init(key, val)); 1296 }) 1297 } 1298 intern_no_init<K, V, T>( &mut self, key: K, map: impl Fn(&mut Self) -> &mut HashMap<K, V>, generate: impl FnOnce(&mut Self, K) -> T, ) -> V where K: Hash + Eq + Copy, V: EntityRef,1299 fn intern_no_init<K, V, T>( 1300 &mut self, 1301 key: K, 1302 map: impl Fn(&mut Self) -> &mut HashMap<K, V>, 1303 generate: impl FnOnce(&mut Self, K) -> T, 1304 ) -> V 1305 where 1306 K: Hash + Eq + Copy, 1307 V: EntityRef, 1308 { 1309 self.intern_(key, map, generate, |_me, _key, _val| {}) 1310 } 1311 intern_<K, V, T>( &mut self, key: K, map: impl Fn(&mut Self) -> &mut HashMap<K, V>, generate: impl FnOnce(&mut Self, K) -> T, init: impl FnOnce(&mut Self, V, T), ) -> V where K: Hash + Eq + Copy, V: EntityRef,1312 fn intern_<K, V, T>( 1313 &mut self, 1314 key: K, 1315 map: impl Fn(&mut Self) -> &mut HashMap<K, V>, 1316 generate: impl FnOnce(&mut Self, K) -> T, 1317 init: impl FnOnce(&mut Self, V, T), 1318 ) -> V 1319 where 1320 K: Hash + Eq + Copy, 1321 V: EntityRef, 1322 { 1323 if let Some(val) = map(self).get(&key) { 1324 return *val; 1325 } 1326 let tmp = generate(self, key); 1327 let index = V::new(map(self).len()); 1328 init(self, index, tmp); 1329 let prev = map(self).insert(key, index); 1330 assert!(prev.is_none()); 1331 index 1332 } 1333 } 1334