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    WaitableSetNew {
290        instance: RuntimeComponentInstanceIndex,
291    },
292    WaitableSetWait {
293        instance: RuntimeComponentInstanceIndex,
294        async_: bool,
295        memory: MemoryId,
296    },
297    WaitableSetPoll {
298        instance: RuntimeComponentInstanceIndex,
299        async_: bool,
300        memory: MemoryId,
301    },
302    WaitableSetDrop {
303        instance: RuntimeComponentInstanceIndex,
304    },
305    WaitableJoin {
306        instance: RuntimeComponentInstanceIndex,
307    },
308    Yield {
309        async_: bool,
310    },
311    SubtaskDrop {
312        instance: RuntimeComponentInstanceIndex,
313    },
314    StreamNew {
315        ty: TypeStreamTableIndex,
316    },
317    StreamRead {
318        ty: TypeStreamTableIndex,
319        options: CanonicalOptions,
320    },
321    StreamWrite {
322        ty: TypeStreamTableIndex,
323        options: CanonicalOptions,
324    },
325    StreamCancelRead {
326        ty: TypeStreamTableIndex,
327        async_: bool,
328    },
329    StreamCancelWrite {
330        ty: TypeStreamTableIndex,
331        async_: bool,
332    },
333    StreamCloseReadable {
334        ty: TypeStreamTableIndex,
335    },
336    StreamCloseWritable {
337        ty: TypeStreamTableIndex,
338    },
339    FutureNew {
340        ty: TypeFutureTableIndex,
341    },
342    FutureRead {
343        ty: TypeFutureTableIndex,
344        options: CanonicalOptions,
345    },
346    FutureWrite {
347        ty: TypeFutureTableIndex,
348        options: CanonicalOptions,
349    },
350    FutureCancelRead {
351        ty: TypeFutureTableIndex,
352        async_: bool,
353    },
354    FutureCancelWrite {
355        ty: TypeFutureTableIndex,
356        async_: bool,
357    },
358    FutureCloseReadable {
359        ty: TypeFutureTableIndex,
360    },
361    FutureCloseWritable {
362        ty: TypeFutureTableIndex,
363    },
364    ErrorContextNew {
365        ty: TypeComponentLocalErrorContextTableIndex,
366        options: CanonicalOptions,
367    },
368    ErrorContextDebugMessage {
369        ty: TypeComponentLocalErrorContextTableIndex,
370        options: CanonicalOptions,
371    },
372    ErrorContextDrop {
373        ty: TypeComponentLocalErrorContextTableIndex,
374    },
375    ResourceTransferOwn,
376    ResourceTransferBorrow,
377    ResourceEnterCall,
378    ResourceExitCall,
379    SyncEnterCall,
380    SyncExitCall {
381        callback: Option<CallbackId>,
382    },
383    AsyncEnterCall,
384    AsyncExitCall {
385        callback: Option<CallbackId>,
386        post_return: Option<PostReturnId>,
387    },
388    FutureTransfer,
389    StreamTransfer,
390    ErrorContextTransfer,
391}
392
393#[derive(Copy, Clone, Hash, Eq, PartialEq)]
394#[expect(missing_docs, reason = "self-describing fields")]
395pub struct FutureInfo {
396    pub instance: RuntimeComponentInstanceIndex,
397    pub payload_type: Option<InterfaceType>,
398}
399
400#[derive(Copy, Clone, Hash, Eq, PartialEq)]
401#[expect(missing_docs, reason = "self-describing fields")]
402pub struct StreamInfo {
403    pub instance: RuntimeComponentInstanceIndex,
404    pub payload_type: InterfaceType,
405}
406
407/// Same as `info::CanonicalOptions`
408#[derive(Clone, Hash, Eq, PartialEq)]
409#[expect(missing_docs, reason = "self-describing fields")]
410pub struct CanonicalOptions {
411    pub instance: RuntimeComponentInstanceIndex,
412    pub string_encoding: StringEncoding,
413    pub memory: Option<MemoryId>,
414    pub realloc: Option<ReallocId>,
415    pub callback: Option<CallbackId>,
416    pub post_return: Option<PostReturnId>,
417    pub async_: bool,
418}
419
420/// Same as `info::Resource`
421#[expect(missing_docs, reason = "self-describing fields")]
422pub struct Resource {
423    pub rep: WasmValType,
424    pub dtor: Option<CoreDef>,
425    pub instance: RuntimeComponentInstanceIndex,
426}
427
428/// A helper structure to "intern" and deduplicate values of type `V` with an
429/// identifying key `K`.
430///
431/// Note that this can also be used where `V` can't be intern'd to represent a
432/// flat list of items.
433pub struct Intern<K: EntityRef, V> {
434    intern_map: HashMap<V, K>,
435    key_map: PrimaryMap<K, V>,
436}
437
438impl<K, V> Intern<K, V>
439where
440    K: EntityRef,
441{
442    /// Inserts the `value` specified into this set, returning either a fresh
443    /// key `K` if this value hasn't been seen before or otherwise returning the
444    /// previous `K` used to represent value.
445    ///
446    /// Note that this should only be used for component model items where the
447    /// creation of `value` is not side-effectful.
448    pub fn push(&mut self, value: V) -> K
449    where
450        V: Hash + Eq + Clone,
451    {
452        *self
453            .intern_map
454            .entry(value.clone())
455            .or_insert_with(|| self.key_map.push(value))
456    }
457
458    /// Returns an iterator of all the values contained within this set.
459    pub fn iter(&self) -> impl Iterator<Item = (K, &V)> {
460        self.key_map.iter()
461    }
462}
463
464impl<K: EntityRef, V> Index<K> for Intern<K, V> {
465    type Output = V;
466    fn index(&self, key: K) -> &V {
467        &self.key_map[key]
468    }
469}
470
471impl<K: EntityRef, V> Default for Intern<K, V> {
472    fn default() -> Intern<K, V> {
473        Intern {
474            intern_map: HashMap::new(),
475            key_map: PrimaryMap::new(),
476        }
477    }
478}
479
480impl ComponentDfg {
481    /// Consumes the intermediate `ComponentDfg` to produce a final `Component`
482    /// with a linear initializer list.
483    pub fn finish(
484        self,
485        wasmtime_types: &mut ComponentTypesBuilder,
486        wasmparser_types: wasmparser::types::TypesRef<'_>,
487    ) -> Result<ComponentTranslation> {
488        let mut linearize = LinearizeDfg {
489            dfg: &self,
490            initializers: Vec::new(),
491            runtime_memories: Default::default(),
492            runtime_tables: Default::default(),
493            runtime_post_return: Default::default(),
494            runtime_reallocs: Default::default(),
495            runtime_callbacks: Default::default(),
496            runtime_instances: Default::default(),
497            num_lowerings: 0,
498            trampolines: Default::default(),
499            trampoline_defs: Default::default(),
500            trampoline_map: Default::default(),
501        };
502
503        // Handle all side effects of this component in the order that they're
504        // defined. This will, for example, process all instantiations necessary
505        // of core wasm modules.
506        for item in linearize.dfg.side_effects.iter() {
507            linearize.side_effect(item);
508        }
509
510        // Next the exports of the instance are handled which will likely end up
511        // creating some lowered imports, perhaps some saved modules, etc.
512        let mut export_items = PrimaryMap::new();
513        let mut exports = NameMap::default();
514        for (name, export) in self.exports.iter() {
515            let export =
516                linearize.export(export, &mut export_items, wasmtime_types, wasmparser_types)?;
517            exports.insert(name, &mut NameMapNoIntern, false, export)?;
518        }
519
520        // With all those pieces done the results of the dataflow-based
521        // linearization are recorded into the `Component`. The number of
522        // runtime values used for each index space is used from the `linearize`
523        // result.
524        Ok(ComponentTranslation {
525            trampolines: linearize.trampoline_defs,
526            component: Component {
527                exports,
528                export_items,
529                initializers: linearize.initializers,
530                trampolines: linearize.trampolines,
531                num_lowerings: linearize.num_lowerings,
532
533                num_runtime_memories: linearize.runtime_memories.len() as u32,
534                num_runtime_tables: linearize.runtime_tables.len() as u32,
535                num_runtime_post_returns: linearize.runtime_post_return.len() as u32,
536                num_runtime_reallocs: linearize.runtime_reallocs.len() as u32,
537                num_runtime_callbacks: linearize.runtime_callbacks.len() as u32,
538                num_runtime_instances: linearize.runtime_instances.len() as u32,
539                imports: self.imports,
540                import_types: self.import_types,
541                num_runtime_component_instances: self.num_runtime_component_instances,
542                num_future_tables: self.num_future_tables,
543                num_stream_tables: self.num_stream_tables,
544                num_error_context_tables: self.num_error_context_tables,
545                num_resources: (self.resources.len() + self.imported_resources.len()) as u32,
546                imported_resources: self.imported_resources,
547                defined_resource_instances: self
548                    .resources
549                    .iter()
550                    .map(|(_, r)| r.instance)
551                    .collect(),
552            },
553        })
554    }
555
556    /// Converts the provided defined index into a normal index, adding in the
557    /// number of imported resources.
558    pub fn resource_index(&self, defined: DefinedResourceIndex) -> ResourceIndex {
559        ResourceIndex::from_u32(defined.as_u32() + (self.imported_resources.len() as u32))
560    }
561}
562
563struct LinearizeDfg<'a> {
564    dfg: &'a ComponentDfg,
565    initializers: Vec<GlobalInitializer>,
566    trampolines: PrimaryMap<TrampolineIndex, ModuleInternedTypeIndex>,
567    trampoline_defs: PrimaryMap<TrampolineIndex, info::Trampoline>,
568    trampoline_map: HashMap<TrampolineIndex, TrampolineIndex>,
569    runtime_memories: HashMap<MemoryId, RuntimeMemoryIndex>,
570    runtime_tables: HashMap<TableId, RuntimeTableIndex>,
571    runtime_reallocs: HashMap<ReallocId, RuntimeReallocIndex>,
572    runtime_callbacks: HashMap<CallbackId, RuntimeCallbackIndex>,
573    runtime_post_return: HashMap<PostReturnId, RuntimePostReturnIndex>,
574    runtime_instances: HashMap<RuntimeInstance, RuntimeInstanceIndex>,
575    num_lowerings: u32,
576}
577
578#[derive(Copy, Clone, Hash, Eq, PartialEq)]
579enum RuntimeInstance {
580    Normal(InstanceId),
581    Adapter(AdapterModuleId),
582}
583
584impl LinearizeDfg<'_> {
585    fn side_effect(&mut self, effect: &SideEffect) {
586        match effect {
587            SideEffect::Instance(i) => {
588                self.instantiate(*i, &self.dfg.instances[*i]);
589            }
590            SideEffect::Resource(i) => {
591                self.resource(*i, &self.dfg.resources[*i]);
592            }
593        }
594    }
595
596    fn instantiate(&mut self, instance: InstanceId, args: &Instance) {
597        log::trace!("creating instance {instance:?}");
598        let instantiation = match args {
599            Instance::Static(index, args) => InstantiateModule::Static(
600                *index,
601                args.iter().map(|def| self.core_def(def)).collect(),
602            ),
603            Instance::Import(index, args) => InstantiateModule::Import(
604                *index,
605                args.iter()
606                    .map(|(module, values)| {
607                        let values = values
608                            .iter()
609                            .map(|(name, def)| (name.clone(), self.core_def(def)))
610                            .collect();
611                        (module.clone(), values)
612                    })
613                    .collect(),
614            ),
615        };
616        let index = RuntimeInstanceIndex::new(self.runtime_instances.len());
617        self.initializers
618            .push(GlobalInitializer::InstantiateModule(instantiation));
619        let prev = self
620            .runtime_instances
621            .insert(RuntimeInstance::Normal(instance), index);
622        assert!(prev.is_none());
623    }
624
625    fn resource(&mut self, index: DefinedResourceIndex, resource: &Resource) {
626        let dtor = resource.dtor.as_ref().map(|dtor| self.core_def(dtor));
627        self.initializers
628            .push(GlobalInitializer::Resource(info::Resource {
629                dtor,
630                index,
631                rep: resource.rep,
632                instance: resource.instance,
633            }));
634    }
635
636    fn export(
637        &mut self,
638        export: &Export,
639        items: &mut PrimaryMap<ExportIndex, info::Export>,
640        wasmtime_types: &mut ComponentTypesBuilder,
641        wasmparser_types: wasmparser::types::TypesRef<'_>,
642    ) -> Result<ExportIndex> {
643        let item = match export {
644            Export::LiftedFunction { ty, func, options } => {
645                let func = self.core_def(func);
646                let options = self.options(options);
647                info::Export::LiftedFunction {
648                    ty: *ty,
649                    func,
650                    options,
651                }
652            }
653            Export::ModuleStatic { ty, index } => info::Export::ModuleStatic {
654                ty: wasmtime_types.convert_module(wasmparser_types, *ty)?,
655                index: *index,
656            },
657            Export::ModuleImport { ty, import } => info::Export::ModuleImport {
658                ty: *ty,
659                import: *import,
660            },
661            Export::Instance { ty, exports } => info::Export::Instance {
662                ty: *ty,
663                exports: {
664                    let mut map = NameMap::default();
665                    for (name, export) in exports {
666                        let export =
667                            self.export(export, items, wasmtime_types, wasmparser_types)?;
668                        map.insert(name, &mut NameMapNoIntern, false, export)?;
669                    }
670                    map
671                },
672            },
673            Export::Type(def) => info::Export::Type(*def),
674        };
675        Ok(items.push(item))
676    }
677
678    fn options(&mut self, options: &CanonicalOptions) -> info::CanonicalOptions {
679        let memory = options.memory.map(|mem| self.runtime_memory(mem));
680        let realloc = options.realloc.map(|mem| self.runtime_realloc(mem));
681        let callback = options.callback.map(|mem| self.runtime_callback(mem));
682        let post_return = options.post_return.map(|mem| self.runtime_post_return(mem));
683        info::CanonicalOptions {
684            instance: options.instance,
685            string_encoding: options.string_encoding,
686            memory,
687            realloc,
688            callback,
689            post_return,
690            async_: options.async_,
691        }
692    }
693
694    fn runtime_memory(&mut self, mem: MemoryId) -> RuntimeMemoryIndex {
695        self.intern(
696            mem,
697            |me| &mut me.runtime_memories,
698            |me, mem| me.core_export(&me.dfg.memories[mem]),
699            |index, export| GlobalInitializer::ExtractMemory(ExtractMemory { index, export }),
700        )
701    }
702
703    fn runtime_realloc(&mut self, realloc: ReallocId) -> RuntimeReallocIndex {
704        self.intern(
705            realloc,
706            |me| &mut me.runtime_reallocs,
707            |me, realloc| me.core_def(&me.dfg.reallocs[realloc]),
708            |index, def| GlobalInitializer::ExtractRealloc(ExtractRealloc { index, def }),
709        )
710    }
711
712    fn runtime_callback(&mut self, callback: CallbackId) -> RuntimeCallbackIndex {
713        self.intern(
714            callback,
715            |me| &mut me.runtime_callbacks,
716            |me, callback| me.core_def(&me.dfg.callbacks[callback]),
717            |index, def| GlobalInitializer::ExtractCallback(ExtractCallback { index, def }),
718        )
719    }
720
721    fn runtime_post_return(&mut self, post_return: PostReturnId) -> RuntimePostReturnIndex {
722        self.intern(
723            post_return,
724            |me| &mut me.runtime_post_return,
725            |me, post_return| me.core_def(&me.dfg.post_returns[post_return]),
726            |index, def| GlobalInitializer::ExtractPostReturn(ExtractPostReturn { index, def }),
727        )
728    }
729
730    fn core_def(&mut self, def: &CoreDef) -> info::CoreDef {
731        match def {
732            CoreDef::Export(e) => info::CoreDef::Export(self.core_export(e)),
733            CoreDef::InstanceFlags(i) => info::CoreDef::InstanceFlags(*i),
734            CoreDef::Adapter(id) => info::CoreDef::Export(self.adapter(*id)),
735            CoreDef::Trampoline(index) => info::CoreDef::Trampoline(self.trampoline(*index)),
736        }
737    }
738
739    fn trampoline(&mut self, index: TrampolineIndex) -> TrampolineIndex {
740        if let Some(idx) = self.trampoline_map.get(&index) {
741            return *idx;
742        }
743        let (signature, trampoline) = &self.dfg.trampolines[index];
744        let trampoline = match trampoline {
745            Trampoline::LowerImport {
746                import,
747                options,
748                lower_ty,
749            } => {
750                let index = LoweredIndex::from_u32(self.num_lowerings);
751                self.num_lowerings += 1;
752                self.initializers.push(GlobalInitializer::LowerImport {
753                    index,
754                    import: *import,
755                });
756                info::Trampoline::LowerImport {
757                    index,
758                    options: self.options(options),
759                    lower_ty: *lower_ty,
760                }
761            }
762            Trampoline::Transcoder {
763                op,
764                from,
765                from64,
766                to,
767                to64,
768            } => info::Trampoline::Transcoder {
769                op: *op,
770                from: self.runtime_memory(*from),
771                from64: *from64,
772                to: self.runtime_memory(*to),
773                to64: *to64,
774            },
775            Trampoline::AlwaysTrap => info::Trampoline::AlwaysTrap,
776            Trampoline::ResourceNew(ty) => info::Trampoline::ResourceNew(*ty),
777            Trampoline::ResourceDrop(ty) => info::Trampoline::ResourceDrop(*ty),
778            Trampoline::ResourceRep(ty) => info::Trampoline::ResourceRep(*ty),
779            Trampoline::BackpressureSet { instance } => info::Trampoline::BackpressureSet {
780                instance: *instance,
781            },
782            Trampoline::TaskReturn { results, options } => info::Trampoline::TaskReturn {
783                results: *results,
784                options: self.options(options),
785            },
786            Trampoline::WaitableSetNew { instance } => info::Trampoline::WaitableSetNew {
787                instance: *instance,
788            },
789            Trampoline::WaitableSetWait {
790                instance,
791                async_,
792                memory,
793            } => info::Trampoline::WaitableSetWait {
794                instance: *instance,
795                async_: *async_,
796                memory: self.runtime_memory(*memory),
797            },
798            Trampoline::WaitableSetPoll {
799                instance,
800                async_,
801                memory,
802            } => info::Trampoline::WaitableSetPoll {
803                instance: *instance,
804                async_: *async_,
805                memory: self.runtime_memory(*memory),
806            },
807            Trampoline::WaitableSetDrop { instance } => info::Trampoline::WaitableSetDrop {
808                instance: *instance,
809            },
810            Trampoline::WaitableJoin { instance } => info::Trampoline::WaitableJoin {
811                instance: *instance,
812            },
813            Trampoline::Yield { async_ } => info::Trampoline::Yield { async_: *async_ },
814            Trampoline::SubtaskDrop { instance } => info::Trampoline::SubtaskDrop {
815                instance: *instance,
816            },
817            Trampoline::StreamNew { ty } => info::Trampoline::StreamNew { ty: *ty },
818            Trampoline::StreamRead { ty, options } => info::Trampoline::StreamRead {
819                ty: *ty,
820                options: self.options(options),
821            },
822            Trampoline::StreamWrite { ty, options } => info::Trampoline::StreamWrite {
823                ty: *ty,
824                options: self.options(options),
825            },
826            Trampoline::StreamCancelRead { ty, async_ } => info::Trampoline::StreamCancelRead {
827                ty: *ty,
828                async_: *async_,
829            },
830            Trampoline::StreamCancelWrite { ty, async_ } => info::Trampoline::StreamCancelWrite {
831                ty: *ty,
832                async_: *async_,
833            },
834            Trampoline::StreamCloseReadable { ty } => {
835                info::Trampoline::StreamCloseReadable { ty: *ty }
836            }
837            Trampoline::StreamCloseWritable { ty } => {
838                info::Trampoline::StreamCloseWritable { ty: *ty }
839            }
840            Trampoline::FutureNew { ty } => info::Trampoline::FutureNew { ty: *ty },
841            Trampoline::FutureRead { ty, options } => info::Trampoline::FutureRead {
842                ty: *ty,
843                options: self.options(options),
844            },
845            Trampoline::FutureWrite { ty, options } => info::Trampoline::FutureWrite {
846                ty: *ty,
847                options: self.options(options),
848            },
849            Trampoline::FutureCancelRead { ty, async_ } => info::Trampoline::FutureCancelRead {
850                ty: *ty,
851                async_: *async_,
852            },
853            Trampoline::FutureCancelWrite { ty, async_ } => info::Trampoline::FutureCancelWrite {
854                ty: *ty,
855                async_: *async_,
856            },
857            Trampoline::FutureCloseReadable { ty } => {
858                info::Trampoline::FutureCloseReadable { ty: *ty }
859            }
860            Trampoline::FutureCloseWritable { ty } => {
861                info::Trampoline::FutureCloseWritable { ty: *ty }
862            }
863            Trampoline::ErrorContextNew { ty, options } => info::Trampoline::ErrorContextNew {
864                ty: *ty,
865                options: self.options(options),
866            },
867            Trampoline::ErrorContextDebugMessage { ty, options } => {
868                info::Trampoline::ErrorContextDebugMessage {
869                    ty: *ty,
870                    options: self.options(options),
871                }
872            }
873            Trampoline::ErrorContextDrop { ty } => info::Trampoline::ErrorContextDrop { ty: *ty },
874            Trampoline::ResourceTransferOwn => info::Trampoline::ResourceTransferOwn,
875            Trampoline::ResourceTransferBorrow => info::Trampoline::ResourceTransferBorrow,
876            Trampoline::ResourceEnterCall => info::Trampoline::ResourceEnterCall,
877            Trampoline::ResourceExitCall => info::Trampoline::ResourceExitCall,
878            Trampoline::SyncEnterCall => info::Trampoline::SyncEnterCall,
879            Trampoline::SyncExitCall { callback } => info::Trampoline::SyncExitCall {
880                callback: callback.map(|v| self.runtime_callback(v)),
881            },
882            Trampoline::AsyncEnterCall => info::Trampoline::AsyncEnterCall,
883            Trampoline::AsyncExitCall {
884                callback,
885                post_return,
886            } => info::Trampoline::AsyncExitCall {
887                callback: callback.map(|v| self.runtime_callback(v)),
888                post_return: post_return.map(|v| self.runtime_post_return(v)),
889            },
890            Trampoline::FutureTransfer => info::Trampoline::FutureTransfer,
891            Trampoline::StreamTransfer => info::Trampoline::StreamTransfer,
892            Trampoline::ErrorContextTransfer => info::Trampoline::ErrorContextTransfer,
893        };
894        let i1 = self.trampolines.push(*signature);
895        let i2 = self.trampoline_defs.push(trampoline);
896        assert_eq!(i1, i2);
897        self.trampoline_map.insert(index, i1);
898        i1
899    }
900
901    fn core_export<T>(&mut self, export: &CoreExport<T>) -> info::CoreExport<T>
902    where
903        T: Clone,
904    {
905        let instance = export.instance;
906        log::trace!("referencing export of {instance:?}");
907        info::CoreExport {
908            instance: self.runtime_instances[&RuntimeInstance::Normal(instance)],
909            item: export.item.clone(),
910        }
911    }
912
913    fn adapter(&mut self, adapter: AdapterId) -> info::CoreExport<EntityIndex> {
914        let (adapter_module, entity_index) = self.dfg.adapter_partitionings[adapter];
915
916        // Instantiates the adapter module if it hasn't already been
917        // instantiated or otherwise returns the index that the module was
918        // already instantiated at.
919        let instance = self.adapter_module(adapter_module);
920
921        // This adapter is always an export of the instance.
922        info::CoreExport {
923            instance,
924            item: ExportItem::Index(entity_index),
925        }
926    }
927
928    fn adapter_module(&mut self, adapter_module: AdapterModuleId) -> RuntimeInstanceIndex {
929        self.intern(
930            RuntimeInstance::Adapter(adapter_module),
931            |me| &mut me.runtime_instances,
932            |me, _| {
933                log::debug!("instantiating {adapter_module:?}");
934                let (module_index, args) = &me.dfg.adapter_modules[adapter_module];
935                let args = args.iter().map(|arg| me.core_def(arg)).collect();
936                let instantiate = InstantiateModule::Static(*module_index, args);
937                GlobalInitializer::InstantiateModule(instantiate)
938            },
939            |_, init| init,
940        )
941    }
942
943    /// Helper function to manage interning of results to avoid duplicate
944    /// initializers being inserted into the final list.
945    ///
946    /// * `key` - the key being referenced which is used to deduplicate.
947    /// * `map` - a closure to access the interning map on `Self`
948    /// * `gen` - a closure to generate an intermediate value with `Self` from
949    ///   `K`. This is only used if `key` hasn't previously been seen. This
950    ///   closure can recursively intern other values possibly.
951    /// * `init` - a closure to use the result of `gen` to create the final
952    ///   initializer now that the index `V` of the runtime item is known.
953    ///
954    /// This is used by all the other interning methods above to lazily append
955    /// initializers on-demand and avoid pushing more than one initializer at a
956    /// time.
957    fn intern<K, V, T>(
958        &mut self,
959        key: K,
960        map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
961        generate: impl FnOnce(&mut Self, K) -> T,
962        init: impl FnOnce(V, T) -> GlobalInitializer,
963    ) -> V
964    where
965        K: Hash + Eq + Copy,
966        V: EntityRef,
967    {
968        if let Some(val) = map(self).get(&key) {
969            return *val;
970        }
971        let tmp = generate(self, key);
972        let index = V::new(map(self).len());
973        self.initializers.push(init(index, tmp));
974        let prev = map(self).insert(key, index);
975        assert!(prev.is_none());
976        index
977    }
978}