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::prelude::*;
32use crate::{EntityIndex, EntityRef, ModuleInternedTypeIndex, PrimaryMap, WasmValType};
33use anyhow::Result;
34use indexmap::IndexMap;
35use std::collections::HashMap;
36use std::hash::Hash;
37use std::ops::Index;
38use wasmparser::component_types::ComponentCoreModuleTypeId;
39
40/// High-level representation of a component as a "data-flow graph".
41#[derive(Default)]
42pub struct ComponentDfg {
43    /// Same as `Component::import_types`
44    pub import_types: PrimaryMap<ImportIndex, (String, TypeDef)>,
45
46    /// Same as `Component::imports`
47    pub imports: PrimaryMap<RuntimeImportIndex, (ImportIndex, Vec<String>)>,
48
49    /// Same as `Component::exports`
50    pub exports: IndexMap<String, Export>,
51
52    /// All trampolines and their type signature which will need to get
53    /// compiled by Cranelift.
54    pub trampolines: Intern<TrampolineIndex, (ModuleInternedTypeIndex, Trampoline)>,
55
56    /// Know reallocation functions which are used by `lowerings` (e.g. will be
57    /// used by the host)
58    pub reallocs: Intern<ReallocId, CoreDef>,
59
60    /// Same as `reallocs`, but for async-lifted functions.
61    pub callbacks: Intern<CallbackId, CoreDef>,
62
63    /// Same as `reallocs`, but for post-return.
64    pub post_returns: Intern<PostReturnId, CoreDef>,
65
66    /// Same as `reallocs`, but for post-return.
67    pub memories: Intern<MemoryId, CoreExport<MemoryIndex>>,
68
69    /// Metadata about identified fused adapters.
70    ///
71    /// Note that this list is required to be populated in-order where the
72    /// "left" adapters cannot depend on "right" adapters. Currently this falls
73    /// out of the inlining pass of translation.
74    pub adapters: Intern<AdapterId, Adapter>,
75
76    /// Metadata about all known core wasm instances created.
77    ///
78    /// This is mostly an ordered list and is not deduplicated based on contents
79    /// unlike the items above. Creation of an `Instance` is side-effectful and
80    /// all instances here are always required to be created. These are
81    /// considered "roots" in dataflow.
82    pub instances: PrimaryMap<InstanceId, Instance>,
83
84    /// Number of component instances that were created during the inlining
85    /// phase (this is not edited after creation).
86    pub num_runtime_component_instances: u32,
87
88    /// Known adapter modules and how they are instantiated.
89    ///
90    /// This map is not filled in on the initial creation of a `ComponentDfg`.
91    /// Instead these modules are filled in by the `inline::adapt` phase where
92    /// adapter modules are identified and filled in here.
93    ///
94    /// The payload here is the static module index representing the core wasm
95    /// adapter module that was generated as well as the arguments to the
96    /// instantiation of the adapter module.
97    pub adapter_modules: PrimaryMap<AdapterModuleId, (StaticModuleIndex, Vec<CoreDef>)>,
98
99    /// Metadata about where adapters can be found within their respective
100    /// adapter modules.
101    ///
102    /// Like `adapter_modules` this is not filled on the initial creation of
103    /// `ComponentDfg` but rather is created alongside `adapter_modules` during
104    /// the `inline::adapt` phase of translation.
105    ///
106    /// The values here are the module that the adapter is present within along
107    /// as the core wasm index of the export corresponding to the lowered
108    /// version of the adapter.
109    pub adapter_partitionings: PrimaryMap<AdapterId, (AdapterModuleId, EntityIndex)>,
110
111    /// Defined resources in this component sorted by index with metadata about
112    /// each resource.
113    ///
114    /// Note that each index here is a unique resource, and that may mean it was
115    /// the same component instantiated twice for example.
116    pub resources: PrimaryMap<DefinedResourceIndex, Resource>,
117
118    /// Metadata about all imported resources into this component. This records
119    /// both how many imported resources there are (the size of this map) along
120    /// with what the corresponding runtime import is.
121    pub imported_resources: PrimaryMap<ResourceIndex, RuntimeImportIndex>,
122
123    /// The total number of resource tables that will be used by this component,
124    /// currently the number of unique `TypeResourceTableIndex` allocations for
125    /// this component.
126    pub num_resource_tables: usize,
127
128    /// The total number of future tables that will be used by this component.
129    pub num_future_tables: usize,
130
131    /// The total number of stream tables that will be used by this component.
132    pub num_stream_tables: usize,
133
134    /// The total number of error-context tables that will be used by this
135    /// component.
136    pub num_error_context_tables: usize,
137
138    /// An ordered list of side effects induced by instantiating this component.
139    ///
140    /// Currently all side effects are either instantiating core wasm modules or
141    /// declaring a resource. These side effects affect the dataflow processing
142    /// of this component by idnicating what order operations should be
143    /// performed during instantiation.
144    pub side_effects: Vec<SideEffect>,
145}
146
147/// Possible side effects that are possible with instantiating this component.
148pub enum SideEffect {
149    /// A core wasm instance was created.
150    ///
151    /// Instantiation is side-effectful due to the presence of constructs such
152    /// as traps and the core wasm `start` function which may call component
153    /// imports. Instantiation order from the original component must be done in
154    /// the same order.
155    Instance(InstanceId),
156
157    /// A resource was declared in this component.
158    ///
159    /// This is a bit less side-effectful than instantiation but this serves as
160    /// the order in which resources are initialized in a component with their
161    /// destructors. Destructors are loaded from core wasm instances (or
162    /// lowerings) which are produced by prior side-effectful operations.
163    Resource(DefinedResourceIndex),
164}
165
166macro_rules! id {
167    ($(pub struct $name:ident(u32);)*) => ($(
168        #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
169        #[expect(missing_docs, reason = "tedious to document")]
170        pub struct $name(u32);
171        cranelift_entity::entity_impl!($name);
172    )*)
173}
174
175id! {
176    pub struct InstanceId(u32);
177    pub struct MemoryId(u32);
178    pub struct TableId(u32);
179    pub struct ReallocId(u32);
180    pub struct CallbackId(u32);
181    pub struct AdapterId(u32);
182    pub struct PostReturnId(u32);
183    pub struct AdapterModuleId(u32);
184}
185
186/// Same as `info::InstantiateModule`
187#[expect(missing_docs, reason = "tedious to document variants")]
188pub enum Instance {
189    Static(StaticModuleIndex, Box<[CoreDef]>),
190    Import(
191        RuntimeImportIndex,
192        IndexMap<String, IndexMap<String, CoreDef>>,
193    ),
194}
195
196/// Same as `info::Export`
197#[expect(missing_docs, reason = "tedious to document variants")]
198pub enum Export {
199    LiftedFunction {
200        ty: TypeFuncIndex,
201        func: CoreDef,
202        options: CanonicalOptions,
203    },
204    ModuleStatic {
205        ty: ComponentCoreModuleTypeId,
206        index: StaticModuleIndex,
207    },
208    ModuleImport {
209        ty: TypeModuleIndex,
210        import: RuntimeImportIndex,
211    },
212    Instance {
213        ty: TypeComponentInstanceIndex,
214        exports: IndexMap<String, Export>,
215    },
216    Type(TypeDef),
217}
218
219/// Same as `info::CoreDef`, except has an extra `Adapter` variant.
220#[derive(Debug, Clone, Hash, Eq, PartialEq)]
221#[expect(missing_docs, reason = "tedious to document variants")]
222pub enum CoreDef {
223    Export(CoreExport<EntityIndex>),
224    InstanceFlags(RuntimeComponentInstanceIndex),
225    Trampoline(TrampolineIndex),
226    /// This is a special variant not present in `info::CoreDef` which
227    /// represents that this definition refers to a fused adapter function. This
228    /// adapter is fully processed after the initial translation and
229    /// identification of adapters.
230    ///
231    /// During translation into `info::CoreDef` this variant is erased and
232    /// replaced by `info::CoreDef::Export` since adapters are always
233    /// represented as the exports of a core wasm instance.
234    Adapter(AdapterId),
235}
236
237impl<T> From<CoreExport<T>> for CoreDef
238where
239    EntityIndex: From<T>,
240{
241    fn from(export: CoreExport<T>) -> CoreDef {
242        CoreDef::Export(export.map_index(|i| i.into()))
243    }
244}
245
246/// Same as `info::CoreExport`
247#[derive(Debug, Clone, Hash, Eq, PartialEq)]
248#[expect(missing_docs, reason = "self-describing fields")]
249pub struct CoreExport<T> {
250    pub instance: InstanceId,
251    pub item: ExportItem<T>,
252}
253
254impl<T> CoreExport<T> {
255    #[expect(missing_docs, reason = "self-describing function")]
256    pub fn map_index<U>(self, f: impl FnOnce(T) -> U) -> CoreExport<U> {
257        CoreExport {
258            instance: self.instance,
259            item: match self.item {
260                ExportItem::Index(i) => ExportItem::Index(f(i)),
261                ExportItem::Name(s) => ExportItem::Name(s),
262            },
263        }
264    }
265}
266
267/// Same as `info::Trampoline`
268#[derive(Clone, PartialEq, Eq, Hash)]
269#[expect(missing_docs, reason = "self-describing fields")]
270pub enum Trampoline {
271    LowerImport {
272        import: RuntimeImportIndex,
273        options: CanonicalOptions,
274        lower_ty: TypeFuncIndex,
275    },
276    Transcoder {
277        op: Transcode,
278        from: MemoryId,
279        from64: bool,
280        to: MemoryId,
281        to64: bool,
282    },
283    AlwaysTrap,
284    ResourceNew(TypeResourceTableIndex),
285    ResourceRep(TypeResourceTableIndex),
286    ResourceDrop(TypeResourceTableIndex),
287    BackpressureSet {
288        instance: RuntimeComponentInstanceIndex,
289    },
290    TaskReturn {
291        results: TypeTupleIndex,
292        options: CanonicalOptions,
293    },
294    WaitableSetNew {
295        instance: RuntimeComponentInstanceIndex,
296    },
297    WaitableSetWait {
298        instance: RuntimeComponentInstanceIndex,
299        async_: bool,
300        memory: MemoryId,
301    },
302    WaitableSetPoll {
303        instance: RuntimeComponentInstanceIndex,
304        async_: bool,
305        memory: MemoryId,
306    },
307    WaitableSetDrop {
308        instance: RuntimeComponentInstanceIndex,
309    },
310    WaitableJoin {
311        instance: RuntimeComponentInstanceIndex,
312    },
313    Yield {
314        async_: bool,
315    },
316    SubtaskDrop {
317        instance: RuntimeComponentInstanceIndex,
318    },
319    StreamNew {
320        ty: TypeStreamTableIndex,
321    },
322    StreamRead {
323        ty: TypeStreamTableIndex,
324        options: CanonicalOptions,
325    },
326    StreamWrite {
327        ty: TypeStreamTableIndex,
328        options: CanonicalOptions,
329    },
330    StreamCancelRead {
331        ty: TypeStreamTableIndex,
332        async_: bool,
333    },
334    StreamCancelWrite {
335        ty: TypeStreamTableIndex,
336        async_: bool,
337    },
338    StreamCloseReadable {
339        ty: TypeStreamTableIndex,
340    },
341    StreamCloseWritable {
342        ty: TypeStreamTableIndex,
343    },
344    FutureNew {
345        ty: TypeFutureTableIndex,
346    },
347    FutureRead {
348        ty: TypeFutureTableIndex,
349        options: CanonicalOptions,
350    },
351    FutureWrite {
352        ty: TypeFutureTableIndex,
353        options: CanonicalOptions,
354    },
355    FutureCancelRead {
356        ty: TypeFutureTableIndex,
357        async_: bool,
358    },
359    FutureCancelWrite {
360        ty: TypeFutureTableIndex,
361        async_: bool,
362    },
363    FutureCloseReadable {
364        ty: TypeFutureTableIndex,
365    },
366    FutureCloseWritable {
367        ty: TypeFutureTableIndex,
368    },
369    ErrorContextNew {
370        ty: TypeComponentLocalErrorContextTableIndex,
371        options: CanonicalOptions,
372    },
373    ErrorContextDebugMessage {
374        ty: TypeComponentLocalErrorContextTableIndex,
375        options: CanonicalOptions,
376    },
377    ErrorContextDrop {
378        ty: TypeComponentLocalErrorContextTableIndex,
379    },
380    ResourceTransferOwn,
381    ResourceTransferBorrow,
382    ResourceEnterCall,
383    ResourceExitCall,
384    SyncEnterCall,
385    SyncExitCall {
386        callback: Option<CallbackId>,
387    },
388    AsyncEnterCall,
389    AsyncExitCall {
390        callback: Option<CallbackId>,
391        post_return: Option<PostReturnId>,
392    },
393    FutureTransfer,
394    StreamTransfer,
395    ErrorContextTransfer,
396}
397
398#[derive(Copy, Clone, Hash, Eq, PartialEq)]
399#[expect(missing_docs, reason = "self-describing fields")]
400pub struct FutureInfo {
401    pub instance: RuntimeComponentInstanceIndex,
402    pub payload_type: Option<InterfaceType>,
403}
404
405#[derive(Copy, Clone, Hash, Eq, PartialEq)]
406#[expect(missing_docs, reason = "self-describing fields")]
407pub struct StreamInfo {
408    pub instance: RuntimeComponentInstanceIndex,
409    pub payload_type: InterfaceType,
410}
411
412/// Same as `info::CanonicalOptions`
413#[derive(Clone, Hash, Eq, PartialEq)]
414#[expect(missing_docs, reason = "self-describing fields")]
415pub struct CanonicalOptions {
416    pub instance: RuntimeComponentInstanceIndex,
417    pub string_encoding: StringEncoding,
418    pub memory: Option<MemoryId>,
419    pub realloc: Option<ReallocId>,
420    pub callback: Option<CallbackId>,
421    pub post_return: Option<PostReturnId>,
422    pub async_: bool,
423}
424
425/// Same as `info::Resource`
426#[expect(missing_docs, reason = "self-describing fields")]
427pub struct Resource {
428    pub rep: WasmValType,
429    pub dtor: Option<CoreDef>,
430    pub instance: RuntimeComponentInstanceIndex,
431}
432
433/// A helper structure to "intern" and deduplicate values of type `V` with an
434/// identifying key `K`.
435///
436/// Note that this can also be used where `V` can't be intern'd to represent a
437/// flat list of items.
438pub struct Intern<K: EntityRef, V> {
439    intern_map: HashMap<V, K>,
440    key_map: PrimaryMap<K, V>,
441}
442
443impl<K, V> Intern<K, V>
444where
445    K: EntityRef,
446{
447    /// Inserts the `value` specified into this set, returning either a fresh
448    /// key `K` if this value hasn't been seen before or otherwise returning the
449    /// previous `K` used to represent value.
450    ///
451    /// Note that this should only be used for component model items where the
452    /// creation of `value` is not side-effectful.
453    pub fn push(&mut self, value: V) -> K
454    where
455        V: Hash + Eq + Clone,
456    {
457        *self
458            .intern_map
459            .entry(value.clone())
460            .or_insert_with(|| self.key_map.push(value))
461    }
462
463    /// Returns an iterator of all the values contained within this set.
464    pub fn iter(&self) -> impl Iterator<Item = (K, &V)> {
465        self.key_map.iter()
466    }
467}
468
469impl<K: EntityRef, V> Index<K> for Intern<K, V> {
470    type Output = V;
471    fn index(&self, key: K) -> &V {
472        &self.key_map[key]
473    }
474}
475
476impl<K: EntityRef, V> Default for Intern<K, V> {
477    fn default() -> Intern<K, V> {
478        Intern {
479            intern_map: HashMap::new(),
480            key_map: PrimaryMap::new(),
481        }
482    }
483}
484
485impl ComponentDfg {
486    /// Consumes the intermediate `ComponentDfg` to produce a final `Component`
487    /// with a linear initializer list.
488    pub fn finish(
489        self,
490        wasmtime_types: &mut ComponentTypesBuilder,
491        wasmparser_types: wasmparser::types::TypesRef<'_>,
492    ) -> Result<ComponentTranslation> {
493        let mut linearize = LinearizeDfg {
494            dfg: &self,
495            initializers: Vec::new(),
496            runtime_memories: Default::default(),
497            runtime_tables: Default::default(),
498            runtime_post_return: Default::default(),
499            runtime_reallocs: Default::default(),
500            runtime_callbacks: Default::default(),
501            runtime_instances: Default::default(),
502            num_lowerings: 0,
503            trampolines: Default::default(),
504            trampoline_defs: Default::default(),
505            trampoline_map: Default::default(),
506        };
507
508        // Handle all side effects of this component in the order that they're
509        // defined. This will, for example, process all instantiations necessary
510        // of core wasm modules.
511        for item in linearize.dfg.side_effects.iter() {
512            linearize.side_effect(item);
513        }
514
515        // Next the exports of the instance are handled which will likely end up
516        // creating some lowered imports, perhaps some saved modules, etc.
517        let mut export_items = PrimaryMap::new();
518        let mut exports = NameMap::default();
519        for (name, export) in self.exports.iter() {
520            let export =
521                linearize.export(export, &mut export_items, wasmtime_types, wasmparser_types)?;
522            exports.insert(name, &mut NameMapNoIntern, false, export)?;
523        }
524
525        // With all those pieces done the results of the dataflow-based
526        // linearization are recorded into the `Component`. The number of
527        // runtime values used for each index space is used from the `linearize`
528        // result.
529        Ok(ComponentTranslation {
530            trampolines: linearize.trampoline_defs,
531            component: Component {
532                exports,
533                export_items,
534                initializers: linearize.initializers,
535                trampolines: linearize.trampolines,
536                num_lowerings: linearize.num_lowerings,
537
538                num_runtime_memories: linearize.runtime_memories.len() as u32,
539                num_runtime_tables: linearize.runtime_tables.len() as u32,
540                num_runtime_post_returns: linearize.runtime_post_return.len() as u32,
541                num_runtime_reallocs: linearize.runtime_reallocs.len() as u32,
542                num_runtime_callbacks: linearize.runtime_callbacks.len() as u32,
543                num_runtime_instances: linearize.runtime_instances.len() as u32,
544                imports: self.imports,
545                import_types: self.import_types,
546                num_runtime_component_instances: self.num_runtime_component_instances,
547                num_resource_tables: self.num_resource_tables,
548                num_future_tables: self.num_future_tables,
549                num_stream_tables: self.num_stream_tables,
550                num_error_context_tables: self.num_error_context_tables,
551                num_resources: (self.resources.len() + self.imported_resources.len()) as u32,
552                imported_resources: self.imported_resources,
553                defined_resource_instances: self
554                    .resources
555                    .iter()
556                    .map(|(_, r)| r.instance)
557                    .collect(),
558            },
559        })
560    }
561
562    /// Converts the provided defined index into a normal index, adding in the
563    /// number of imported resources.
564    pub fn resource_index(&self, defined: DefinedResourceIndex) -> ResourceIndex {
565        ResourceIndex::from_u32(defined.as_u32() + (self.imported_resources.len() as u32))
566    }
567}
568
569struct LinearizeDfg<'a> {
570    dfg: &'a ComponentDfg,
571    initializers: Vec<GlobalInitializer>,
572    trampolines: PrimaryMap<TrampolineIndex, ModuleInternedTypeIndex>,
573    trampoline_defs: PrimaryMap<TrampolineIndex, info::Trampoline>,
574    trampoline_map: HashMap<TrampolineIndex, TrampolineIndex>,
575    runtime_memories: HashMap<MemoryId, RuntimeMemoryIndex>,
576    runtime_tables: HashMap<TableId, RuntimeTableIndex>,
577    runtime_reallocs: HashMap<ReallocId, RuntimeReallocIndex>,
578    runtime_callbacks: HashMap<CallbackId, RuntimeCallbackIndex>,
579    runtime_post_return: HashMap<PostReturnId, RuntimePostReturnIndex>,
580    runtime_instances: HashMap<RuntimeInstance, RuntimeInstanceIndex>,
581    num_lowerings: u32,
582}
583
584#[derive(Copy, Clone, Hash, Eq, PartialEq)]
585enum RuntimeInstance {
586    Normal(InstanceId),
587    Adapter(AdapterModuleId),
588}
589
590impl LinearizeDfg<'_> {
591    fn side_effect(&mut self, effect: &SideEffect) {
592        match effect {
593            SideEffect::Instance(i) => {
594                self.instantiate(*i, &self.dfg.instances[*i]);
595            }
596            SideEffect::Resource(i) => {
597                self.resource(*i, &self.dfg.resources[*i]);
598            }
599        }
600    }
601
602    fn instantiate(&mut self, instance: InstanceId, args: &Instance) {
603        log::trace!("creating instance {instance:?}");
604        let instantiation = match args {
605            Instance::Static(index, args) => InstantiateModule::Static(
606                *index,
607                args.iter().map(|def| self.core_def(def)).collect(),
608            ),
609            Instance::Import(index, args) => InstantiateModule::Import(
610                *index,
611                args.iter()
612                    .map(|(module, values)| {
613                        let values = values
614                            .iter()
615                            .map(|(name, def)| (name.clone(), self.core_def(def)))
616                            .collect();
617                        (module.clone(), values)
618                    })
619                    .collect(),
620            ),
621        };
622        let index = RuntimeInstanceIndex::new(self.runtime_instances.len());
623        self.initializers
624            .push(GlobalInitializer::InstantiateModule(instantiation));
625        let prev = self
626            .runtime_instances
627            .insert(RuntimeInstance::Normal(instance), index);
628        assert!(prev.is_none());
629    }
630
631    fn resource(&mut self, index: DefinedResourceIndex, resource: &Resource) {
632        let dtor = resource.dtor.as_ref().map(|dtor| self.core_def(dtor));
633        self.initializers
634            .push(GlobalInitializer::Resource(info::Resource {
635                dtor,
636                index,
637                rep: resource.rep,
638                instance: resource.instance,
639            }));
640    }
641
642    fn export(
643        &mut self,
644        export: &Export,
645        items: &mut PrimaryMap<ExportIndex, info::Export>,
646        wasmtime_types: &mut ComponentTypesBuilder,
647        wasmparser_types: wasmparser::types::TypesRef<'_>,
648    ) -> Result<ExportIndex> {
649        let item = match export {
650            Export::LiftedFunction { ty, func, options } => {
651                let func = self.core_def(func);
652                let options = self.options(options);
653                info::Export::LiftedFunction {
654                    ty: *ty,
655                    func,
656                    options,
657                }
658            }
659            Export::ModuleStatic { ty, index } => info::Export::ModuleStatic {
660                ty: wasmtime_types.convert_module(wasmparser_types, *ty)?,
661                index: *index,
662            },
663            Export::ModuleImport { ty, import } => info::Export::ModuleImport {
664                ty: *ty,
665                import: *import,
666            },
667            Export::Instance { ty, exports } => info::Export::Instance {
668                ty: *ty,
669                exports: {
670                    let mut map = NameMap::default();
671                    for (name, export) in exports {
672                        let export =
673                            self.export(export, items, wasmtime_types, wasmparser_types)?;
674                        map.insert(name, &mut NameMapNoIntern, false, export)?;
675                    }
676                    map
677                },
678            },
679            Export::Type(def) => info::Export::Type(*def),
680        };
681        Ok(items.push(item))
682    }
683
684    fn options(&mut self, options: &CanonicalOptions) -> info::CanonicalOptions {
685        let memory = options.memory.map(|mem| self.runtime_memory(mem));
686        let realloc = options.realloc.map(|mem| self.runtime_realloc(mem));
687        let callback = options.callback.map(|mem| self.runtime_callback(mem));
688        let post_return = options.post_return.map(|mem| self.runtime_post_return(mem));
689        info::CanonicalOptions {
690            instance: options.instance,
691            string_encoding: options.string_encoding,
692            memory,
693            realloc,
694            callback,
695            post_return,
696            async_: options.async_,
697        }
698    }
699
700    fn runtime_memory(&mut self, mem: MemoryId) -> RuntimeMemoryIndex {
701        self.intern(
702            mem,
703            |me| &mut me.runtime_memories,
704            |me, mem| me.core_export(&me.dfg.memories[mem]),
705            |index, export| GlobalInitializer::ExtractMemory(ExtractMemory { index, export }),
706        )
707    }
708
709    fn runtime_realloc(&mut self, realloc: ReallocId) -> RuntimeReallocIndex {
710        self.intern(
711            realloc,
712            |me| &mut me.runtime_reallocs,
713            |me, realloc| me.core_def(&me.dfg.reallocs[realloc]),
714            |index, def| GlobalInitializer::ExtractRealloc(ExtractRealloc { index, def }),
715        )
716    }
717
718    fn runtime_callback(&mut self, callback: CallbackId) -> RuntimeCallbackIndex {
719        self.intern(
720            callback,
721            |me| &mut me.runtime_callbacks,
722            |me, callback| me.core_def(&me.dfg.callbacks[callback]),
723            |index, def| GlobalInitializer::ExtractCallback(ExtractCallback { index, def }),
724        )
725    }
726
727    fn runtime_post_return(&mut self, post_return: PostReturnId) -> RuntimePostReturnIndex {
728        self.intern(
729            post_return,
730            |me| &mut me.runtime_post_return,
731            |me, post_return| me.core_def(&me.dfg.post_returns[post_return]),
732            |index, def| GlobalInitializer::ExtractPostReturn(ExtractPostReturn { index, def }),
733        )
734    }
735
736    fn core_def(&mut self, def: &CoreDef) -> info::CoreDef {
737        match def {
738            CoreDef::Export(e) => info::CoreDef::Export(self.core_export(e)),
739            CoreDef::InstanceFlags(i) => info::CoreDef::InstanceFlags(*i),
740            CoreDef::Adapter(id) => info::CoreDef::Export(self.adapter(*id)),
741            CoreDef::Trampoline(index) => info::CoreDef::Trampoline(self.trampoline(*index)),
742        }
743    }
744
745    fn trampoline(&mut self, index: TrampolineIndex) -> TrampolineIndex {
746        if let Some(idx) = self.trampoline_map.get(&index) {
747            return *idx;
748        }
749        let (signature, trampoline) = &self.dfg.trampolines[index];
750        let trampoline = match trampoline {
751            Trampoline::LowerImport {
752                import,
753                options,
754                lower_ty,
755            } => {
756                let index = LoweredIndex::from_u32(self.num_lowerings);
757                self.num_lowerings += 1;
758                self.initializers.push(GlobalInitializer::LowerImport {
759                    index,
760                    import: *import,
761                });
762                info::Trampoline::LowerImport {
763                    index,
764                    options: self.options(options),
765                    lower_ty: *lower_ty,
766                }
767            }
768            Trampoline::Transcoder {
769                op,
770                from,
771                from64,
772                to,
773                to64,
774            } => info::Trampoline::Transcoder {
775                op: *op,
776                from: self.runtime_memory(*from),
777                from64: *from64,
778                to: self.runtime_memory(*to),
779                to64: *to64,
780            },
781            Trampoline::AlwaysTrap => info::Trampoline::AlwaysTrap,
782            Trampoline::ResourceNew(ty) => info::Trampoline::ResourceNew(*ty),
783            Trampoline::ResourceDrop(ty) => info::Trampoline::ResourceDrop(*ty),
784            Trampoline::ResourceRep(ty) => info::Trampoline::ResourceRep(*ty),
785            Trampoline::BackpressureSet { instance } => info::Trampoline::BackpressureSet {
786                instance: *instance,
787            },
788            Trampoline::TaskReturn { results, options } => info::Trampoline::TaskReturn {
789                results: *results,
790                options: self.options(options),
791            },
792            Trampoline::WaitableSetNew { instance } => info::Trampoline::WaitableSetNew {
793                instance: *instance,
794            },
795            Trampoline::WaitableSetWait {
796                instance,
797                async_,
798                memory,
799            } => info::Trampoline::WaitableSetWait {
800                instance: *instance,
801                async_: *async_,
802                memory: self.runtime_memory(*memory),
803            },
804            Trampoline::WaitableSetPoll {
805                instance,
806                async_,
807                memory,
808            } => info::Trampoline::WaitableSetPoll {
809                instance: *instance,
810                async_: *async_,
811                memory: self.runtime_memory(*memory),
812            },
813            Trampoline::WaitableSetDrop { instance } => info::Trampoline::WaitableSetDrop {
814                instance: *instance,
815            },
816            Trampoline::WaitableJoin { instance } => info::Trampoline::WaitableJoin {
817                instance: *instance,
818            },
819            Trampoline::Yield { async_ } => info::Trampoline::Yield { async_: *async_ },
820            Trampoline::SubtaskDrop { instance } => info::Trampoline::SubtaskDrop {
821                instance: *instance,
822            },
823            Trampoline::StreamNew { ty } => info::Trampoline::StreamNew { ty: *ty },
824            Trampoline::StreamRead { ty, options } => info::Trampoline::StreamRead {
825                ty: *ty,
826                options: self.options(options),
827            },
828            Trampoline::StreamWrite { ty, options } => info::Trampoline::StreamWrite {
829                ty: *ty,
830                options: self.options(options),
831            },
832            Trampoline::StreamCancelRead { ty, async_ } => info::Trampoline::StreamCancelRead {
833                ty: *ty,
834                async_: *async_,
835            },
836            Trampoline::StreamCancelWrite { ty, async_ } => info::Trampoline::StreamCancelWrite {
837                ty: *ty,
838                async_: *async_,
839            },
840            Trampoline::StreamCloseReadable { ty } => {
841                info::Trampoline::StreamCloseReadable { ty: *ty }
842            }
843            Trampoline::StreamCloseWritable { ty } => {
844                info::Trampoline::StreamCloseWritable { ty: *ty }
845            }
846            Trampoline::FutureNew { ty } => info::Trampoline::FutureNew { ty: *ty },
847            Trampoline::FutureRead { ty, options } => info::Trampoline::FutureRead {
848                ty: *ty,
849                options: self.options(options),
850            },
851            Trampoline::FutureWrite { ty, options } => info::Trampoline::FutureWrite {
852                ty: *ty,
853                options: self.options(options),
854            },
855            Trampoline::FutureCancelRead { ty, async_ } => info::Trampoline::FutureCancelRead {
856                ty: *ty,
857                async_: *async_,
858            },
859            Trampoline::FutureCancelWrite { ty, async_ } => info::Trampoline::FutureCancelWrite {
860                ty: *ty,
861                async_: *async_,
862            },
863            Trampoline::FutureCloseReadable { ty } => {
864                info::Trampoline::FutureCloseReadable { ty: *ty }
865            }
866            Trampoline::FutureCloseWritable { ty } => {
867                info::Trampoline::FutureCloseWritable { ty: *ty }
868            }
869            Trampoline::ErrorContextNew { ty, options } => info::Trampoline::ErrorContextNew {
870                ty: *ty,
871                options: self.options(options),
872            },
873            Trampoline::ErrorContextDebugMessage { ty, options } => {
874                info::Trampoline::ErrorContextDebugMessage {
875                    ty: *ty,
876                    options: self.options(options),
877                }
878            }
879            Trampoline::ErrorContextDrop { ty } => info::Trampoline::ErrorContextDrop { ty: *ty },
880            Trampoline::ResourceTransferOwn => info::Trampoline::ResourceTransferOwn,
881            Trampoline::ResourceTransferBorrow => info::Trampoline::ResourceTransferBorrow,
882            Trampoline::ResourceEnterCall => info::Trampoline::ResourceEnterCall,
883            Trampoline::ResourceExitCall => info::Trampoline::ResourceExitCall,
884            Trampoline::SyncEnterCall => info::Trampoline::SyncEnterCall,
885            Trampoline::SyncExitCall { callback } => info::Trampoline::SyncExitCall {
886                callback: callback.map(|v| self.runtime_callback(v)),
887            },
888            Trampoline::AsyncEnterCall => info::Trampoline::AsyncEnterCall,
889            Trampoline::AsyncExitCall {
890                callback,
891                post_return,
892            } => info::Trampoline::AsyncExitCall {
893                callback: callback.map(|v| self.runtime_callback(v)),
894                post_return: post_return.map(|v| self.runtime_post_return(v)),
895            },
896            Trampoline::FutureTransfer => info::Trampoline::FutureTransfer,
897            Trampoline::StreamTransfer => info::Trampoline::StreamTransfer,
898            Trampoline::ErrorContextTransfer => info::Trampoline::ErrorContextTransfer,
899        };
900        let i1 = self.trampolines.push(*signature);
901        let i2 = self.trampoline_defs.push(trampoline);
902        assert_eq!(i1, i2);
903        self.trampoline_map.insert(index, i1);
904        i1
905    }
906
907    fn core_export<T>(&mut self, export: &CoreExport<T>) -> info::CoreExport<T>
908    where
909        T: Clone,
910    {
911        let instance = export.instance;
912        log::trace!("referencing export of {instance:?}");
913        info::CoreExport {
914            instance: self.runtime_instances[&RuntimeInstance::Normal(instance)],
915            item: export.item.clone(),
916        }
917    }
918
919    fn adapter(&mut self, adapter: AdapterId) -> info::CoreExport<EntityIndex> {
920        let (adapter_module, entity_index) = self.dfg.adapter_partitionings[adapter];
921
922        // Instantiates the adapter module if it hasn't already been
923        // instantiated or otherwise returns the index that the module was
924        // already instantiated at.
925        let instance = self.adapter_module(adapter_module);
926
927        // This adapter is always an export of the instance.
928        info::CoreExport {
929            instance,
930            item: ExportItem::Index(entity_index),
931        }
932    }
933
934    fn adapter_module(&mut self, adapter_module: AdapterModuleId) -> RuntimeInstanceIndex {
935        self.intern(
936            RuntimeInstance::Adapter(adapter_module),
937            |me| &mut me.runtime_instances,
938            |me, _| {
939                log::debug!("instantiating {adapter_module:?}");
940                let (module_index, args) = &me.dfg.adapter_modules[adapter_module];
941                let args = args.iter().map(|arg| me.core_def(arg)).collect();
942                let instantiate = InstantiateModule::Static(*module_index, args);
943                GlobalInitializer::InstantiateModule(instantiate)
944            },
945            |_, init| init,
946        )
947    }
948
949    /// Helper function to manage interning of results to avoid duplicate
950    /// initializers being inserted into the final list.
951    ///
952    /// * `key` - the key being referenced which is used to deduplicate.
953    /// * `map` - a closure to access the interning map on `Self`
954    /// * `gen` - a closure to generate an intermediate value with `Self` from
955    ///   `K`. This is only used if `key` hasn't previously been seen. This
956    ///   closure can recursively intern other values possibly.
957    /// * `init` - a closure to use the result of `gen` to create the final
958    ///   initializer now that the index `V` of the runtime item is known.
959    ///
960    /// This is used by all the other interning methods above to lazily append
961    /// initializers on-demand and avoid pushing more than one initializer at a
962    /// time.
963    fn intern<K, V, T>(
964        &mut self,
965        key: K,
966        map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
967        generate: impl FnOnce(&mut Self, K) -> T,
968        init: impl FnOnce(V, T) -> GlobalInitializer,
969    ) -> V
970    where
971        K: Hash + Eq + Copy,
972        V: EntityRef,
973    {
974        if let Some(val) = map(self).get(&key) {
975            return *val;
976        }
977        let tmp = generate(self, key);
978        let index = V::new(map(self).len());
979        self.initializers.push(init(index, tmp));
980        let prev = map(self).insert(key, index);
981        assert!(prev.is_none());
982        index
983    }
984}