wasmtime_environ/component/
dfg.rs

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