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