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