Skip to main content

wasmtime_environ/component/
dfg.rs

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