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    /// Interned map of id-to-`CanonicalOptions`, or all sets-of-options used by
143    /// this component.
144    pub options: Intern<OptionsId, CanonicalOptions>,
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
166/// A sound approximation of a particular module's set of instantiations.
167///
168/// This type forms a simple lattice that we can use in static analyses that in
169/// turn let us specialize a module's compilation to exactly the imports it is
170/// given.
171#[derive(Clone, Copy, Default)]
172pub enum AbstractInstantiations<'a> {
173    /// The associated module is instantiated many times.
174    Many,
175
176    /// The module is instantiated exactly once, with the given definitions as
177    /// arguments to that instantiation.
178    One(&'a [info::CoreDef]),
179
180    /// The module is never instantiated.
181    #[default]
182    None,
183}
184
185impl AbstractInstantiations<'_> {
186    /// Join two facts about a particular module's instantiation together.
187    ///
188    /// This is the least-upper-bound operation on the lattice.
189    pub fn join(&mut self, other: Self) {
190        *self = match (*self, other) {
191            (Self::Many, _) | (_, Self::Many) => Self::Many,
192            (Self::One(a), Self::One(b)) if a == b => Self::One(a),
193            (Self::One(_), Self::One(_)) => Self::Many,
194            (Self::One(a), Self::None) | (Self::None, Self::One(a)) => Self::One(a),
195            (Self::None, Self::None) => Self::None,
196        }
197    }
198}
199
200macro_rules! id {
201    ($(pub struct $name:ident(u32);)*) => ($(
202        #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
203        #[expect(missing_docs, reason = "tedious to document")]
204        pub struct $name(u32);
205        cranelift_entity::entity_impl!($name);
206    )*)
207}
208
209id! {
210    pub struct InstanceId(u32);
211    pub struct MemoryId(u32);
212    pub struct TableId(u32);
213    pub struct ReallocId(u32);
214    pub struct CallbackId(u32);
215    pub struct AdapterId(u32);
216    pub struct PostReturnId(u32);
217    pub struct AdapterModuleId(u32);
218    pub struct OptionsId(u32);
219}
220
221/// Same as `info::InstantiateModule`
222#[expect(missing_docs, reason = "tedious to document variants")]
223pub enum Instance {
224    Static(StaticModuleIndex, Box<[CoreDef]>),
225    Import(
226        RuntimeImportIndex,
227        IndexMap<String, IndexMap<String, CoreDef>>,
228    ),
229}
230
231/// Same as `info::Export`
232#[expect(missing_docs, reason = "tedious to document variants")]
233pub enum Export {
234    LiftedFunction {
235        ty: TypeFuncIndex,
236        func: CoreDef,
237        options: OptionsId,
238    },
239    ModuleStatic {
240        ty: ComponentCoreModuleTypeId,
241        index: StaticModuleIndex,
242    },
243    ModuleImport {
244        ty: TypeModuleIndex,
245        import: RuntimeImportIndex,
246    },
247    Instance {
248        ty: TypeComponentInstanceIndex,
249        exports: IndexMap<String, Export>,
250    },
251    Type(TypeDef),
252}
253
254/// Same as `info::CoreDef`, except has an extra `Adapter` variant.
255#[derive(Debug, Clone, Hash, Eq, PartialEq)]
256#[expect(missing_docs, reason = "tedious to document variants")]
257pub enum CoreDef {
258    Export(CoreExport<EntityIndex>),
259    InstanceFlags(RuntimeComponentInstanceIndex),
260    Trampoline(TrampolineIndex),
261    /// This is a special variant not present in `info::CoreDef` which
262    /// represents that this definition refers to a fused adapter function. This
263    /// adapter is fully processed after the initial translation and
264    /// identification of adapters.
265    ///
266    /// During translation into `info::CoreDef` this variant is erased and
267    /// replaced by `info::CoreDef::Export` since adapters are always
268    /// represented as the exports of a core wasm instance.
269    Adapter(AdapterId),
270}
271
272impl<T> From<CoreExport<T>> for CoreDef
273where
274    EntityIndex: From<T>,
275{
276    fn from(export: CoreExport<T>) -> CoreDef {
277        CoreDef::Export(export.map_index(|i| i.into()))
278    }
279}
280
281/// Same as `info::CoreExport`
282#[derive(Debug, Clone, Hash, Eq, PartialEq)]
283#[expect(missing_docs, reason = "self-describing fields")]
284pub struct CoreExport<T> {
285    pub instance: InstanceId,
286    pub item: ExportItem<T>,
287}
288
289impl<T> CoreExport<T> {
290    #[expect(missing_docs, reason = "self-describing function")]
291    pub fn map_index<U>(self, f: impl FnOnce(T) -> U) -> CoreExport<U> {
292        CoreExport {
293            instance: self.instance,
294            item: match self.item {
295                ExportItem::Index(i) => ExportItem::Index(f(i)),
296                ExportItem::Name(s) => ExportItem::Name(s),
297            },
298        }
299    }
300}
301
302/// Same as `info::Trampoline`
303#[derive(Clone, PartialEq, Eq, Hash)]
304#[expect(missing_docs, reason = "self-describing fields")]
305pub enum Trampoline {
306    LowerImport {
307        import: RuntimeImportIndex,
308        options: OptionsId,
309        lower_ty: TypeFuncIndex,
310    },
311    Transcoder {
312        op: Transcode,
313        from: MemoryId,
314        from64: bool,
315        to: MemoryId,
316        to64: bool,
317    },
318    AlwaysTrap,
319    ResourceNew {
320        instance: RuntimeComponentInstanceIndex,
321        ty: TypeResourceTableIndex,
322    },
323    ResourceRep {
324        instance: RuntimeComponentInstanceIndex,
325        ty: TypeResourceTableIndex,
326    },
327    ResourceDrop {
328        instance: RuntimeComponentInstanceIndex,
329        ty: TypeResourceTableIndex,
330    },
331    BackpressureSet {
332        instance: RuntimeComponentInstanceIndex,
333    },
334    BackpressureInc {
335        instance: RuntimeComponentInstanceIndex,
336    },
337    BackpressureDec {
338        instance: RuntimeComponentInstanceIndex,
339    },
340    TaskReturn {
341        instance: RuntimeComponentInstanceIndex,
342        results: TypeTupleIndex,
343        options: OptionsId,
344    },
345    TaskCancel {
346        instance: RuntimeComponentInstanceIndex,
347    },
348    WaitableSetNew {
349        instance: RuntimeComponentInstanceIndex,
350    },
351    WaitableSetWait {
352        instance: RuntimeComponentInstanceIndex,
353        options: OptionsId,
354    },
355    WaitableSetPoll {
356        instance: RuntimeComponentInstanceIndex,
357        options: OptionsId,
358    },
359    WaitableSetDrop {
360        instance: RuntimeComponentInstanceIndex,
361    },
362    WaitableJoin {
363        instance: RuntimeComponentInstanceIndex,
364    },
365    ThreadYield {
366        instance: RuntimeComponentInstanceIndex,
367        cancellable: bool,
368    },
369    SubtaskDrop {
370        instance: RuntimeComponentInstanceIndex,
371    },
372    SubtaskCancel {
373        instance: RuntimeComponentInstanceIndex,
374        async_: bool,
375    },
376    StreamNew {
377        instance: RuntimeComponentInstanceIndex,
378        ty: TypeStreamTableIndex,
379    },
380    StreamRead {
381        instance: RuntimeComponentInstanceIndex,
382        ty: TypeStreamTableIndex,
383        options: OptionsId,
384    },
385    StreamWrite {
386        instance: RuntimeComponentInstanceIndex,
387        ty: TypeStreamTableIndex,
388        options: OptionsId,
389    },
390    StreamCancelRead {
391        instance: RuntimeComponentInstanceIndex,
392        ty: TypeStreamTableIndex,
393        async_: bool,
394    },
395    StreamCancelWrite {
396        instance: RuntimeComponentInstanceIndex,
397        ty: TypeStreamTableIndex,
398        async_: bool,
399    },
400    StreamDropReadable {
401        instance: RuntimeComponentInstanceIndex,
402        ty: TypeStreamTableIndex,
403    },
404    StreamDropWritable {
405        instance: RuntimeComponentInstanceIndex,
406        ty: TypeStreamTableIndex,
407    },
408    FutureNew {
409        instance: RuntimeComponentInstanceIndex,
410        ty: TypeFutureTableIndex,
411    },
412    FutureRead {
413        instance: RuntimeComponentInstanceIndex,
414        ty: TypeFutureTableIndex,
415        options: OptionsId,
416    },
417    FutureWrite {
418        instance: RuntimeComponentInstanceIndex,
419        ty: TypeFutureTableIndex,
420        options: OptionsId,
421    },
422    FutureCancelRead {
423        instance: RuntimeComponentInstanceIndex,
424        ty: TypeFutureTableIndex,
425        async_: bool,
426    },
427    FutureCancelWrite {
428        instance: RuntimeComponentInstanceIndex,
429        ty: TypeFutureTableIndex,
430        async_: bool,
431    },
432    FutureDropReadable {
433        instance: RuntimeComponentInstanceIndex,
434        ty: TypeFutureTableIndex,
435    },
436    FutureDropWritable {
437        instance: RuntimeComponentInstanceIndex,
438        ty: TypeFutureTableIndex,
439    },
440    ErrorContextNew {
441        instance: RuntimeComponentInstanceIndex,
442        ty: TypeComponentLocalErrorContextTableIndex,
443        options: OptionsId,
444    },
445    ErrorContextDebugMessage {
446        instance: RuntimeComponentInstanceIndex,
447        ty: TypeComponentLocalErrorContextTableIndex,
448        options: OptionsId,
449    },
450    ErrorContextDrop {
451        instance: RuntimeComponentInstanceIndex,
452        ty: TypeComponentLocalErrorContextTableIndex,
453    },
454    ResourceTransferOwn,
455    ResourceTransferBorrow,
456    ResourceEnterCall,
457    ResourceExitCall,
458    PrepareCall {
459        memory: Option<MemoryId>,
460    },
461    SyncStartCall {
462        callback: Option<CallbackId>,
463    },
464    AsyncStartCall {
465        callback: Option<CallbackId>,
466        post_return: Option<PostReturnId>,
467    },
468    FutureTransfer,
469    StreamTransfer,
470    ErrorContextTransfer,
471    ContextGet {
472        instance: RuntimeComponentInstanceIndex,
473        slot: u32,
474    },
475    ContextSet {
476        instance: RuntimeComponentInstanceIndex,
477        slot: u32,
478    },
479}
480
481#[derive(Copy, Clone, Hash, Eq, PartialEq)]
482#[expect(missing_docs, reason = "self-describing fields")]
483pub struct FutureInfo {
484    pub instance: RuntimeComponentInstanceIndex,
485    pub payload_type: Option<InterfaceType>,
486}
487
488#[derive(Copy, Clone, Hash, Eq, PartialEq)]
489#[expect(missing_docs, reason = "self-describing fields")]
490pub struct StreamInfo {
491    pub instance: RuntimeComponentInstanceIndex,
492    pub payload_type: InterfaceType,
493}
494
495/// Same as `info::CanonicalOptionsDataModel`.
496#[derive(Clone, Hash, Eq, PartialEq)]
497#[expect(missing_docs, reason = "self-describing fields")]
498pub enum CanonicalOptionsDataModel {
499    Gc {},
500    LinearMemory {
501        memory: Option<MemoryId>,
502        realloc: Option<ReallocId>,
503    },
504}
505
506/// Same as `info::CanonicalOptions`
507#[derive(Clone, Hash, Eq, PartialEq)]
508#[expect(missing_docs, reason = "self-describing fields")]
509pub struct CanonicalOptions {
510    pub instance: RuntimeComponentInstanceIndex,
511    pub string_encoding: StringEncoding,
512    pub callback: Option<CallbackId>,
513    pub post_return: Option<PostReturnId>,
514    pub async_: bool,
515    pub cancellable: bool,
516    pub core_type: ModuleInternedTypeIndex,
517    pub data_model: CanonicalOptionsDataModel,
518}
519
520/// Same as `info::Resource`
521#[expect(missing_docs, reason = "self-describing fields")]
522pub struct Resource {
523    pub rep: WasmValType,
524    pub dtor: Option<CoreDef>,
525    pub instance: RuntimeComponentInstanceIndex,
526}
527
528/// A helper structure to "intern" and deduplicate values of type `V` with an
529/// identifying key `K`.
530///
531/// Note that this can also be used where `V` can't be intern'd to represent a
532/// flat list of items.
533pub struct Intern<K: EntityRef, V> {
534    intern_map: HashMap<V, K>,
535    key_map: PrimaryMap<K, V>,
536}
537
538impl<K, V> Intern<K, V>
539where
540    K: EntityRef,
541{
542    /// Inserts the `value` specified into this set, returning either a fresh
543    /// key `K` if this value hasn't been seen before or otherwise returning the
544    /// previous `K` used to represent value.
545    ///
546    /// Note that this should only be used for component model items where the
547    /// creation of `value` is not side-effectful.
548    pub fn push(&mut self, value: V) -> K
549    where
550        V: Hash + Eq + Clone,
551    {
552        *self
553            .intern_map
554            .entry(value.clone())
555            .or_insert_with(|| self.key_map.push(value))
556    }
557
558    /// Returns an iterator of all the values contained within this set.
559    pub fn iter(&self) -> impl Iterator<Item = (K, &V)> {
560        self.key_map.iter()
561    }
562}
563
564impl<K: EntityRef, V> Index<K> for Intern<K, V> {
565    type Output = V;
566    fn index(&self, key: K) -> &V {
567        &self.key_map[key]
568    }
569}
570
571impl<K: EntityRef, V> Default for Intern<K, V> {
572    fn default() -> Intern<K, V> {
573        Intern {
574            intern_map: HashMap::new(),
575            key_map: PrimaryMap::new(),
576        }
577    }
578}
579
580impl ComponentDfg {
581    /// Consumes the intermediate `ComponentDfg` to produce a final `Component`
582    /// with a linear initializer list.
583    pub fn finish(
584        self,
585        wasmtime_types: &mut ComponentTypesBuilder,
586        wasmparser_types: wasmparser::types::TypesRef<'_>,
587    ) -> Result<ComponentTranslation> {
588        let mut linearize = LinearizeDfg {
589            dfg: &self,
590            initializers: Vec::new(),
591            runtime_memories: Default::default(),
592            runtime_tables: Default::default(),
593            runtime_post_return: Default::default(),
594            runtime_reallocs: Default::default(),
595            runtime_callbacks: Default::default(),
596            runtime_instances: Default::default(),
597            num_lowerings: 0,
598            trampolines: Default::default(),
599            trampoline_defs: Default::default(),
600            trampoline_map: Default::default(),
601            options: Default::default(),
602            options_map: Default::default(),
603        };
604
605        // Handle all side effects of this component in the order that they're
606        // defined. This will, for example, process all instantiations necessary
607        // of core wasm modules.
608        for item in linearize.dfg.side_effects.iter() {
609            linearize.side_effect(item);
610        }
611
612        // Next the exports of the instance are handled which will likely end up
613        // creating some lowered imports, perhaps some saved modules, etc.
614        let mut export_items = PrimaryMap::new();
615        let mut exports = NameMap::default();
616        for (name, export) in self.exports.iter() {
617            let export =
618                linearize.export(export, &mut export_items, wasmtime_types, wasmparser_types)?;
619            exports.insert(name, &mut NameMapNoIntern, false, export)?;
620        }
621
622        // With all those pieces done the results of the dataflow-based
623        // linearization are recorded into the `Component`. The number of
624        // runtime values used for each index space is used from the `linearize`
625        // result.
626        Ok(ComponentTranslation {
627            trampolines: linearize.trampoline_defs,
628            component: Component {
629                exports,
630                export_items,
631                initializers: linearize.initializers,
632                trampolines: linearize.trampolines,
633                num_lowerings: linearize.num_lowerings,
634                options: linearize.options,
635
636                num_runtime_memories: linearize.runtime_memories.len() as u32,
637                num_runtime_tables: linearize.runtime_tables.len() as u32,
638                num_runtime_post_returns: linearize.runtime_post_return.len() as u32,
639                num_runtime_reallocs: linearize.runtime_reallocs.len() as u32,
640                num_runtime_callbacks: linearize.runtime_callbacks.len() as u32,
641                num_runtime_instances: linearize.runtime_instances.len() as u32,
642                imports: self.imports,
643                import_types: self.import_types,
644                num_runtime_component_instances: self.num_runtime_component_instances,
645                num_future_tables: self.num_future_tables,
646                num_stream_tables: self.num_stream_tables,
647                num_error_context_tables: self.num_error_context_tables,
648                num_resources: (self.resources.len() + self.imported_resources.len()) as u32,
649                imported_resources: self.imported_resources,
650                defined_resource_instances: self
651                    .resources
652                    .iter()
653                    .map(|(_, r)| r.instance)
654                    .collect(),
655            },
656        })
657    }
658
659    /// Converts the provided defined index into a normal index, adding in the
660    /// number of imported resources.
661    pub fn resource_index(&self, defined: DefinedResourceIndex) -> ResourceIndex {
662        ResourceIndex::from_u32(defined.as_u32() + (self.imported_resources.len() as u32))
663    }
664}
665
666struct LinearizeDfg<'a> {
667    dfg: &'a ComponentDfg,
668    initializers: Vec<GlobalInitializer>,
669    trampolines: PrimaryMap<TrampolineIndex, ModuleInternedTypeIndex>,
670    trampoline_defs: PrimaryMap<TrampolineIndex, info::Trampoline>,
671    options: PrimaryMap<OptionsIndex, info::CanonicalOptions>,
672    trampoline_map: HashMap<TrampolineIndex, TrampolineIndex>,
673    runtime_memories: HashMap<MemoryId, RuntimeMemoryIndex>,
674    runtime_tables: HashMap<TableId, RuntimeTableIndex>,
675    runtime_reallocs: HashMap<ReallocId, RuntimeReallocIndex>,
676    runtime_callbacks: HashMap<CallbackId, RuntimeCallbackIndex>,
677    runtime_post_return: HashMap<PostReturnId, RuntimePostReturnIndex>,
678    runtime_instances: HashMap<RuntimeInstance, RuntimeInstanceIndex>,
679    options_map: HashMap<OptionsId, OptionsIndex>,
680    num_lowerings: u32,
681}
682
683#[derive(Copy, Clone, Hash, Eq, PartialEq)]
684enum RuntimeInstance {
685    Normal(InstanceId),
686    Adapter(AdapterModuleId),
687}
688
689impl LinearizeDfg<'_> {
690    fn side_effect(&mut self, effect: &SideEffect) {
691        match effect {
692            SideEffect::Instance(i) => {
693                self.instantiate(*i, &self.dfg.instances[*i]);
694            }
695            SideEffect::Resource(i) => {
696                self.resource(*i, &self.dfg.resources[*i]);
697            }
698        }
699    }
700
701    fn instantiate(&mut self, instance: InstanceId, args: &Instance) {
702        log::trace!("creating instance {instance:?}");
703        let instantiation = match args {
704            Instance::Static(index, args) => InstantiateModule::Static(
705                *index,
706                args.iter().map(|def| self.core_def(def)).collect(),
707            ),
708            Instance::Import(index, args) => InstantiateModule::Import(
709                *index,
710                args.iter()
711                    .map(|(module, values)| {
712                        let values = values
713                            .iter()
714                            .map(|(name, def)| (name.clone(), self.core_def(def)))
715                            .collect();
716                        (module.clone(), values)
717                    })
718                    .collect(),
719            ),
720        };
721        let index = RuntimeInstanceIndex::new(self.runtime_instances.len());
722        self.initializers
723            .push(GlobalInitializer::InstantiateModule(instantiation));
724        let prev = self
725            .runtime_instances
726            .insert(RuntimeInstance::Normal(instance), index);
727        assert!(prev.is_none());
728    }
729
730    fn resource(&mut self, index: DefinedResourceIndex, resource: &Resource) {
731        let dtor = resource.dtor.as_ref().map(|dtor| self.core_def(dtor));
732        self.initializers
733            .push(GlobalInitializer::Resource(info::Resource {
734                dtor,
735                index,
736                rep: resource.rep,
737                instance: resource.instance,
738            }));
739    }
740
741    fn export(
742        &mut self,
743        export: &Export,
744        items: &mut PrimaryMap<ExportIndex, info::Export>,
745        wasmtime_types: &mut ComponentTypesBuilder,
746        wasmparser_types: wasmparser::types::TypesRef<'_>,
747    ) -> Result<ExportIndex> {
748        let item = match export {
749            Export::LiftedFunction { ty, func, options } => {
750                let func = self.core_def(func);
751                let options = self.options(*options);
752                info::Export::LiftedFunction {
753                    ty: *ty,
754                    func,
755                    options,
756                }
757            }
758            Export::ModuleStatic { ty, index } => info::Export::ModuleStatic {
759                ty: wasmtime_types.convert_module(wasmparser_types, *ty)?,
760                index: *index,
761            },
762            Export::ModuleImport { ty, import } => info::Export::ModuleImport {
763                ty: *ty,
764                import: *import,
765            },
766            Export::Instance { ty, exports } => info::Export::Instance {
767                ty: *ty,
768                exports: {
769                    let mut map = NameMap::default();
770                    for (name, export) in exports {
771                        let export =
772                            self.export(export, items, wasmtime_types, wasmparser_types)?;
773                        map.insert(name, &mut NameMapNoIntern, false, export)?;
774                    }
775                    map
776                },
777            },
778            Export::Type(def) => info::Export::Type(*def),
779        };
780        Ok(items.push(item))
781    }
782
783    fn options(&mut self, options: OptionsId) -> OptionsIndex {
784        self.intern_no_init(
785            options,
786            |me| &mut me.options_map,
787            |me, options| me.convert_options(options),
788        )
789    }
790
791    fn convert_options(&mut self, options: OptionsId) -> OptionsIndex {
792        let options = &self.dfg.options[options];
793        let data_model = match options.data_model {
794            CanonicalOptionsDataModel::Gc {} => info::CanonicalOptionsDataModel::Gc {},
795            CanonicalOptionsDataModel::LinearMemory { memory, realloc } => {
796                info::CanonicalOptionsDataModel::LinearMemory(LinearMemoryOptions {
797                    memory: memory.map(|mem| self.runtime_memory(mem)),
798                    realloc: realloc.map(|mem| self.runtime_realloc(mem)),
799                })
800            }
801        };
802        let callback = options.callback.map(|mem| self.runtime_callback(mem));
803        let post_return = options.post_return.map(|mem| self.runtime_post_return(mem));
804        let options = info::CanonicalOptions {
805            instance: options.instance,
806            string_encoding: options.string_encoding,
807            callback,
808            post_return,
809            async_: options.async_,
810            cancellable: options.cancellable,
811            core_type: options.core_type,
812            data_model,
813        };
814        self.options.push(options)
815    }
816
817    fn runtime_memory(&mut self, mem: MemoryId) -> RuntimeMemoryIndex {
818        self.intern(
819            mem,
820            |me| &mut me.runtime_memories,
821            |me, mem| me.core_export(&me.dfg.memories[mem]),
822            |index, export| GlobalInitializer::ExtractMemory(ExtractMemory { index, export }),
823        )
824    }
825
826    fn runtime_realloc(&mut self, realloc: ReallocId) -> RuntimeReallocIndex {
827        self.intern(
828            realloc,
829            |me| &mut me.runtime_reallocs,
830            |me, realloc| me.core_def(&me.dfg.reallocs[realloc]),
831            |index, def| GlobalInitializer::ExtractRealloc(ExtractRealloc { index, def }),
832        )
833    }
834
835    fn runtime_callback(&mut self, callback: CallbackId) -> RuntimeCallbackIndex {
836        self.intern(
837            callback,
838            |me| &mut me.runtime_callbacks,
839            |me, callback| me.core_def(&me.dfg.callbacks[callback]),
840            |index, def| GlobalInitializer::ExtractCallback(ExtractCallback { index, def }),
841        )
842    }
843
844    fn runtime_post_return(&mut self, post_return: PostReturnId) -> RuntimePostReturnIndex {
845        self.intern(
846            post_return,
847            |me| &mut me.runtime_post_return,
848            |me, post_return| me.core_def(&me.dfg.post_returns[post_return]),
849            |index, def| GlobalInitializer::ExtractPostReturn(ExtractPostReturn { index, def }),
850        )
851    }
852
853    fn core_def(&mut self, def: &CoreDef) -> info::CoreDef {
854        match def {
855            CoreDef::Export(e) => info::CoreDef::Export(self.core_export(e)),
856            CoreDef::InstanceFlags(i) => info::CoreDef::InstanceFlags(*i),
857            CoreDef::Adapter(id) => info::CoreDef::Export(self.adapter(*id)),
858            CoreDef::Trampoline(index) => info::CoreDef::Trampoline(self.trampoline(*index)),
859        }
860    }
861
862    fn trampoline(&mut self, index: TrampolineIndex) -> TrampolineIndex {
863        if let Some(idx) = self.trampoline_map.get(&index) {
864            return *idx;
865        }
866        let (signature, trampoline) = &self.dfg.trampolines[index];
867        let trampoline = match trampoline {
868            Trampoline::LowerImport {
869                import,
870                options,
871                lower_ty,
872            } => {
873                let index = LoweredIndex::from_u32(self.num_lowerings);
874                self.num_lowerings += 1;
875                self.initializers.push(GlobalInitializer::LowerImport {
876                    index,
877                    import: *import,
878                });
879                info::Trampoline::LowerImport {
880                    index,
881                    options: self.options(*options),
882                    lower_ty: *lower_ty,
883                }
884            }
885            Trampoline::Transcoder {
886                op,
887                from,
888                from64,
889                to,
890                to64,
891            } => info::Trampoline::Transcoder {
892                op: *op,
893                from: self.runtime_memory(*from),
894                from64: *from64,
895                to: self.runtime_memory(*to),
896                to64: *to64,
897            },
898            Trampoline::AlwaysTrap => info::Trampoline::AlwaysTrap,
899            Trampoline::ResourceNew { instance, ty } => info::Trampoline::ResourceNew {
900                instance: *instance,
901                ty: *ty,
902            },
903            Trampoline::ResourceDrop { instance, ty } => info::Trampoline::ResourceDrop {
904                instance: *instance,
905                ty: *ty,
906            },
907            Trampoline::ResourceRep { instance, ty } => info::Trampoline::ResourceRep {
908                instance: *instance,
909                ty: *ty,
910            },
911            Trampoline::BackpressureSet { instance } => info::Trampoline::BackpressureSet {
912                instance: *instance,
913            },
914            Trampoline::BackpressureInc { instance } => info::Trampoline::BackpressureInc {
915                instance: *instance,
916            },
917            Trampoline::BackpressureDec { instance } => info::Trampoline::BackpressureDec {
918                instance: *instance,
919            },
920            Trampoline::TaskReturn {
921                instance,
922                results,
923                options,
924            } => info::Trampoline::TaskReturn {
925                instance: *instance,
926                results: *results,
927                options: self.options(*options),
928            },
929            Trampoline::TaskCancel { instance } => info::Trampoline::TaskCancel {
930                instance: *instance,
931            },
932            Trampoline::WaitableSetNew { instance } => info::Trampoline::WaitableSetNew {
933                instance: *instance,
934            },
935            Trampoline::WaitableSetWait { instance, options } => {
936                info::Trampoline::WaitableSetWait {
937                    instance: *instance,
938                    options: self.options(*options),
939                }
940            }
941            Trampoline::WaitableSetPoll { instance, options } => {
942                info::Trampoline::WaitableSetPoll {
943                    instance: *instance,
944                    options: self.options(*options),
945                }
946            }
947            Trampoline::WaitableSetDrop { instance } => info::Trampoline::WaitableSetDrop {
948                instance: *instance,
949            },
950            Trampoline::WaitableJoin { instance } => info::Trampoline::WaitableJoin {
951                instance: *instance,
952            },
953            Trampoline::ThreadYield {
954                instance,
955                cancellable,
956            } => info::Trampoline::ThreadYield {
957                instance: *instance,
958                cancellable: *cancellable,
959            },
960            Trampoline::SubtaskDrop { instance } => info::Trampoline::SubtaskDrop {
961                instance: *instance,
962            },
963            Trampoline::SubtaskCancel { instance, async_ } => info::Trampoline::SubtaskCancel {
964                instance: *instance,
965                async_: *async_,
966            },
967            Trampoline::StreamNew { instance, ty } => info::Trampoline::StreamNew {
968                instance: *instance,
969                ty: *ty,
970            },
971            Trampoline::StreamRead {
972                instance,
973                ty,
974                options,
975            } => info::Trampoline::StreamRead {
976                instance: *instance,
977                ty: *ty,
978                options: self.options(*options),
979            },
980            Trampoline::StreamWrite {
981                instance,
982                ty,
983                options,
984            } => info::Trampoline::StreamWrite {
985                instance: *instance,
986                ty: *ty,
987                options: self.options(*options),
988            },
989            Trampoline::StreamCancelRead {
990                instance,
991                ty,
992                async_,
993            } => info::Trampoline::StreamCancelRead {
994                instance: *instance,
995                ty: *ty,
996                async_: *async_,
997            },
998            Trampoline::StreamCancelWrite {
999                instance,
1000                ty,
1001                async_,
1002            } => info::Trampoline::StreamCancelWrite {
1003                instance: *instance,
1004                ty: *ty,
1005                async_: *async_,
1006            },
1007            Trampoline::StreamDropReadable { instance, ty } => {
1008                info::Trampoline::StreamDropReadable {
1009                    instance: *instance,
1010                    ty: *ty,
1011                }
1012            }
1013            Trampoline::StreamDropWritable { instance, ty } => {
1014                info::Trampoline::StreamDropWritable {
1015                    instance: *instance,
1016                    ty: *ty,
1017                }
1018            }
1019            Trampoline::FutureNew { instance, ty } => info::Trampoline::FutureNew {
1020                instance: *instance,
1021                ty: *ty,
1022            },
1023            Trampoline::FutureRead {
1024                instance,
1025                ty,
1026                options,
1027            } => info::Trampoline::FutureRead {
1028                instance: *instance,
1029                ty: *ty,
1030                options: self.options(*options),
1031            },
1032            Trampoline::FutureWrite {
1033                instance,
1034                ty,
1035                options,
1036            } => info::Trampoline::FutureWrite {
1037                instance: *instance,
1038                ty: *ty,
1039                options: self.options(*options),
1040            },
1041            Trampoline::FutureCancelRead {
1042                instance,
1043                ty,
1044                async_,
1045            } => info::Trampoline::FutureCancelRead {
1046                instance: *instance,
1047                ty: *ty,
1048                async_: *async_,
1049            },
1050            Trampoline::FutureCancelWrite {
1051                instance,
1052                ty,
1053                async_,
1054            } => info::Trampoline::FutureCancelWrite {
1055                instance: *instance,
1056                ty: *ty,
1057                async_: *async_,
1058            },
1059            Trampoline::FutureDropReadable { instance, ty } => {
1060                info::Trampoline::FutureDropReadable {
1061                    instance: *instance,
1062                    ty: *ty,
1063                }
1064            }
1065            Trampoline::FutureDropWritable { instance, ty } => {
1066                info::Trampoline::FutureDropWritable {
1067                    instance: *instance,
1068                    ty: *ty,
1069                }
1070            }
1071            Trampoline::ErrorContextNew {
1072                instance,
1073                ty,
1074                options,
1075            } => info::Trampoline::ErrorContextNew {
1076                instance: *instance,
1077                ty: *ty,
1078                options: self.options(*options),
1079            },
1080            Trampoline::ErrorContextDebugMessage {
1081                instance,
1082                ty,
1083                options,
1084            } => info::Trampoline::ErrorContextDebugMessage {
1085                instance: *instance,
1086                ty: *ty,
1087                options: self.options(*options),
1088            },
1089            Trampoline::ErrorContextDrop { instance, ty } => info::Trampoline::ErrorContextDrop {
1090                instance: *instance,
1091                ty: *ty,
1092            },
1093            Trampoline::ResourceTransferOwn => info::Trampoline::ResourceTransferOwn,
1094            Trampoline::ResourceTransferBorrow => info::Trampoline::ResourceTransferBorrow,
1095            Trampoline::ResourceEnterCall => info::Trampoline::ResourceEnterCall,
1096            Trampoline::ResourceExitCall => info::Trampoline::ResourceExitCall,
1097            Trampoline::PrepareCall { memory } => info::Trampoline::PrepareCall {
1098                memory: memory.map(|v| self.runtime_memory(v)),
1099            },
1100            Trampoline::SyncStartCall { callback } => info::Trampoline::SyncStartCall {
1101                callback: callback.map(|v| self.runtime_callback(v)),
1102            },
1103            Trampoline::AsyncStartCall {
1104                callback,
1105                post_return,
1106            } => info::Trampoline::AsyncStartCall {
1107                callback: callback.map(|v| self.runtime_callback(v)),
1108                post_return: post_return.map(|v| self.runtime_post_return(v)),
1109            },
1110            Trampoline::FutureTransfer => info::Trampoline::FutureTransfer,
1111            Trampoline::StreamTransfer => info::Trampoline::StreamTransfer,
1112            Trampoline::ErrorContextTransfer => info::Trampoline::ErrorContextTransfer,
1113            Trampoline::ContextGet { instance, slot } => info::Trampoline::ContextGet {
1114                instance: *instance,
1115                slot: *slot,
1116            },
1117            Trampoline::ContextSet { instance, slot } => info::Trampoline::ContextSet {
1118                instance: *instance,
1119                slot: *slot,
1120            },
1121        };
1122        let i1 = self.trampolines.push(*signature);
1123        let i2 = self.trampoline_defs.push(trampoline);
1124        assert_eq!(i1, i2);
1125        self.trampoline_map.insert(index, i1);
1126        i1
1127    }
1128
1129    fn core_export<T>(&mut self, export: &CoreExport<T>) -> info::CoreExport<T>
1130    where
1131        T: Clone,
1132    {
1133        let instance = export.instance;
1134        log::trace!("referencing export of {instance:?}");
1135        info::CoreExport {
1136            instance: self.runtime_instances[&RuntimeInstance::Normal(instance)],
1137            item: export.item.clone(),
1138        }
1139    }
1140
1141    fn adapter(&mut self, adapter: AdapterId) -> info::CoreExport<EntityIndex> {
1142        let (adapter_module, entity_index) = self.dfg.adapter_partitionings[adapter];
1143
1144        // Instantiates the adapter module if it hasn't already been
1145        // instantiated or otherwise returns the index that the module was
1146        // already instantiated at.
1147        let instance = self.adapter_module(adapter_module);
1148
1149        // This adapter is always an export of the instance.
1150        info::CoreExport {
1151            instance,
1152            item: ExportItem::Index(entity_index),
1153        }
1154    }
1155
1156    fn adapter_module(&mut self, adapter_module: AdapterModuleId) -> RuntimeInstanceIndex {
1157        self.intern(
1158            RuntimeInstance::Adapter(adapter_module),
1159            |me| &mut me.runtime_instances,
1160            |me, _| {
1161                log::debug!("instantiating {adapter_module:?}");
1162                let (module_index, args) = &me.dfg.adapter_modules[adapter_module];
1163                let args = args.iter().map(|arg| me.core_def(arg)).collect();
1164                let instantiate = InstantiateModule::Static(*module_index, args);
1165                GlobalInitializer::InstantiateModule(instantiate)
1166            },
1167            |_, init| init,
1168        )
1169    }
1170
1171    /// Helper function to manage interning of results to avoid duplicate
1172    /// initializers being inserted into the final list.
1173    ///
1174    /// * `key` - the key being referenced which is used to deduplicate.
1175    /// * `map` - a closure to access the interning map on `Self`
1176    /// * `gen` - a closure to generate an intermediate value with `Self` from
1177    ///   `K`. This is only used if `key` hasn't previously been seen. This
1178    ///   closure can recursively intern other values possibly.
1179    /// * `init` - a closure to use the result of `gen` to create the final
1180    ///   initializer now that the index `V` of the runtime item is known.
1181    ///
1182    /// This is used by all the other interning methods above to lazily append
1183    /// initializers on-demand and avoid pushing more than one initializer at a
1184    /// time.
1185    fn intern<K, V, T>(
1186        &mut self,
1187        key: K,
1188        map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
1189        generate: impl FnOnce(&mut Self, K) -> T,
1190        init: impl FnOnce(V, T) -> GlobalInitializer,
1191    ) -> V
1192    where
1193        K: Hash + Eq + Copy,
1194        V: EntityRef,
1195    {
1196        self.intern_(key, map, generate, |me, key, val| {
1197            me.initializers.push(init(key, val));
1198        })
1199    }
1200
1201    fn intern_no_init<K, V, T>(
1202        &mut self,
1203        key: K,
1204        map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
1205        generate: impl FnOnce(&mut Self, K) -> T,
1206    ) -> V
1207    where
1208        K: Hash + Eq + Copy,
1209        V: EntityRef,
1210    {
1211        self.intern_(key, map, generate, |_me, _key, _val| {})
1212    }
1213
1214    fn intern_<K, V, T>(
1215        &mut self,
1216        key: K,
1217        map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
1218        generate: impl FnOnce(&mut Self, K) -> T,
1219        init: impl FnOnce(&mut Self, V, T),
1220    ) -> V
1221    where
1222        K: Hash + Eq + Copy,
1223        V: EntityRef,
1224    {
1225        if let Some(val) = map(self).get(&key) {
1226            return *val;
1227        }
1228        let tmp = generate(self, key);
1229        let index = V::new(map(self).len());
1230        init(self, index, tmp);
1231        let prev = map(self).insert(key, index);
1232        assert!(prev.is_none());
1233        index
1234    }
1235}