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